Reference checkbox name/value in a subroutine - vba

Is there a way to pass a checkbox value from a userform? I've seen it done when the checkbox is on the worksheet but I haven't been able to get it to work when it comes from my userform.
I have several repeating if statements and the only difference between them is the name of the checkbox. I'm sure there's a simple fix that I just haven't found yet. Any help is appreciated.
Edit: included code
If LockboxCheckBox.Value = True Then
If IsEmpty(wsInput.Cells(emptyRow, productCol)) Then
wsInput.Cells(emptyRow, productCol).Value = LockboxCheckBox.Caption
Else: wsInput.Cells(emptyRow, productCol).Value = wsInput.Cells(emptyRow, productCol).Value & ", " & LockboxCheckBox.Caption
End If
End If
I want to make this a small subroutine and need to pass the checkbox.value as well as the checkbox.caption to it when I call it.

The following code example demonstrates how to pass a Checkbox control on a UserForm to another procedure, get the checkbox's value and caption, and do something with them.
Note that I choose to pass the checkbox, rather than the value and caption as two parameters, as this will reduce the amount of code you need to type.
Private Sub btnOK_Click()
Dim chk As MSForms.CheckBox
Set chk = Me.CheckBox1
ProcessCheckBox chk
ProcessCheckBox Me.CheckBox2
End Sub
Sub ProcessCheckBox(chk As MSForms.CheckBox)
Dim chkVal As Boolean
Dim chkCap As String
chkVal = chk.value
chkCap = chk.Caption
If chkVal = True Then
Debug.Print chkCap & " is true"
Else
Debug.Print chkCap & " is false"
End If
End Sub

Related

Highlight field background in continuous form

I have an Access continuous form. I would like to change the forecolor of a specific record's field.
I have the field to highlight from the FieldModified field. So for example FieldModified = "Converted". Converted being a field on my form.
I would like to change the color of the "Converted" field, and do this for each record in the form.
I thought this code would work, but I get an error on Me.[FieldModified].ForeColor. And I need to do this for each record in the form.
Code:
Private Sub Form_Load()
Dim fldName As String
fldName = Me.FieldModified.value
If (Not IsNull(fldName)) Then
Me.[fldName].ForeColor = vbRed '<--doesn't recognize fldName value
End If
End Sub
Updated code but it gives me an error 438 saying object doesn't support this property or method. But the form does highlight fields on the form but it highlights more then the one field "fldName"
Private Sub Form_Load()
Dim rstForm As String
Dim fldName As String
Set rstForm = Me.ChangedData.Form.Recordset
Do While Not rstForm.EOF
fldName = Me.FieldModified.value
If (Not IsNull(fldName)) Then
Me.Controls(fldName).ForeColor = vbRed '<--doesn't recognize fldName value
End If
rstForm.MoveNext
Loop
End Sub
You set the default format for the control. Every copy of the control in the continuous form uses this format. To format by a condition (fldName = Me.FieldModified.value) you need Condtional Formatting as Andre told you or use the detail-sections paint event (see update on bottom)
In conditional format wizard, you can create a condtion withExpression Isand[Converted].Name = [FieldModified]for each control of the form that should be highlighted, if its name matchesFiledModified. In Ms Access expressions you can't useMe, just omit it .
You can use VBA to format all controls with FormatConditions by code. If you want to modify an existing condition use.Modifyinstead of.Add
Private Sub Form_Load()
Dim ctl As Access.Control
For Each ctl In Me.Controls ' loop through all controls of form
On Error Resume Next ' Not all controls can have conditional format (e.g. labels). To save the check of control type, we ignore errors here
ctl.FormatConditions.Add(acExpression, , ctl.Name & ".Name=[FieldModified]").BackColor = vbRed 'add o format condition to control if possible, else an error is raised but ignored
If Err.Number Then 'show errors
Debug.Print "Error: " & Err.Number & " - " & Err.description & " in Control: " & ctl.Name & " Type is " & TypeName(ctl)
Err.Clear 'reset error to catch next
Else
Debug.Print "FormatCondition added to Control: " & ctl.Name & " Type is " & TypeName(ctl)
End If
Next ctl
On Error GoTo 0 ' turn on errors again, maybe add an error handler (On Error Goto MyErrHandler)
End Sub
Update:
You can use theDetails_Paintevent of the form to format same control different per record. This enables conditional format for controls withoutFormatConditionsproperty like labels, buttons.
Private Sub Detail_Paint()
Dim c As Access.Control
For Each c In Me.Detail.Controls
If c.Name = Me.FieldModified.Value Then
c.ForeColor = vbRed
Else
c.ForeColor = vbBlack
End If
Next
End Sub
You can't use a String variable like this, fldName is an identifier holding a String value.. not an identifier - in Me.ControlName, both Me and ControlName are identifiers.
But not all hope is lost! You can use a String to pull a Control object from a form!
All form controls should exist in the form's Controls collection, keyed by name:
Me.Controls(fldName).ForeColor = vbRed

