Get the selected item of a dropdown in a custom menu (and run a macro accordingly) - vba

I have this simple menu setup and I am trying to run a macro based on user selection of the label item from a dropdown list. The OnAction only works on the entire dropdown object and not executing macros per dropdown-list-item selection:
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
Dim oMenu As CommandBar
Set oMenu = CommandBars.Add("", msoBarPopup, , True)
Dim cbcm1 As CommandBarButton
Set cbcm1 = oMenu.Controls.Add(Type:=msoControlButton, Temporary:=True)
cbcm1.Caption = "Add new label"
cbcm1.OnAction = "AddNewLabel"
Dim cbcm2 As CommandBarComboBox
Set cbcm2 = oMenu.Controls.Add(Type:=msoControlDropdown, Temporary:=True)
cbcm2.Caption = "Select label:"
cbcm2.AddItem "NVPE" ' << this should run a macro that adds a 'NVPE' in some other range..
cbcm2.AddItem "COMP" ' << this should run a macro that adds a 'COMP' in some other range.. and so on.
cbcm2.AddItem "HOLD"
cbcm2.AddItem "INPROG"
cbcm2.AddItem "CANC"
cbcm2.Width = 150
cbcm2.ListIndex = 1 'default
cbcm2.OnAction = "NewCommand_OnAction"
cbcm2.Style = msoComboLabel
oMenu.ShowPopup 'display the menu
Cancel = True
End Sub
Any suggestions?
I can't think of a way to get the selected index or value (caption) of the selected item.
Thanks!

All you are missing is a Select Case in your event handler. Using your existing code, simply add the string cbcm2Text and set it to equal cbcm2.Text. Then, add the necessary Select Case prior to your Cancel = True statement to call your macros.
Example:
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
Dim oMenu As CommandBar
Dim cbcm2Text As String
Dim cbcm1 As CommandBarButton
Dim cbcm2 As CommandBarComboBox
Set oMenu = CommandBars.Add("", msoBarPopup, , True)
Set cbcm1 = oMenu.Controls.Add(Type:=msoControlButton, Temporary:=True)
Set cbcm2 = oMenu.Controls.Add(Type:=msoControlDropdown, Temporary:=True)
cbcm1.Caption = "Add new label"
cbcm1.OnAction = "AddNewLabel"
cbcm2.Caption = "Select label:"
cbcm2.AddItem "NVPE"
cbcm2.AddItem "COMP"
cbcm2.AddItem "HOLD"
cbcm2.AddItem "INPROG"
cbcm2.AddItem "CANC"
cbcm2.Width = 150
cbcm2.ListIndex = 1
cbcm2.OnAction = "NewCommand_OnAction"
cbcm2.Style = msoComboLabel
oMenu.ShowPopup
cbcm2Text = cbcm2.Text
Select Case cbcm2Text
Case "NVPE"
Call NVPE
Case "COMP"
Call COMP
Case "HOLD"
Call HOLD
Case "INPROG"
Call INPROG
Case "CANC"
Call CANC
End Select
Cancel = True
End Sub
Sub NVPE()
MsgBox "You selected NVPE"
End Sub
Sub COMP()
MsgBox "You selected COMP"
End Sub
Sub HOLD()
MsgBox "You selected HOLD"
End Sub
Sub INPROG()
MsgBox "You selected INPROG"
End Sub
Sub CANC()
MsgBox "You selected CANC"
End Sub
The preceding code produces the following result:
Here is the relevant Microsoft Documentation if you would like to see more examples of how to utilize combobox change events.

Related

Connect Bookmark to another

I have word file with VBA userform with one ComboBox1, In ComboBox1 I wrote this code for three options
Private Sub UserForm_Initialize()
ComboBox1.List = Array("Mr.", "Ms.", "Miss")
End Sub
and I have 2 Bookmarks with name Bookmark1 and Bookmark
I wrote code
Private Sub CommandButton1_Click()
Dim Bookmark1 As Range
Set Bookmark1 = ActiveDocument.Bookmarks("Bookmark1").Range
Bookmark1.Text = Me.ComboBox1.Value
End Sub
The ComboBox1 is connected to the Bookmark1 (Whatever my choice from ComboBox will appear in Bookmark1).
What I want is when Bookmark1 = "Mr." then Bookmark2 should be changed to "Manger" , and if choose "Mis." should be Changed to "student", and if choose "Miss." should be Changed to "Job seeker"
I solved it by writing a Case statement.
The code is:
Private Sub CommandButton1_Click()
Dim Bookmark1 As Range
Dim Bookmark2 As Range
Set Bookmark1 = ActiveDocument.Bookmarks("Bookmark1").Range
Bookmark1.Text = Me.ComboBox1.Value
Set Bookmark2 = ActiveDocument.Bookmarks("Bookmark2").Range
Bookmark2.Text = Me.ComboBox1.Value
Select Case Bookmark1
Case "Mr": Bookmark2.Text = "Manger"
Case "Mis": Bookmark2.Text = "student"
Case "Miss": Bookmark2.Text = "Job seeker"
End Select
End Sub

