The PODA Blog

News, views and articles from our membership

Archive for the 'Office (All)' Category

PopUp Menus on a Userform

Posted by Derek Mang on 15th September 2008

Most of the Office VBA solutions I produce include userforms and the usual controls are there - textboxes, commandbuttons, checkboxes and dropdowns - to present an easy-to-use, functional user interface. 

I have also been including custom “popup” menus with many of the userforms due to the nature of the solution, most often used within textboxes.  (A right-click in the textbox shows the popup as expected).  I found the base code on the net a few years ago and use it often. Full credit here to an author unknown!  I have used the code verbatim - except for the actual menu item captions and related functions - in Excel, Word, PowerPoint and OutLook VBA.

Once recent solution for MS Outlook uses this technique to provide ease in extracting start and end date information from freeform Outlook message text.  The dates are in various formats, and are needed in yy/mm/dd format.  In this case, a custom pop-up with the menu items “Start Date” and “End Date” is used.  When the date text is selected from within the text box, the Start Date menu option converts the selected text into the required format, and appends the time 00:00:00 for beginning-of-day. Similarly, when the end date provided is selected, the End Date menu option converts the selected text into the same format and appends the time 23:59:59.

The resulting values are dropped into individual text boxes for later use.

The userform’s initialize event drives the creation of the popup menu(s).  A menu needs to be created for each userform control requiring a popup, as well as for the userform itself as needed. 

Some code has to be included for the control’s “mouse_up” event to first check for a right-click (button2) and then for the selected menu item.  If the same functionality is required for all of the same type of control on the form - like an array of textboxes - then a class module should be set up with the mouse_up event holding the corresponding code.

Finally, the userform’s terminate event requires a little code to destroy the popups previously created. 

A set of APIs and some globals are also required.

Popup menus may not be for everyone - CTRL+C, CTRL+V are surely favourites for some. They can however greatly enhance userform usability.

Userform Code

(You’ll need 3 textboxes on the form - txtEx1, txtEx2, txtBody)

Private Declare Function ShellExecute Lib “shell32.dll” Alias “ShellExecuteA” _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Private Declare Function SendMessage Lib “user32″ _
Alias “SendMessageA” (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, _
lParam As Any) As Long
Private Sub txtBody_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
If Button = 2 Then
GetCursorPos pt
lngID = TrackPopupMenuEx(lngMnuTB, TPM_RETURNCMD, pt.X, _
pt.Y, lngHwndTB, ByVal 0&)
Select Case lngID
Case 1
txtEx1.Text = Trim(Replace(txtBody.SelText, Chr(13), “”))
Case 2
txtEx2.Text = Trim(Replace(txtBody.SelText, Chr(13), “”))
End Select
End IfEnd Sub
Private Sub UserForm_Initialize()

txtBody.Text = “This is sample text to demonstrate the textbox popup menu.”
Call SetUFMenu
Call SetTBMenu
End Sub
Sub SetUFMenu()

Dim strArrayUF(4) As String
strArrayUF(1) = “Help on this Form”
strArrayUF(2) = “About this Userform”
strArrayUF(3) = “Statistics”
strArrayUF(4) = “Date and Time”

lngMnuUF = CreatePopupMenu()
lngHwndUF = FindWindow(vbNullString, Me.Caption)
For lngCnt = 1 To 4
With objMNU
.cbSize = Len(objMNU)
.fMask = MIIM_TYPE Or MIIM_ID Or MIIM_DATA Or MIIM_STATE
.dwTypeData = strArrayUF(lngCnt)
.cch = Len(strArrayUF(lngCnt))
.fType = MF_STRING
.wID = lngCnt
.fState = 0
End With
Call InsertMenuItem(lngMnuUF, lngCnt, 1, objMNU)
Next lngCnt

End Sub
Sub SetTBMenu()

Dim strArrayTB(2) As String
strArrayTB(1) = “Extract 1″
strArrayTB(2) = “Extract 2″

lngMnuTB = CreatePopupMenu()
lngHwndTB = FindWindow(vbNullString, Me.Caption)
For lngCnt = 1 To 2
With objMNU
.cbSize = Len(objMNU)
.fMask = MIIM_TYPE Or MIIM_ID Or MIIM_DATA Or MIIM_STATE
.dwTypeData = strArrayTB(lngCnt)
.cch = Len(strArrayTB(lngCnt))
.fType = MF_STRING
.wID = lngCnt
.fState = 0
End With
Call InsertMenuItem(lngMnuTB, lngCnt, 1, objMNU)
Next lngCnt

txtBody.Text = “This is sample text to demonstrate the textbox popup menu.”

End Sub

Private Sub UserForm_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)

If Button = 2 Then
GetCursorPos pt
lngID = TrackPopupMenuEx(lngMnuUF, TPM_RETURNCMD, pt.X, _
pt.Y, lngHwndUF, ByVal 0&)

Select Case lngID
Case 1
MsgBox “Help on this userform is not available”, vbOKOnly, “Help on this Userform”
Case 2
MsgBox “This userform contains sample popup menus. It has been provided by Derek Mang, based on information found somewhere on the NET”, vbOKOnly, “About this Userform”
Case 3
MsgBox “There are no statistics available”, vbOKOnly, “Statistics”
Case 4
MsgBox “It’s ” & Format(Now, “HH:MM”) & ” on ” & Format(Now, “ddd mmm, yyyy”)

End Select

End If

End Sub

Private Sub UserForm_Terminate()
DestroyMenu (lngHwndTB)
DestroyMenu (lngHwndUF)
End Sub

Module Code

Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type
Type POINTAPI
X As Long
Y As Long
End Type
Declare Function GetCursorPos Lib "user32" _
(lpPoint As POINTAPI) As Long
Declare Function CreatePopupMenu Lib _
“user32″ () As Long
Declare Function TrackPopupMenuEx Lib "user32" _
(ByVal hMenu As Long, ByVal un As Long, _
ByVal n1 As Long, ByVal n2 As Long, _
ByVal hwnd As Long, lpTPMParams As Any) As Long

Declare Function InsertMenuItem Lib “user32″ _
Alias “InsertMenuItemA” (ByVal hMenu As Long, _
ByVal un As Long, ByVal bool As Long, _
lpcMenuItemInfo As MENUITEMINFO) As Long

Declare Function DestroyMenu Lib “user32″ _
(ByVal hMenu As Long) As Long

Declare Function FindWindow Lib “user32″ _
Alias “FindWindowA” (ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long

Declare Sub Sleep Lib “kernel32″ (ByVal dwMilliseconds As Long)

Global Const MF_STRING = &H0&
Global Const TPM_RETURNCMD = &H100&
Global Const MIIM_ID = &H2
Global Const MIIM_STATE As Long = &H1&

Global Const MIIM_TYPE = &H10
Global Const MIIM_DATA = &H20

Global lngMnuUF As Long
Global lngHwndUF As Long
Global lngID As Long
Global lngMnuTB As Long
Global lngHwndTB As Long

Global pt As POINTAPI
Global objMNU As MENUITEMINFO

Posted in Office (All) | No Comments »