Checking and Unchecking Checkboxes in Access

I have a form in MS Access with multiple checkboxes which I want to use to fill up one textbox. If one of the checkboxes gets unchecked, I want its value to be deleted from the textbox without deleting other values. I'm new at using Access and coding in VBA (been reading ebooks for the past 3 weeks) and although I've tried to do research online it's been difficult for me to find the right code.
This is what I have so far:
First code found
Private Sub cb_click()
If Me.cb1 = True Then
Me.txtComentarios.Value = "INACTIVO;"
Else
Me.txtComentarios.Value = Null
End If
End Sub
Second code found
Private Sub cb2_Click()
If Me.cb2 = -1 Then
Me.[txtComentarios] = [txtComentarios] & "DISCREPANCIA"
Else
Me.[txtComentarios] = ""
End If
Exit Sub
End Sub
Also I would like for the checkboxes to fill the textbox in the same order the chechboxes are displayed.
Ex.
cb1; cb2; cb3
If, cb2 gets unchecked and its value gets deleted, I should have "cb1; cb3" but if I re-check cb2 I should get "cb1; cb2; cb3" again.
I just hope someone could guide me in. Thank you in advance.
Luz
You don't need events for each checkbox. Just create one procedure, which creates full text depending on checkboxes state and puts this text to the textbox. To call this function after each click on checkbox set After Update property of all checkboxes to =MyFunctionToUpdateTextbox instead of [Event Procedure]
Private Function MyFunctionToUpdateTextbox()
Dim strText As String
If Me.cb1 = True Then
strText = strText & "INACTIVO;"
End If
If Me.cb2 = True Then
strText = strText & "DISCREPANCIA;"
End If
If Me.cb3 = True Then
strText = strText & "Text for cb3"
End If
Me.txtComentarios = strText
End Function

Create dynamic input for variable

I hope someone can help, I am new to programming, my problem is this:
40 checkboxes on a form which one by one, needs to be checked for boolean "True" or "False" (checked or unchecked by user), so that I can run individual code for each "True" case.
I am trying to include a counter "i" in the "MS Access checkbox reference" which I use for the variable, to give me the value of the given checkbox. The following code should show what I try to accomplish, can anybody point me in the right direction, without using a very advanced solution? I presume it is because it cannot execute all of this in a single step or because it only sees my input for the variable as a string and not a command to execute :
Do While Flag = True
Dim CheckboxVar As Boolean
i = i + 1
If i = 40 Then
Flag = False
End If
CheckboxVar = "Me.Checkbox" & i & ".Value"
AddWhereSQL = SQLBuilder (CheckboxVar)
Loop
(Retrieve the value of Checkbox1 and send it to SQLBuilder, retrieve Checkbox2 and send it to SQLBuilder, and so on)
Loop through your checkboxes like this:
Sub Test()
Dim ctrl As Control
For Each ctrl In Me.Controls
If TypeOf ctrl Is CheckBox Then
If ctrl.Value = True Then
'do something
End If
End If
Next ctrl
End Sub
Naming your checkboxes "Checkbox1", "Checkbox2", etc. is tiresome and not the best naming practice. The code above will find every checkbox on the form but you could easily restrict it to all checkboxes with a specific tag, for example.
To loop through the controls, you can do this:
Dim i As Long
For i = 1 To 40
If Me.Controls("CheckBoxControlName" & i).Value = -1 Then
'The control value is True
End If
Next i
If you code is placed in a Standard Module, change Me to Forms!YourFormName.
I think you need a "for" loop. Maybe something like:
CheckboxVar = " WHERE "
For i = 1 to 40
CheckboxVar = Me.Controls("Checkbox" & i).Value = True & " AND " & checkboxVar
next

check if textbox exists vba (using name)