Change value of dynamically created UserForm element

This is a followup on my first question:
Through a click event, I dynamically added some elements (txtBox01 and cmdButton01) to the previously empty (static) UserForm1. Now I want to change the textbox's content through the click event of cmdButton01. How exactly do I have to reference cmdButton01?
Here's how I create the dynamic elements (simplified!):
Private Sub CommandButton1_Click()
Dim cmdArray() As New Class1
i = 1
'Layout for static Form
'Set Formsize / Formtitle
UserForm1.Height = 130
UserForm1.Width = 300
'Create Form-Elements (TextBox1)
Dim txtBox01 As MSForms.TextBox
Set txtBox01 = UserForm1.Controls.Add("Forms.TextBox.1", "dynTxtBox_01")
txtBox01.Top = 10
txtBox01.Left = 10
txtBox01.Width = 200
txtBox01.Text = "something"
'Create Form-Elements (Commandbutton)
Dim cmdButton01 As MSForms.CommandButton
Set cmdButton01 = UserForm13.Controls.Add("Forms.CommandButton.1", "dynCmdButton01", False)
cmdButton01.Top = 70
cmdButton01.Left = 10
cmdButton01.Width = 200
cmdButton01.Caption = "Save"
cmdButton01.Visible = True
ReDim Preserve cmdArray(1 To i)
Set cmdArray(i).CmdEvents = cmdButton01
Set cmdButton01 = Nothing
'Show Form
UserForm1.Show
End Sub
I assigned the code for the click event through the following code. But I'm not sure how to reference the dynamic elements on the static form. I tried a few examples I found on the web but nothing worked:
Public WithEvents CmdEvents As MSForms.CommandButton
Private Sub CmdEvents_Click()
'Simple Test (works fine)
MsgBox "Test1"
'Change the Text of TextBox01 (this one is PSEUDO code to illustrate what I want to do)
UserForm1.txtBox01.Text= "123"
'=> how should I reference the dynamic form element to make this work??
'Close Form
UserForm1.Hide
End Sub
To answer your specific question, the syntax would be like the following:
UserForm1.Controls("dynTxtBox_01").Text = "123"
Use the next approach, please:
Insert a Class module, name it clsBtn and copy the next code:
Option Explicit
Public WithEvents cmdButton As MSForms.CommandButton
Public Sub cmdButton_Click()
Dim ans As String
ans = InputBox("What to write in the newly created text box?", _
"Write some text, please", "Default")
If ans <> "" Then
cmdButton.Parent.txtBox01.Text = ans
End If
End Sub
On top of the Form module, in the declarations area, paste the next variables declaration:
Public txtBox01 As MSForms.TextBox
Private cmdButton01 As MSForms.CommandButton
Private ButtColl As New Collection
Private cmdButt(0) As New clsBtn
Your CommandButton1_Click event will look like this:
Private Sub CommandButton1_Click()
Set txtBox01 = Me.Controls.Add("Forms.TextBox.1", "dynTxtBox_01")
With txtBox01
.top = 10
.left = 10
.width = 200
.Text = "something"
End With
Set cmdButton01 = Me.Controls.Add("Forms.CommandButton.1", "dynCmdButton01", False)
With cmdButton01
.top = 70
.left = 10
.width = 200
.Caption = "Save"
.Visible = True
End With
ButtColl.Add cmdButton01, cmdButton01.Name
Set cmdButt(0).cmdButton = cmdButton01
End Sub
Load the form, click CommandButton1 and then click the newly created button ("Save" Caption). It will change the newly created text box from "something" in "Changed"...

Catia VBA Automation Error Run-Time 80010005 - Selection ERROR

