Frames
Now, this is where it gets really interesting. We can make our pegging routine even more flexible. In effect, I could have called this section "Improving the peg handler - 3". Imagine that we have 2 buttons on the screen. If we wanted to peg both of them, we would have to have two separate peg routines because our code actually needs to know the ID of the button it is to peg - two buttons, two routines. Well, that's a bit inefficient. Or it would be, except for the
It's quite simple, really. Go to your EasyCode "View code" window and scroll down until the cursor is between the end of the OnResize and the beginning of the pegObject routines. Hit Enter a couple of times to move them apart. Now type in:
When you hit the Enter key at the end of the line, you will see that EasyCode puts in a
We're almost ready to gobut firt we need to update our "OnResize" handler. The
So, what we're going to do now is to add another button to the window and we'll compile and run the program twice - once using the exit button and the second time using the other button. We should see that we can peg either button but with no changes to the "pegObject" routine! However, before we try anything smart, we have to ensure that the code still works as it did originally, so compile it and run it with our single button window. This is called a regression test and is intended to make sure that when we have changed something, we have not broken something else that worked perfectly well before the change. You should always do this.
If the regression test has gone OK, go to the EasyCode visual designer window and add another button. Call it "btnOK" and change the text to "OK". Doesn't matter where on the screen you put it but you should have something like the illustration shown here. This is another change, so do a regression test - compile it and run it. You should see two buttons on the screen but, when you resize it, btnOK should remain stationary but btnExit should move with the bottom right of the window. All is well. Now go to the resize handler and change the invocation to:
Recompile this and, when you run it, you should now find that it's the btnOK that is pegged and btnExit stays where it is! It's the same pegObject code but we are now able to tell it which button to peg and on which window. Terrific.Frame
instruction. Now, frames are a whole ball game all to themselves and goAsm has a lot to say about it but all we need to know about them is to think of the EasyCode methods we have invoked. When we called GetWidth
we specified the handle of the object whose width we wanted to get, didn't we? So why can't we tell our "pegObject" routine which window and which button?
pegObject Frame hWnd, idControl
Ret
for you and an EndF
to mark the end of the frame. Moreover, it underlines the end of the frame with a horizontal line. You should regard the Frame .. EndF
as being like a pair of tall, brick walls. The rest of the program can't see in. The problem is that, if you're inside the frame, you can't see out. That means that any variables from outside the frame you want to work on have to be "thrown" over the wall. That's the purpose of the parameters in the code above. OK. Copy everything inside the old "pegObject" , except the UseData and EndU instructions, and paste into the new one, overwriting the Ret
(we don't need that). You can also delete everything remaining of the old "pegObject".Invoke
statement now needs to pass the handle of the window and the ID of the button to the "pegObject" routine. The ID is no problem but, as you know, the handle to the window is one of those things known inside the event loop, so we'll have to replace the UseData winMainProcedure
instruction inside the "OnResize" handler. Don't forget - that means we will also have to add an EndU
at the end, too. Now all we have to do is to add the two parameters to the end of the invocation. Remember that the "hWnd" will have to be enclosed in sqrae brackets but here's something neat - when you press the comma after the "pegObject", EasyCode will pop up a hint for you, just as it did for GetWidth
to tell you the parameters that "pegObject" now needs! Anyway, to make sure you fully understand what we're trying to do, here's the code of the two routines:
OnResize:
UseData winMainProcedure
Invoke pegObject, [hWnd], IDC_WINMAIN_BTNEXIT
Return (TRUE)
; End OnResize
EndU
pegObject Frame hWnd, idControl
; 1. Get a handle on the button
Invoke GetWindowItem, [hWnd], [idControl]
Mov [hButton], Eax
; 2. Get the new size of the window's client area
Invoke GetClientRect, [hWnd], Addr pBox
; 3. Get the width of the button and subtract it from the width of the
; client area, together with any border
Invoke GetWidth, [hButton] ; Get the button's current width
Add Eax, [pegBorder] ; A border of 4
Mov Ebx, [pBox.right] ; Retrieve the parent's width
Sub Ebx, Eax ; Subtract the button's (plus border)
width from it.
; 4. Set the "left" position of the button to the above value
Invoke SetLeft, [hButton], Ebx ; Set the button's left position to the
new value
; 5. Get the height of the button and subtract it from the height of the
; client area, together with any border
Invoke GetHeight, [hButton] ; Get the button's current height
Add Eax, [pegBorder] ; A border of 4
Mov Ebx, [pBox.bottom] ; Retrieve the parent's height
Sub Ebx, Eax ; Subtract the button's (plus border)
height from it.
; 6. Set the "top" position of the button to the above value
Invoke SetTop, [hButton], Ebx ; Set the button's top position to the
new value
; 7. Return back to the main code
Return (TRUE)
EndF
OnResize:
UseData winMainProcedure
Invoke pegObject, [hWnd], IDC_WINMAIN_BTNOK
Return (TRUE)
; End OnResize
EndU