So I'm making a userform and I have to use make a group of mutually exclusive checkboxes or only allow the user to pick one. "But just use option buttons!" you cry. Two problems with that:
I already have a separate set of option buttons in the userform (I believe you can somehow group them to allow multiple sets but I am unfamiliar with how to actually do this).
My professor specifically wants checkboxes
so I attempted to solve this problem like this
If CheckBoxBar.Value = True And CheckBoxatm.Value = True Then
GoTo Here:
End If
If CheckBoxatm.Value = True And CheckBoxmmHg.Value = True Then
GoTo Here:
End If
If CheckBoxatm.Value = True And CheckBoxpsia.Value = True Then
GoTo Here:
End If
If CheckBoxBar.Value = True And CheckBoxmmHg.Value = True Then
GoTo Here:
End If
If CheckBoxBar.Value = True And CheckBoxpsia.Value = True Then
GoTo Here:
End If
If CheckBoxmmHg.Value = True And CheckBoxpsia.Value = True Then
GoTo Here:
End If
The here leads to a message box that re initializes the userform after the msg box says "You are only allowed to select one" with code like this
Here: MsgBox "You are only allowed to select on pressure unit."
The code "works" but it always goes to the Here: statement despite only picking one of the checkboxes. Can you spot anything wrong?
Thanks for the help!
As stated by Doug Glancy in a comment, your current code is probably missing an Exit Sub before the label Here:, which is therefore allowing your code to fall into the section after the label.
Another way of achieving what you are after is just to have one If statement which checks if more than one CheckBox is checked, and then display the MsgBox if so, e.g. as follows:
If CheckBoxBar.Value + _
CheckBoxatm.Value + _
CheckBoxmmHg.Value + _
CheckBoxpsia.Value < -1 Then
MsgBox "You are only allowed to select one pressure unit."
Exit Sub
End If
Or you can rely on the .Value being the default property of a CheckBox and thus "reduce" that code to:
If CheckBoxBar + CheckBoxatm + CheckBoxmmHg + CheckBoxpsia < -1 Then
MsgBox "You are only allowed to select one pressure unit."
Exit Sub
End If
Note: This method won't work if the .TripleState property of the CheckBox is set to True. (My thanks to Comintern for pointing that out.)
You can make the checkboxes act like option buttons if you override the click function and clear the other boxes (although you can also have none selected).
Private Sub CheckBoxatm_Click()
If Me.Controls("CheckBoxatm").Value = True Then Call ClearOtherValues("CheckBoxatm")
End Sub
Private Sub CheckBoxBar_Click()
If Me.Controls("CheckBoxBar").Value = True Then Call ClearOtherValues("CheckBoxBar")
End Sub
Private Sub CheckBoxmmHg_Click()
If Me.Controls("CheckBoxmmHg").Value = True Then Call ClearOtherValues("CheckBoxmmHg")
End Sub
Private Sub CheckBoxpsia_Click()
If Me.Controls("CheckBoxpsia").Value = True Then Call ClearOtherValues("CheckBoxpsia")
End Sub
Private Function ClearOtherValues(cb As String)
Dim cbPressure() As String, i As Long
cbPressure = Split("CheckBoxBar,CheckBoxatm,CheckBoxmmHg,CheckBoxpsia", ",")
For i = 0 To UBound(cbPressure)
If cbPressure(i) <> cb Then Me.Controls(cbPressure(i)).Value = False
Next i
End Function
Related
Situation
I have two form control check boxes. I am trying to write a code that will allow only either of them to be true.
my code is
Sub CheckBox2_Click()
If CheckBox1.Enabled = True Then
CheckBox2.Enabled = False
Else
If CheckBox2.Enabled = True Then
CheckBox1.Enabled = False
End If
End If
End Sub
I have this code in module and have assigned the same macro for both the checkboxes. I get run-time error 424. I beleive this is very basic problem but I unable to dela with it.
Thank you
Please, test the following way. Form check boxes do not have a click event, as ActiveX ones have. You should associate the next sub to both of them. The check boxes I tested, have their names as "Check Box 1" and "Check Box 2". You have to change yours according to the reality in your case, Please, copy the next code in a standard module and then associate it to both used check boxes:
Option Explicit
Sub FormCheckBoxChange()
If ActiveSheet.CheckBoxes(Application.Caller).value = 1 Then
Select Case Application.Caller
Case "Check Box 1": ActiveSheet.CheckBoxes("Check Box 2").value = -4146
Case "Check Box 2": ActiveSheet.CheckBoxes("Check Box 1").value = -4146
End Select
End If
End Sub
Use instead of the used check box names, the appropriate ones for your case.
In case of Form text boxes, their value is not True and False as in case of ActiveX ones. It is 1 and -4146...
Are you sure you want to enable/disable the checkboxes.
Following code makes sure that either one of both boxes is checked.
Public Sub checkbox2_onClick()
Dim oCb1 As Object
Set oCb1 = Table1.Shapes("Checkbox1").OLEFormat.Object
Dim oCb2 As Object
Set oCb2 = Table1.Shapes("Checkbox2").OLEFormat.Object
If oCb2.Value = 1 Then oCb1.Value = 0
End Sub
Public Sub checkbox1_onClick()
Dim oCb1 As Object
Set oCb1 = Table1.Shapes("Checkbox1").OLEFormat.Object
Dim oCb2 As Object
Set oCb2 = Table1.Shapes("Checkbox2").OLEFormat.Object
If oCb1.Value = 1 Then oCb2.Value = 0
End Sub
I want the checkbox stays the same and generates a message box.
Private Sub CheckBox1_Click()
Dim beast As String
beast = Range("k1").Value
If beast = "No" Then
CheckBox1 = False
MsgBox "You Are Missing Ingredients", vbCritical, "Missing Ingredients"
End If
End Sub
Disable application events. Application events for ActiveX controls are trapped by the code sheet belonging to the worksheet on which the control has been installed. Therefore the code below must be on that code sheet, not a standard code module where it will never run.
Private Sub CheckBox1_Click()
Dim beast As String
With CheckBox1
If .Value = True Then
beast = Range("K1").Value
If beast = "No" Then
MsgBox "You Are Missing Ingredients", vbCritical, "Missing Ingredients"
' prevent the upcoming change from triggering this event
Application.EnableEvents = False
.Value = False
Application.EnableEvents = True
End If
End If
End With
End Sub
Make sure that your check box is an ActiveX control. In fact, once you create such a control it will be listed in the controls drop-down on the top left of the sheet's code module and VBA will create or select the click event procedure for you.
I have tested the above code and it doesn't run more thna once on one click. I have added a check to let it do nothing if the checkmark was removed rather than set.
You can use a static boolean variable to avoid the double execution, like so:
Private Sub CheckBox1_Click()
Static isBusy As Boolean
Dim beast As String
If Not isBusy Then
isBusy = True
beast = Range("k1").Value
If beast = "No" Then
CheckBox1.Value = False
MsgBox "You Are Missing Ingredients", vbCritical, "Missing Ingredients"
End If
isBusy = False
End If
End Sub
Static variables maintain their values across invocations, so if you set it in the first CheckBox1_Click invocation, you can check it in the second one and know a first invocation is ongoing.
I get
Compile Error: Expected function or variable
when I select a radio button and click ok on my form. The top line of code where the macro title is gets highlighted in yellow.
My form is four radio buttons and an ok button.
I've checked the macro names and option button names
Private Sub CommandButton1_Click()
If Ties.Radio_OpPlan.Value = True Then
Run clearties
ElseIf Ties.Radio_Prior.Value = True Then
Run TieToPrevious
ElseIf Ties.Radio_Custom.Value = True Then
Run CustomTie
ElseIf Ties.Radio_NetCase.Value = True Then
Run NetCaseTie
Else
output = MsgBox("You need to pick a case to tie to", vbExclamation)
End If
Me.Hide
output = MsgBox("Case tied out", vbOKOnly)
End Sub
Your issue is more than like due to the use of Run. This is used to call a macro from its name as a String.
Try removing Run from your different methods and see if that fixes it.
Private Sub CommandButton1_Click()
If Ties.Radio_OpPlan.Value = True Then
clearties
ElseIf Ties.Radio_Prior.Value = True Then
TieToPrevious
ElseIf Ties.Radio_Custom.Value = True Then
CustomTie
ElseIf Ties.Radio_NetCase.Value = True Then
NetCaseTie
Else
output = MsgBox("You need to pick a case to tie to", vbExclamation)
End If
Me.Hide
output = MsgBox("Case tied out", vbOKOnly)
End Sub
Additional Notes
Try not to use underscore case. Underscores have special meanings in VBA for events and implementations. So instead of Radio_OpPlan you could do RadioOpPlan, or even better simply OpPlan (really even make OpPlan even more descriptive).
In my opinion, a Case statement looks cleaner in this situation.
Select Case True
Case RadioOpPlan
clearties
Case RadioPrior
TieToPrevious
Case RadioCustom
CustomTie
Case RadioNetCase
NetCaseTie
Case Else
output = MsgBox("You need to pick a case to tie to", vbExclamation)
End Select
this is what worked, and all the macros had to make sure they started with selecting the sheet I was making changes on first
Private Sub CommandButton1_Click()
If Ties.OpPlan.Value = True Then
clearties
ElseIf Ties.Prior.Value = True Then
TieToPrevious
ElseIf Ties.Custom.Value = True Then
CustomTie
ElseIf Ties.NetCase.Value = True Then
NetCaseTie
Else
output = MsgBox("You need to pick a case to tie to", vbOKOnly)
End If
Me.Hide
End Sub
I am trying to make a label visible if a Textbox has a value. So far I have this but its not working?
Private Sub Label1_Change()
If MailChannel.Value <> "" Then
Me.Label1.Caption = True
Else
Me.Label1.Caption = False
End If
End Sub
Your current code won't be triggered now, because it is linked to form's label. You should link it to textbox change event. It can be realized as follows (assuming that textbox name is txtMailChannel):
Private Sub txtMailChannel_Change()
If txtMailChannel.Value <> "" Then
lblMailChannel.Visible = True
Else
lblMailChannel.Visible = False
End If
End Sub
P.S. Try to introduce some order to your code, especially what concerns naming convention of variables. Please check-out the following link for references: https://github.com/spences10/VBA-Coding-Standards.
I have 5 checkboxes to set some options for a macro, one of them is a Select/Unselect All checkbox. I want to create something similar to what you have on web-based mailboxes when you select mails to delete or mark as read, etc.
When I check the Select/Unselect All checkbox, I turn the rest of the checkboxes's values to true and viceversa when I uncheck it. That's ok.
The problem comes when I also want to validate that if everything is unchecked and one by one I check the other checkboxes, if in the end I check all, then the Select/Unselect All checkbox turns to checked. And viceversa, meaning that if eveything is checked and then I uncheck one of the four others, then I turn the "All" checkbox to false (unchecked).
But it seems that even when I just set the value, for example Option1Checkbox.value = True, in the SelectAllCheckbox_Click event, it triggers both the Option1Checkbox_Click and Option1Checkbox_Change events.
Shouldn't it just trigger the Change event since I'm not actually clicking that checkbox?
What happens is that I check the SelectAll, so it turns Option1 to checked, but by doing this, Option1 triggers also the click event so it unchecks it which triggers the click event again and then unchecks again the All checkbox which in the end leaves everything unchecked, like at the beginning. Hope this part is clear enough.
How can I avoid this behavior? How can I make sure only the Change event is triggered and not the Click event?
Has anyone ever had such an arrangement of checkboxes and had a similar problem? Or how did you manage to do this without the behavior I'm getting?
The checkboxes are not on a form but simply on a worksheet. They are ActiveX controls. And what I have is nothing complicated:
Private Sub SelectAll_Click()
Option1Checkbox.Value = SelectAll.Value
Option2Checkbox.Value = SelectAll.Value
Option3Checkbox.Value = SelectAll.Value
Option4Checkbox.Value = SelectAll.Value
End Sub
Then the options checkboxes click events look like this:
Private Sub Option1Checkbox_Click()
If Option1Checkbox.Value = True And Option2Checkbox.Value = True And Option3Checkbox.Value = True And Option4Checkbox.Value = True Then
SelectAll.Value = True
Else
SelectAll.Value = False
End If
End Sub
It's quite simple, the biggest problem I see is the calls to the click events when the checkbox is not actually click.
Thanks for your help.
I would define a local variable (one defined outside the subs) and set/check that
Option Explicit
Dim ImChangingStuff As Boolean
Private Sub SelectAll_Click()
ImChangingStuff = True
Option1Checkbox.Value = SelectAll.Value
Option2Checkbox.Value = SelectAll.Value
Option3Checkbox.Value = SelectAll.Value
Option4Checkbox.Value = SelectAll.Value
ImChangingStuff = False
End Sub
then your click routines would look like this:
Private Sub Option1Checkbox_Click()
If ImChangingStuff Then Exit Sub
If Option1Checkbox.Value = True And Option2Checkbox.Value = True And Option3Checkbox.Value = True And Option4Checkbox.Value = True Then
SelectAll.Value = True
Else
SelectAll.Value = False
End If
End Sub
To solve this problem,
in your main userform (in this example it is called Mainform) add this code:
Private Sub Mainform_Initialize()
stateCheckbox = True
End Sub
Create a module to store your global variables (eg. globalVariables), and add the following, which will hold the state of the checkbox:
Public stateCheckbox as Boolean
In the _click event of your checkbox, wrap your code like this:
if stateCheckbox = false then
{ whatever your code is }
Else:
stateCheckbox = false
end if
I have had the same issue as described above. I recognized that each change of a Checkbox, no matter if by click or by changing Checkbox.Value, each time first fires the Checkbox_Change event and then the Checkbox_Click event , provided that any of these events are declared.
I would thus recommend to use only one event for each checkbox, p.e. the Checkbox_Change event, and to check if the checkbox has been changed by click or by declaration at the beginning of the Sub. This can be done by comparing the ActiveControl.Name with the Checkbox.Name:
Private Sub CheckBox1_Change()
On Error Goto Err:
If ActiveControl.Name = CheckBox1.Name Then
On Error Goto 0
'Commands for click
Exit Sub
Else
On Error Goto 0
'Commands for change from within the Userform
Exit Sub
Err:On Error Goto 0
'Commands for change from outside the Userform
End Sub
I would write a sub checking if Option1 to Option4 are all checked in an If statement. In a second if statemement, I'd check to see if they are all false:
Sub Are_O1_to_O4_All_Checked ()
If Option1Checkbox.Value = True And _
Option2Checkbox.Value = True And _
Option3Checkbox.Value = True And _
Option4Checkbox.Value = True Then
Option5Checkbox.Value = True ' select/unselect checkbox
End If
If Option1Checkbox.Value = False And _
Option2Checkbox.Value = False And _
Option3Checkbox.Value = False And _
Option4Checkbox.Value = False Then
Option5Checkbox.Value = False ' select/unselect checkbox
End If
End Sub
Then I would Call this sub at the end of each OnClick event for the check boxes.