I have a Problem with my Userform. It should automatically Switch to another TextBox when an selection in the catpart made. I get the Automation Error: It is illegal to call out while inside message filter.
Run-time error '-2147418107 (80010005)
Sub Auswahl_Click()
Dim sel As Object, Objekt As Object, ObjektTyp(0)
Dim b, Auswahl, i As Integer
ObjektTyp(0) = "Body"
Set sel = CATIA.ActiveDocument.Selection
For i = 1 To 6
sel.Clear
UserFormNow.Controls("Textbox" & i).SetFocus
Auswahl = sel.SelectElement2(ObjektTyp, "Wähle ein Body aus...", False)
Set b = CATIA.ActiveDocument.Selection.Item(i)
If Auswahl = "Normal" Then
Set Objekt = sel.Item(i)
UserFormNow.ActiveControl = Objekt.Value.Name
sel.Clear
End If
i = i + 1
Next
sel.Clear
End Sub
' EXCEL DATEI ÖFFNEN____________________________________
Sub Durchsuchen1_Click()
Dim FPath As String
FPath = CATIA.FileSelectionBox("Select the Excel file you wish to put the value in", "*.xlsx", CatFileSelectionModeOpen)
If FPath = "" Then
Else
DurchsuchenFeld.AddItem FPath
ListBox1.Clear
ListBox1.AddItem "Bitte wählen Sie das Panel"
TextBox1.SetFocus
End If
End Sub
' FORMULAR SCHLIEßEN____________________________________
Sub ButtonEnd_Click()
ButtonEnd = True
Unload UserFormNow
End Sub
First you have to know that when you use an UI and still want to interact with CATIA, you have to choices:
Launch the UI in NoModal: mode UserFormNow.Show 0
Hide the UI each time you want to interact with CATIA: Me.Hide or UserFormNow.Hide
Then, I strongly recommend you to avoid looking for items with names:
UserFormNow.Controls("Textbox" & i).SetFocus
If you want to group controls and loop through them, use a Frame and then use a For Each loop.
For Each currentTextBox In MyFrame.Controls
MsgBox currentTextBox.Text
Next
Regarding your code, many simplifications can be done:
Private Sub Auswahl_Click()
Dim sel As Object
Dim currentTextBox As TextBox
Dim Filter As Variant
ReDim Filter(0)
Filter(0) = "Body"
Set sel = CATIA.ActiveDocument.Selection
'Loop through each textbox
For Each currentTextBox In MyFrame.Controls
sel.Clear
'Ask for the selection and test the result at the same time
If sel.SelectElement2(Filter, "Wahle ein Body aus...", False) = "Normal" Then
'Get the name without saving the object
currentTextBox.Text = sel.Item2(1).Value.Name
Else
'allow the user to exit all the process if press Escape
Exit Sub
End If
Next
sel.Clear
End Sub

Name of textbox depends on where it is located in an ArrayList