I am using Ms-Access and I created a userform which has a number of Textboxes on it. The boxes are named: Box1, Box2, Box3 ...
I need to loop through all boxes, but I don't know which is the last one. To avoid looping through all userform controls I thought of trying the following:
For i =1 To 20
If Me.Controls("Box" & i).value = MyCondition Then
'do stuff
End If
Next i
This errors at Box6, which is the first box not found. Is there a way to capture this error and exit the loop when it happens.
I know I could use On Error but I 'd rather capture this specific instance with code instead.
Thanks,
George
A Controls collection is a simplified collection of controls (obviously) and share a same order as a placement order of controls.
First of all, even a creatable collection object lacks methods such as Exists or Contains , hence you need a function with error handling to checking/pulling widget from a collection.
Public Function ExistsWidget(ByVal Name As String) As Boolean
On Error Resume Next
ExistsWidget = Not Me.Controls(Name) Is Nothing
On Error GoTo 0
End Function
If you really doesnt like "ask forgiveness not permission" option you can pull entire ordered collection of your textboxes (and/or check existance by name in another loop with similar logic).
Public Function PullBoxes() As Collection
Dim Control As MSForms.Control
Set PullBoxes = New Collection
For Each Control In Me.Controls
If TypeOf Control Is MSForms.TextBox And _
Left(Control.Name, 3) = "Box" Then
Call PullBoxes.Add(Control)
End If
Next
End Function
Since names of widgets are unique - you can return a Dictionary from that function with (Control.Name, Control) pairs inside and able to check existance of widget by name properly w/o an error suppression.
There's a good guide to Dictionary if it's a new information for you.
Anyway, no matter what object you choose, if user (or code) is unable to create more of thoose textboxes - you can convert this Function above to a Static Property Get or just to a Property Get with Static collection inside, so you iterate over all controls only once (e.g. on UserForm_Initialize event)!
Public Property Get Boxes() As Collection
Static PreservedBoxes As Collection
'There's no loop, but call to PullBoxes to reduce duplicate code in answer
If PreservedBoxes Is Nothing Then _
Set PreservedBoxes = PullBoxes
Set Boxes = PreservedBoxes
End Property
After all, the last created TextBox with name Box* will be:
Public Function LastCreatedBox() As MSForms.TextBox
Dim Boxes As Collection
Set Boxes = PullBoxes
With Boxes
If .Count <> 0 Then _
Set LastCreatedBox = Boxes(.Count)
End With
End Function
I think that now things are clearer to you! Cheers!
Note: All code are definitely a bunch of methods/properties of your form, hence all stuff should be placed inside of form module.
Long story short - you cannot do what you want with VBA.
However, there is a good way to go around it - make a boolean formula, that checks whether the object exists, using the On Error. Thus, your code will not be spoiled with it.
Function ControlExists(ControlName As String, FormCheck As Form) As Boolean
Dim strTest As String
On Error Resume Next
strTest = FormCheck(ControlName).Name
ControlExists = (Err.Number = 0)
End Function
Taken from here:http://www.tek-tips.com/viewthread.cfm?qid=1029435
To see the whole code working, check it like this:
Option Explicit
Sub TestMe()
Dim i As Long
For i = 1 To 20
If fnBlnExists("Label" & i, UserForm1) Then
Debug.Print UserForm1.Controls(CStr("Label" & i)).Name & " EXISTS"
Else
Debug.Print "Does Not exist!"
End If
Next i
End Sub
Public Function fnBlnExists(ControlName As String, ByRef FormCheck As UserForm) As Boolean
Dim strTest As String
On Error Resume Next
strTest = FormCheck(ControlName).Name
fnBlnExists = (Err.Number = 0)
End Function
I would suggest testing the existence in another procedure per below: -
Private Sub Command1_Click()
Dim i As Long
i = 1
Do Until Not BoxExists(i)
If Me.Conrtols("Box" & i).Value = MyCondition Then
'Do stuff
End If
i = i + 1
Next
End Sub
Private Function BoxExists(ByVal LngID As Long) As Boolean
Dim Ctrl As Control
On Error GoTo ErrorHandle
Set Ctrl = Me.Controls("BoX" & LngID)
Set Ctrl = Nothing
BoxExists = True
Exit Function
ErrorHandle:
Err.Clear
End Function
In the above, BoxExists only returns true if the box does exists.
You have taken an incorrect approach here.
If you want to limit the loop, you can loop only in the section your controls reside e.g. Detail. You can use the ControlType property to limit controls to TextBox.
Dim ctl As Control
For Each ctl In Me.Detail.Controls
If ctl.ControlType = acTextBox Then
If ctl.Value = MyCondition Then
'do stuff
End If
End If
Next ctl
I believe the loop will be faster than checking if the control name exists through a helper function and an On Error Resume Next.
But this only a personal opinion.

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