Looping through a collection of text boxes - vba

I have a userform that has three conceptual groups of textboxes. I'm trying to create a collection for each group and then when the user clicks on a button to call a sub/function associated with one of those groups, I want to be able to call a function that loops through the collection of textboxes associated with that group and check if they are empty, contain invalid characters, etc.
I've made the following declarations at the module level.
Dim typSectFields, laneFields, matFields As Collection
Then when the user form initializes I add the text boxes to the collections:
Set typSectFields = New Collection
With frmAddTypSect
typSectFields.Add txtTypSectName
typSectFields.Add txtStartSta
typSectFields.Add txtEndSta
End With
And then when the user clicks the button that uses the input from the "typSectFields" collection:
Dim tb As Control, res As VbMsgBoxResult
For Each tb In typSectFields
If tb.Text = vbNullString And t.Tag <> vbNullString Then
res = MsgBox("You've not completed the " + tb.Tag + " field. Would you like to complete it now?", vbYesNo + vbQuestion)
If res = vbYes Then Exit Sub
End If
Next
I get an "Object Required" error when execution hits the For loop.
VBE shows that tb = nothing and typSectFields = Empty.
What am I doing wrong?

Make sure all of your code (specifically the module-level declarations) are in the code behind the form module. The following runs without error for me:
Dim typSectFields As Collection, laneFields As Collection, matFields As Collection
Private Sub CommandButton1_Click()
Dim tb As Control, res As VbMsgBoxResult
For Each tb In typSectFields
If tb.Text = vbNullString And tb.Tag <> vbNullString Then
res = MsgBox("You've not completed the " + tb.Tag + " field. Would you like to complete it now?", vbYesNo + vbQuestion)
If res = vbYes Then Exit Sub
End If
Next
End Sub
Private Sub UserForm_Initialize()
Set typSectFields = New Collection
With frmAddTypSect
typSectFields.Add txtTypSectName
typSectFields.Add txtStartSta
typSectFields.Add txtEndSta
End With
End Sub

Related

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

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.

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

vba - Msg if box if checked - but not if unchecked

I am trying to write code for a message to pop up if a checkbox is checked. My spreadsheet has a LOT of checkboxes, and I only want it to do this for the checkboxes in column H. I believe the best way may be to assign a macro to all checkboxes using vba using something like the following code (Except this is not working):
ActiveSheet.Shapes.Range(Array("h9:h89")).Select
Selection.OnAction = "Sheet4.Checkbox"
The second problem I have is that I only want the message to pop-up when it is checked, not when it is unchecked. The following works when the macro is assigned mannually, but for both checking and unchecking. The commented out sections are examples of some of the things I have tried. I believe they are ActiveX checkboxes.
Sub Checkbox()
' Dim rangeVar As Range
'
' rangeVar = ("h9:h89")
'
'With rangeVar
' If WorksheetFunction.Or(.Cells) = True Then
MsgBox ("Are you sure you want to check this box?")
Exit Sub
' End If
'End With
' Dim chk As Checkbox
'
' For Each chk In rangeVar
' If chk.Value = True Then
' MsgBox ("Are you sure you want to check this box?")
' Exit Sub
' End If
' Next chk
End Sub
Thank you!
Assigning the action:
Sub AssignClicks()
Dim cb
For Each cb In ActiveSheet.CheckBoxes
If Not Application.Intersect(cb.TopLeftCell, _
ActiveSheet.Range("H:H")) Is Nothing Then
cb.OnAction = "Sheet1.ClickedIt"
End If
Next cb
End Sub
In the sheet code module:
Sub ClickedIt()
Dim cb As CheckBox
Set cb = Me.CheckBoxes(Application.Caller)
If cb.Value = 1 Then
MsgBox "checkbox at " & cb.TopLeftCell.Address() & " is checked"
End If
End Sub
...or you can assign the action to all of your checkboxes and use code in ClickedIt to determine whether the current checkbox is in Col H.

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

Excel - Returning the caption of the selected option button

Probably a silly question with a simple answer but I am a real novice when it comes to userforms.
I have "Frame 3" with 5 different option buttons (Dest1, Dest2, Dest3, Dest4, Dest5) After an option is selected, where is the caption value of the selected option stored? How can I access that with vba.
Thank you,
Josh
Here's just some example code you can use. Add your Option Buttons to groups, and then you can go from there. I used groups since you had multiple frames, and you can check based on group, and have multiple groups, and check which one's selected for each group.
Private Sub CommandButton1_Click()
Dim x As Control
' Loop through ALL the controls on the UserForm.
For Each x In Me.Controls
' Check to see if "Option" is in the Name of each control.
If InStr(x.Name, "Option") Then
' Check Group name.
If x.GroupName = "Grp1" Then
' Check the status of the OptionButton.
If x.Value = True Then
MsgBox x.Caption
Exit For
End If
End If
End If
Next
End Sub
You can also access the option buttons through the frame-ojbect that holds them (if you have other frames and controls you don't want to go through):
Option Explicit
Sub Test()
Dim oCtrl As Control
'***** Try only controls in Frame3
For Each oCtrl In Frame3.Controls
'***** Try only option buttons
If TypeName(oCtrl) = "OptionButton" Then
'***** Which one is checked?
If oCtrl.Value = True Then
'***** What's the caption?
Debug.Print "You have checked option " & oCtrl.Caption
Exit For
End If
End If
Next
End Sub
The Label Text associated with an Option Button is obtainable by using OptionButton1.Caption
If you are using a loop, just substitute the OptionButton1 with your variable for option buttons and it will pull through the one you need when conditions are met. eg:
For xitem = 1 To 5
xFrm = "OptionButton" & xitem
For Each fItem In Me.Controls
If fItem.Name Like xFrm Then
If fItem.Value Then
k = fitem.Caption
End If
End If
Next fItem
Next xitem
In my case, I wanted the caption of the toggle that was selected in an option group to be passed on to a subform filter. e.g. choosing toggle "black" filters subform to all cars where strColour = "black".
I ended up with this:
Private Sub OptionGroupName_Click()
Dim Caption As String
Caption = OptionGroupName.Controls.Item(OptionGroupName.Value - 1).Caption
Me.SubformName.Form.Filter = "[SubformField] = """ & Caption & """"
Me.SubformName.Form.FilterOn = True
End Sub
Not to dog pile on everyone else's options but I created a function that takes the radio group name and spits out the selected radios coresponding label caption. Was using it in Access not Excel.
Only works provided you name your controls similarly....
i.e. (lblRadioButton1 & optRadioButton1)
Function GetSelectedRadioButtonCaption(ByVal optionGroupName As OptionGroup) As String
Dim oCtrl As Control
Dim oCtrl2 As Control
Dim optionLabelName As String
Dim optionLabelObject As Label
Dim optionButtonObject As OptionButton
For Each oCtrl In optionGroupName.Controls
'***** Try only option buttons
If TypeOf oCtrl Is OptionButton Then
'***** Which one is checked?
Set optionButtonObject = oCtrl
If optionButtonObject.OptionValue = optionGroupName.Value Then
'***** What's the caption?
optionLabelName = Replace(oCtrl.Name, "opt", "lbl")
For Each oCtrl2 In optionGroupName.Controls
If oCtrl2.Name = optionLabelName Then
Set optionLabelObject = oCtrl2
GetSelectedRadioButtonCaption = optionLabelObject.caption
Exit For
End If
Next
End If
If GetSelectedRadioButtonCaption <> "" Then
Exit For
End If
End If
Next
Exit_GetSelectedRadioButtonCaption:
End Function