Page 1
Page 2
Ok, so now you're straight on the creation of the popup menu, so let's move on to the
trigger mechanism for that menu, the simulated Tap 'n' Hold event. First, copy this code
into the form module, then I'll discuss how it works:
Option Explicit
Private Sub Command1_MouseDown(ByVal Button As Integer, ByVal Shift As
Integer, ByVal X As Single, ByVal Y As Single)
CurX = X
CurY = Y
MenuX = X + Command1.Left
MenuY = Y + Command1.Top
mnuTimer.Enabled = True
End Sub
Private Sub Command1_MouseMove(ByVal Button As Integer, ByVal Shift As
Integer, ByVal X As Single, ByVal Y As Single)
' Pick up if stylus is moving too much and ignore tap and hold
If Abs(CurX - X) > 4 Then mnuTimer.Enabled = False
If Abs(CurY - Y) > 4 Then mnuTimer.Enabled = False
End Sub
Private Sub Command1_MouseUp(ByVal Button As Integer, ByVal Shift As
Integer, ByVal X As Single, ByVal Y As Single)
mnuTimer.Enabled = False
End Sub
Private Sub Label1_MouseDown(ByVal Button As Integer, ByVal Shift As
Integer, ByVal X As Single, ByVal Y As Single)
CurX = X
CurY = Y
MenuX = X + Label1.Left
MenuY = Y + Label1.Top
mnuTimer.Enabled = True
End Sub
Private Sub Label1_MouseMove(ByVal Button As Integer, ByVal Shift As
Integer, ByVal X As Single, ByVal Y As Single)
' Pick up if stylus is moving too much and ignore tap and hold
If Abs(CurX - X) > 4 Then mnuTimer.Enabled = False
If Abs(CurY - Y) > 4 Then mnuTimer.Enabled = False
End Sub
Private Sub Label1_MouseUp(ByVal Button As Integer, ByVal Shift As
Integer, ByVal X As Single, ByVal Y As Single)
mnuTimer.Enabled = False
End Sub
Private Sub mnuTimer_Timer()
Dim intMenuResult As Integer
mnuTimer.Enabled = False
intMenuResult = ShowPopupMenu(MenuX, MenuY + 30)
Select Case intMenuResult
Case 1
lblResult.Caption = "You selected First Option"
Case 2
lblResult.Caption = "You selected Second Option"
Case 3
'nothing here.. can't select a grayed option
Case 4
lblResult.Caption = "You selected Checked Option"
Case 5
'nothing here.. can't select a grayed option
End Select
End Sub
As you can see, each of our two testing controls, Command1 and Label1, have three
events with code the MouseDown, MouseMove and MouseUp events. Since they are
the same I'll just discuss them as one.
In the MouseDown event it sets the global variables CurX and CurY to the coordinates
where the user initiates the Tap 'n' Hold. Next it sets the global variables MenuX and
MenuY to the actual screen coordinates that correspond to CurX and CurY (since these,
along with the X and Y parameters are relative to the control itself). Finally it starts the
timer off and running.
The MouseMove event must verify the user is actually holding the stylus in about the
same position for the hold duration. This is done by checking the difference in
coordinates on a move, should one happen. In the sample code the tolerance is set to 4
pixels, but you may find that you want to accommodate people with a less steady hand
and increase that number to something like 7 or even 10.
The MouseUp event is for cleanup should the user abort the Tap 'n' Hold early. It simply
shuts off the timer before it has a chance to fire.
Ok, so assuming all went well, the user held the tap properly, after the interval has
passed, the timer code will begin to execute. In the beginning I had you set the timer
interval property to 1000 (which is one second). This time directly corresponds to how
long the user must hold the stylus before the event will officially fire and the menu will
show up, so you may choose to adjust it however you wish.
The last part of the code to discuss is in the timer. The first thing it must do is disable the
timer or it will keep calling this code and the menu will never disappear. Next, we call
the ShowPopupMenu function, and pass its result back into intMenuResult. The
parameters are needed to describe where the menu should appear. This is why we got the
actual screen coordinates and stored them in the MenuX and MenuY variables. The +30
part is to accommodate for the titlebar, and can be tacked on now, or could have been
added when I stored the MenuY value just a matter of preference.
Finally, we create the case statement to handle the result of the menu selection, and as
mentioned before that third index parameter passed into the AppendMenu calls
corresponds to what comes out of the function and therefore the values in the case
statement.
If you build this project exactly as described, you should expect it to report the menu
selected to the longer label placed toward the bottom. At that point, you should have no
trouble working this functionality into any other application. A few things to keep in
mind however:
To keep things clean, you will need a separate timer, as well as a separate
ShowPopupMenu function for each different menu you create. If you want to show the
same popup menu on different controls as I've done here with the Command1 and Label1
controls, you can use the same one, but if you wanted Command1 to show a totally
different menu than Label1, the timer and function will need to be different.
For simplicity's sake, I've defined all the constants you might ever need, however in the
real world, you should only define the ones you will use in that situation to cut down on
program size and increase speed (though only slightly).
This example works well for simple controls, however the jury's still out on how to make
it work well with more complex controls like the TreeView and ListView, where you
might want to have a popup menu associated with each element listed in those controls.
If I figure out a way to do this in eVB, I'll certainly post an update to this article, but it's
looking like it will have to be done with much more complex windows messaging
routines, and then possibly only in eVC++.
That about wraps it up for this lesson. If you have any questions or concerns, please
come to my website and use either of the email links at the bottom of any page there.
Thanks for reading and good luck!
Previous Page