I'm using VBA to code an application for an Excel file. Put simply, I need the names of my textboxes to change depending on where a certain variable is in an ArrayList.
I have one textbox to start, when someone pushes a button it should add a textbox after the first one, and do this as many times as one presses the button. So the first box should be named tbx1, the second should be tbx2, the third tbx3, and so on.
Now when they press a different button located next to any of the boxes, it deletes that box and button and all boxes after that one are named one lower to make up for it.
Any ideas how to do this? I'm only assuming ArrayList is the best tactic, please correct me if there is a better way.
Here's an example that you can hopefully modify to your needs. I have a userform named UClassList with one commandbutton, cmdAdd, and one textbox, tbxClass_1.
Private mEventButtons As Collection
Public Property Get ClassMax() As Long
ClassMax = 75
End Property
Private Sub cmdAdd_Click()
Dim i As Long
For i = 2 To Me.ClassMax
'find the first invisible control and make it visible
If Not Me.Controls("tbxClass_" & i).Visible Then
Me.Controls("tbxClass_" & i).Visible = True
Me.Controls("cmdClass_" & i).Visible = True
Exit For 'stop after one
End If
Next i
End Sub
Private Sub UserForm_Initialize()
Dim i As Long
Dim tbx As MSForms.TextBox
Dim cmd As MSForms.CommandButton
Dim clsEventClass As CEventClass
Set mEventButtons = New Collection
'Add as many textboxes and commandbuttons as you need
'or you can do this part at design time
For i = 2 To Me.ClassMax
Set tbx = Me.Controls.Add("Forms.TextBox.1", "tbxClass_" & i, False)
tbx.Top = Me.tbxClass_1.Top + ((i - 1) * 25) 'use the first textbox as the anchor
tbx.Left = Me.tbxClass_1.Left
tbx.Width = Me.tbxClass_1.Width
tbx.Height = Me.tbxClass_1.Height
'Create a delete commandbutton
Set cmd = Me.Controls.Add("Forms.CommandButton.1", "cmdClass_" & i, False)
cmd.Top = tbx.Top
cmd.Left = tbx.Left + tbx.Width + 10
cmd.Width = 20
cmd.Height = tbx.Height
cmd.Caption = "X"
'add delete commandbutton to the event class so they all share
'the same click event code
Set clsEventClass = New CEventClass
Set clsEventClass.cmdEvent = cmd
mEventButtons.Add clsEventClass
Next i
End Sub
I have a custom class named CEventClass.
Public WithEvents cmdEvent As MSForms.CommandButton
Private Sub cmdEvent_Click()
Dim i As Long
Dim lThisIndex As Long
Dim tbxThis As MSForms.TextBox
Dim tbxPrev As MSForms.TextBox
Dim uf As UClassList
Set uf = cmdEvent.Parent
'get the number that was clicked
lThisIndex = Val(Split(cmdEvent.Name, "_")(1))
'loop from the next textbox to the end
For i = lThisIndex + 1 To uf.ClassMax
Set tbxThis = uf.Controls("tbxClass_" & i)
Set tbxPrev = uf.Controls("tbxClass_" & i - 1)
'if it's not visible, clear and hide
'the previous textbox
If Not tbxThis.Visible Then
tbxPrev.Text = vbNullString
tbxPrev.Visible = False
uf.Controls("cmdClass_" & i - 1).Visible = False
Else
'if it's visible, copy it's text to the one above
tbxPrev.Text = tbxThis.Text
End If
Next i
End Sub
Instead of adding and deleting and keeping track of a bunch of textboxes, I create all 75 (or fewer) at launch (or design time). Then I just make then visible or hide them as needed.
You can see the workbook I did this on here http://dailydoseofexcel.com/excel/ControlEventClass.xlsm

Create a right-click context menu in Outlook 2003

