Skip to main content

Past Blast

Featured Products

Windows Mobile Developer Controls
Windows Mobile Developer Controls
Stay in touch using the DEVBUSS RSS feeds.
 

News

Windows Mobile Developer Controls
Windows Mobile Developer Controls

eVB Popup Menu /Tap and Hold Menu using Windows CE API calls.

Written by Derek Mitchell  [author's bio]  [read 44665 times]
Edited by Derek

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