I'm already able to create a new menu in the top menubar of Outlook 2003 but would like to do the same when the user right-click on an email (but not anywhere else in the interface if possible).
Here is what I got:
Sub AddMenus()
Dim cbMainMenuBar As CommandBar
Dim cbcCustomMenu As CommandBarControl
Dim cbcTest As CommandBarControl
Dim iHelpMenu as Integer
Set cbMainMenuBar = Application.ActiveExplorer.CommandBars.ActiveMenuBar
iHelpMenu = cbMainMenuBar.Controls("&?").index
Set cbcCustomMenu = cbMainMenuBar.Controls.Add(Type:=msoControlPopup, before:=iHelpMenu)
cbcCustomMenu.caption = "Menu &Name"
Set cbcTest = cbcCustomMenu.Controls.Add(Type:=msoControlPopup)
cbcTest.caption = "&Test"
With cbcTest.Controls.Add(Type:=msoControlButton)
.caption = "&Submenu item"
.OnAction = "macro"
End With
With cbcTest.Controls.Add(Type:=msoControlButton)
.caption = "Another submenu item"
.OnAction = "macro"
End With
With cbcCustomMenu.Controls.Add(Type:=msoControlButton)
.caption = "About"
.OnAction = "macro"
End With
End Sub
What do I have to change to make this works when right-clicking?
The definitive answer to the problem can be found here: http://www.outlookcode.com/codedetail.aspx?id=314
Here is what I come with after removing some of the code/comments I didn't need:
Option Explicit
Private WithEvents ActiveExplorerCBars As CommandBars
Private WithEvents ContextButton As CommandBarButton
Private IgnoreCommandbarsChanges As Boolean
Private Sub Application_Startup()
Set ActiveExplorerCBars = ActiveExplorer.CommandBars
End Sub
Private Sub ActiveExplorerCBars_OnUpdate()
Dim bar As CommandBar
If IgnoreCommandbarsChanges Then Exit Sub
On Error Resume Next
Set bar = ActiveExplorerCBars.Item("Context Menu")
On Error GoTo 0
If Not bar Is Nothing Then
AddContextButton bar
End If
End Sub
Sub AddContextButton(ContextMenu As CommandBar)
Dim b As CommandBarButton
Dim subMenu As CommandBarControl
Dim cbcCustomMenu As CommandBarControl, cbcLink As CommandBarControl
Set ContextMenu = ActiveExplorerCBars.Item("Context Menu")
'Unprotect context menu
ChangingBar ContextMenu, Restore:=False
'Menu
Set cbcCustomMenu = ContextMenu.Controls.Add(Type:=msoControlPopup)
cbcCustomMenu.caption = "&Menu"
'Link in Menu
Set cbcLink = cbcCustomMenu.Controls.Add(Type:=msoControlButton)
cbcLink.caption = "Link 1"
cbcLink.OnAction = "macro"
'Reprotect context menu
ChangingBar ContextMenu, Restore:=True
End Sub
'Called once to prepare for changes to the command bar, then again with
'Restore = true once changes are complete.
Private Sub ChangingBar(bar As CommandBar, Restore As Boolean)
Static oldProtectFromCustomize, oldIgnore As Boolean
If Restore Then
'Restore the Ignore Changes flag
IgnoreCommandbarsChanges = oldIgnore
'Restore the protect-against-customization bit
If oldProtectFromCustomize Then bar.Protection = bar.Protection And msoBarNoCustomize
Else
'Store the old Ignore Changes flag
oldIgnore = IgnoreCommandbarsChanges
IgnoreCommandbarsChanges = True
'Store old protect-against-customization bit setting then clear
'CAUTION: Be careful not to alter the property if there is no need,
'as changing the Protection will cause any visible CommandBarPopup
'to disappear unless it is the popup we are altering.
oldProtectFromCustomize = bar.Protection And msoBarNoCustomize
If oldProtectFromCustomize Then bar.Protection = bar.Protection And Not msoBarNoCustomize
End If
End Sub
I no longer have Outlook 2003 installed and Outlook 2010 doesn't let you mess with right-click menus the same way. So this compiles and is, hopefully close to what you need to do.
Before writing any code, you'll want to show hidden items, I think, to get the Intellisense for a couple of objects. In 2010 the ActiveExporer and ActiveInspector objects - which are the two types of view in Outlook, e.g., looking at all you email, or looking at a single email - are hidden. To unhide them, go into the Object Explorer by clicking F2 in the VBE, and right-click just about anywhere and check "Show Hidden Items".
So now you're ready to code:
First you need a way to determine the name of the right-click menu you are interested in. This tries to add a button to every menu, with the button's caption being the name and index of the menu. It resets the menu first, so as to not create more than one such button. The button should be at the bottom of the menu. The buttons are temporary, meaning they'll be gone the next time you open Outlook:
Sub GetCommandBarNames()
Dim cbar As Office.CommandBar
Dim cbarButton As Office.CommandBarButton
For Each cbar In ActiveInspector.CommandBars
On Error Resume Next
cbar.Reset
Set cbarButton = cbar.Controls.Add(Type:=msoControlButton, temporary:=True)
With cbarButton
.Caption = cbar.Name
.Style = msoButtonCaption
.Visible = True
End With
On Error GoTo 0
Next cbar
For Each cbar In ActiveExplorer.CommandBars
On Error Resume Next
cbar.Reset
Set cbarButton = cbar.Controls.Add(Type:=msoControlButton, temporary:=True)
With cbarButton
.Caption = cbar.Name & "-" & cbar.Index
.Style = msoButtonCaption
.Visible = True
End With
On Error GoTo 0
Next cbar
End Sub
After running this, right-click in Outlook and get the name of the menu you want. It will be the part before the dash on the last button. Let's say it's "foobar".
You should then be able to do this:
Sub AddButton()
Dim cbar As Office.CommandBar
Dim cbarButton As Office.CommandBarButton
Set cbar = ActiveExplorer.CommandBars("foobar") 'or maybe it's ActiveInspector
Set cbarButton = cbar.Controls.Add(Type:=msoControlButton, temporary:=True)
With cbarButton
.Caption = "&Submenu item"
.OnAction = "macro"
.Style = msoButtonCaption
'etc.
End With
'do the next button
Set cbarButton = cbar.Controls.Add(Type:=msoControlButton, temporary:=True)
'...
End Sub
Like I say, I'm doing this a bit blind, but I've done it many times in Excel (I even wrote two addins), so if this doesn't work, I should be able to get you there.