Cycling through some checkboxes on my excel page - vba

I am VERY new to VBA (and know of it only within excel).
I am trying to cycle through some (but not all) checkboxes. They are currently named CheckBox1 through CheckBox15. Howe do I cycle through say for instance CheckBox5 through CheckBox10?
I guess I am hoping there is a 'method' similar to 'CheckType' for controls that will allow me to check name?
Here is what I have tried. Causes a Compile Error - Sub or Function not defined, and highlights Worksheet.
Private Sub BoxCheck()
atLeastOneChecked = False
For i = 2 To 4
If Worksheets("ActiveX").Controls("Checkbox" & i).Value = True Then
atLeastOneChecked = True
End If
Next i
End Sub
While the above doesnt work, what is below does:
Private Sub BoxCheck()
atLeastOneChecked = False
For i = 1 To 2
If Sheet2.CheckBox2.Value = True Then
atLeastOneChecked = True
End If
Next i
End Sub
Of course, the loop has no affect on the outcome, but it compiles and atLeastOneChecked turns from False to True when Checkbox2 is True. Note that Sheet2 has been named ActiveX. I clearly don't understand how Worksheet and Controls work. Could someone help?
After fixing the error described below, this still won't work. I simplified to the following:
Private Sub BoxCheck()
Dim ole As OLEObject
atLeastOneChecked = False
Set ole = Sheets("ActiveX").OLEObjects("Checkbox2")
If ole.Value = True Then
atLeastOneChecked = True
End If
End Sub
This doesn't work. It fails at:
If ole.Value = True Then
The error states: Object Doesn't support this property or method
This is true for OLEObjects, but not for Checkboxes. When I look at the properties of ole, I see that its Object property is set to Object/Checkbox and that this Object has a value. I guess that is what I should be referencing in my if statement, but I don't know how.

I think I solved the problem.
The value of the Checkbox is accessed by Referencing the Object property within the OLEObject I set...Like this:
If ole.Object.Value = True Then
Thanks for all your help. If someone has a more elegant solution, I would still like to see it.

Use CheckBox.Name
Example:
For Each cb In ActiveSheet.CheckBoxes
If cb.Name = "CheckBox5"
' Do stuff
End If
Next cb

To expand on #Parker's answer:
Private Sub BoxCheck()
atleastonechecked = False
Dim oles As OLEObject
For i = 2 To 4
'If you're using Shapes Controls:
If ThisWorkbook.Worksheets("ActiveX").Shapes("Check Box " & i).Value = True Then
atleastonechecked = True
End If
' If you're using ActiveX Controls
Set oles = ThisWorkbook.Worksheets("ActiveX").OLEObjects("CheckBox" & i)
If oles.Value = True Then
atleastonechecked = True
End If
Next i
End Sub
Sorry, just put together the previous answer without testing - that always fails. Just use the If loop based on what type of control you're using.

Related

(Excel Userform) Check if all checkboxes in a Userform are checked

Never tried UserForm checkboxes before so I don't even know how to point to the Checkboxes in a Userform.
This is what I have at the moment....and I know, I know, it is completely wrong. Please help?
Private Sub Step1_Confirm_Click()
Dim i As Byte
Dim Done As Boolean
For i = 1 To 4
If Step1_(i).value = True Then
Done = True
End If
Next i
If Not Done = True Then
MsgBox "Please make sure you have done all"
End If
End Sub
Basically I have:
A Userform called IOSP_Acc_R_Approval_Step1
4 checkboxes called Step1_1; Step1_2; Step1_3; Step1_4
A button called Step1_Confirm
I want the button to show Error, if not all checkboxes are checked - meaning that all checkboxes have to be checked....(in case my English is too bad to convey my meaning)
Try the code below (explanations inside the code as comments):
Private Sub Step1_Confirm_Click()
Dim i As Long
Dim Ctrl As Control
' loop through all user_form control
For Each Ctrl In IOSP_Acc_R_Approval.Controls
If TypeName(Ctrl) = "CheckBox" Then ' check if control type is Check-Box
If Ctrl.Value = True Then ' check if check-box is checked
i = i + 1
End If
End If
Next Ctrl
If i < 4 Then ' not all 4 check-boxes are checked
MsgBox "Please make sure you have done all"
End If
End Sub
You can do this by:
assume that all checkboxes are checked by setting a flag to True
iterate the checkboxes and if one is not checked set the flag to False and exit
at the end of the loop, if all checkboxes were checked then the flag is still True
You can refer to the checkboxes dynamically by using the Me.Controls collection and pass in the name of the checkbox like "Step1_" & i.
Example code:
Option Explicit
Private Sub Step1_Confirm_Click()
Dim i As Long '<-- use Long, not Byte
Dim blnResult As Boolean
' set a flag to assume that it is true that all checkboxes are checked
blnResult = True
' get the value of each check box
For i = 1 To 4
If Me.Controls("Step1_" & i).Value = False Then
blnResult = False
Exit For '<-- skip loop if at least one box not checked
End If
Next i
' check the value of the flag
If blnResult = False Then
MsgBox "Please make sure you have done all"
Else
' all boxes checked ...
MsgBox "All checked"
End If
End Sub
Done=true
For i = 1 To 4
Done = Done*Step1_(i).value
Next i
if done `then`
msgbox "All checkboxes are checked"
end if

vba Checkbox if else condition in Subform, access

I have a main form with several tab controls with subforms in them. On the first tab or subform I have a "checkbox 1", which shall be:
checked if "textbox 1" is not empty
unchecked if "textbox 1" is empty
The code is directly put into the Class Object of "subform 1", that's why I thought I could use Me.
Here is my code, but I always get error messages :(
Private Sub Ctltextbox_1_AfterUpdate()
If Len(Ctltextbox_1.Value) = 0 Then
Me.checkbox_1.Value = 0
Else
Me.checkbox_1.Value = -1
End If
End Sub
That way I am getting the
Run-time error '2448': You can't assign a value to this object.
On the line that attempts to assign -1 to Me.checkbox_1.Value.
Try this. It is working for me. I moved it to the Ctltextbox_1_Change action. This will call the function whenever it is changed and will catch when you have nothing in the box as well. I also changed your values to True and False.
Please try this and let me know.
Private Sub Ctltextbox_1_Change()
If Len(frmSub.Ctltextbox_1.Value) = 0 Then
frmSub.CheckBox_1.Value = False
Else
frmSub.CheckBox_1.Value = True
End If
End Sub
you can also solve this in one line as mentioned below.
Private Sub Ctltextbox_1_Change()
frmSub.CheckBox_1.Value = IIf((Len(frmSub.Ctltextbox_1.Value) = 0), False, True)
End Sub
Ok, the simple answer is: you can not use the expression Len()= 0 for a not numeric field! So my working code for the subform is now:
Private Sub Textbox1_AfterUpdate()
If IsNull(Textbox1.Value) = False Then
Me.checkbox1.Value = True
Else
Me.checkbox1.Value = False
End If
End Sub
Thank you all for your help! :)

Userform controlled variables within a macro

Morning Guys,
I have ran into a small roadblock with my project. I'm new to VBA and am trying my best to 'learn by doing' but I cannot seem to get my head around macro/userform interactions.
I have a userform with one textbox and 9 checkboxes. This is supposed to show the userform, allow the user to dictate a sheet name, and (from a list of 9 users) select which is active or not (true or false).
In my main sub, I just have a
Allocator.show
command, as you may have guessed, allocator is my userform name.
Then I've sort of just been trying things so I don't know how right the rest of the userform code is;
Private Sub cbGo_Click()
Unload Allocator
End Sub
Private Sub cboxAlison_Click()
If Me.cboxAlison.Value = True Then
AlisonYN = True
Else
AlisonYN = False
End If
End Sub
Private Sub cboxBeverly_Click()
If Me.cboxBeverly.Value = True Then
BevelyYN = True
Else
BevelyYN = False
End If
End Sub
Private Sub cboxCallum_Click()
If Me.cboxCallum.Value = True Then
CallumYN = True
Else
CallumYN = False
End If
End Sub
Private Sub cboxEllen_Click()
If Me.cboxEllen.Value = True Then
EllenYN = True
Else
EllenYN = False
End If
End Sub
Private Sub cboxGeoff_Click()
If Me.cboxGeoff.Value = True Then
GeoffYN = True
Else
GeoffYN = False
End If
End Sub
Private Sub cboxJames_Click()
If Me.cboxJames.Value = True Then
JamesYN = True
Else
JamesYN = False
End If
End Sub
Private Sub cboxLouise_Click()
If Me.cboxLouise.Value = True Then
LouiseYN = True
Else
LouiseYN = False
End If
End Sub
Private Sub cboxMick_Click()
If Me.cboxMick.Value = True Then
MickYN = True
Else
MickYN = False
End If
End Sub
Private Sub cboxTammy_Click()
If Me.cboxTammy.Value = True Then
TammyYN = True
Else
TammyYN = False
End If
End Sub
Private Sub tbRPName_Change()
End Sub
Private Sub UserForm_Initialize()
Dim GeoffYN, TammyYN, CallumYN, JamesYN, MickYN, AlisonYN, BeverlyYN, LouiseYN, EllenYN As Boolean
Dim RP_Name As String
Me.cboxGeoff.Value = True
Me.cboxTammy.Value = True
Me.cboxCallum.Value = True
Me.cboxJames.Value = True
Me.cboxMick.Value = False
Me.cboxAlison.Value = False
Me.cboxBeverly.Value = False
Me.cboxLouise.Value = False
Me.cboxEllen.Value = False
Me.tbRPName = ""
End Sub
All of the named user variables (xxxxYN) are public in my main module.
These are the variables I want to pull back into my main macro as true or false following the user checking the desired boxes, along with the name as a string, and then continue running the original macro.
Any help would be greatly appreciated, I seem to be taking myself round in circles at the moment!
PS if it helps, my userform looks like this;
UserForm
Cheers,
Callum
You wrote "All of the named user variables (xxxxYN) are public in my main module." But we see them declared in userform's Sub UserForm_Initialize, too:
Private Sub UserForm_Initialize()
Dim GeoffYN, TammyYN, CallumYN, JamesYN, MickYN, AlisonYN, BeverlyYN, LouiseYN, EllenYN As Boolean
Dim RP_Name As Stringn
...
even if you declared the same variables as Public in any module, the Userform variables hide their Public namsakes so any Userform setting is not "seen" in other modules
so you'd better remove the Userform dimming statement of the "namesakes" and leave only the Public one
moreover in such a declaration statement as you used, every single variable not explicitly associated with a specific type is implicitly associated to a Variant type
so in the main module you should use a "dimming" statement like follows:
Public GeoffYN As Boolean, TammyYN As Boolean, CallumYN As Boolean, JamesYN As Boolean, MickYN As Boolean, AlisonYN As Boolean, BeverlyYN As Boolean, LouiseYN As Boolean, EllenYN As Boolean
But should all what above get you going, nevertheless I'd recommend you to switch to a "class" approach together with the use of Dictionary object, like follows
in the Allocator code pane place the following code
Option Explicit
Dim chkBoxes() As ChkBx_Class 'array of type "ChkBx_Class" which you define in a Class Module
Private Sub UserForm_Initialize()
Dim nControls As Integer, i As Integer
Dim namesArray As Variant, cbIniValues As Variant
UFInit = True
namesArray = Array("Geoff", "Tammy", "Callum", "James", "Mick", "Alison", "Beverly", "Louise", "Ellen") '<== set here the names to be associated to every CheckBox
cbIniValues = Array(True, True, True, True, False, False, False, False, False) '<== set here the initial values of checkboxes
nControls = UBound(namesArray) + 1 '<== retrieve the number of CheckBoxes you're going to consider in the Form
ReDim chkBoxes(1 To nControls) As ChkBx_Class 'redim the "ChkBx_Class" array
For i = 1 To nControls
Set chkBoxes(i) = New ChkBx_Class 'initialize a new instance of 'ChkBoxClass' class and store it in the array i-th position
With chkBoxes(i)
Set .ChkBox = Me.Controls("CheckBox" & i) 'assign the correct CheckBox control to its "ChkBox" property
.Name = namesArray(i - 1) ' assign the Name property of the Checkbox
.ChkBox.Value = cbIniValues(i - 1) 'set the checkbox correct initial value
Me.Controls("Label" & i) = .Name ' set the corresponding label caption
dealersDict.Add .Name, .ChkBox.Value ' fill the dictionary initial pair of Dealer-name/checkbox-value
End With
Next i
Me.tbRPName.Text = ""
UFInit = False
End Sub
Private Sub cbGo_Click()
Me.Hide
End Sub
add a "Class Module" to your project
either clicking Insert-> Class Module in the VBA IDE main Ribbon menu
or right-clicking anywhere in the VBA IDE Project Window and selecting Insert -> Class Module in subsequent sub-menus
expand the "Class Module" node in the Project Window
if you don't see the Project Window you can open it by clicking View-> Project Window in the main ribbon menu, or press "Ctrl+R"
select the new Class you added (it should be some "Class1" or the likes) and change its name to "ChkBx_Class" in the Property Window "Name" textbox
if you don't see the Property Window you can open it by clicking View-> Property Window in the main ribbon menu or press "F4"
in the Class Module code pane place the following
Option Explicit
'declare class properties: they will be associated in every instance of this class.
Public WithEvents ChkBox As MSForms.CheckBox ' "ChkBox" is now a property of the class of type CheckBox. it's associated to events
Public Name As String
' events associated to ChkBox class property
Sub ChkBox_Click()
If Not UFInit Then dealersDict.Item(Me.Name) = Me.ChkBox.Value ' set the dictionary pair of Dealer-name/checkbox-value
End Sub
edit your main sub module as follows
Option Explicit
Public dealersDict As New Scripting.Dictionary
Public UFInit As Boolean
Sub main()
myval = "io"
Dim myKey As Variant
Allocator.Show
Unload Allocator
For Each myKey In dealersDict
MsgBox myKey & ": " & dealersDict(myKey)
Next myKey
End Sub
create a reference to Microsoft Scripting Runtime Library to use Dictionaries.
this is done by choosing Tools➜References command in the Visual Basic Editor (VBE) which pops up a dialog box in whose listbox you are to find "Microsoft Scripting Runtime" to put a check mark next and press OK.
run the main sub
whenever you need to retrieve the boolean value associated to a given name you just have to use
myBool = dealersDict(name)
where name can be:
a string literal with the wanted name ("Alison", "Mick" , ..)
a string variable whose value stores the wanted name, so that somewhere in your code you may have typed:
Dim name as string
name = "Mick"
such an approach gives you a lot of flexibility, since you only have to:
set the names and their initial boolean values in those two arrays (namesArray and cbIniValues) in UserForm_Initialize
make sure you have checkboxes named after "CheckBox1", "CheckBox2", and so on as well as have labels named after "label1", "Label2", and so on
make sure that "CheckBoxX" is aligned with "LabelX"
make sure namesArray and cbIniValues have the same items number as labels and checkboxes
IDK what the actual issue is, but I tried to recreate your issue and just decided to show you what I have. See if any of this helps you at all.
All of this code is in the userform code, not at the module level. When I change the check box values, the values are stored (outside of the main sub, which is validated in the "check" sub click event).
To make you code a little shorter, you can directly assign the value of a checkbox to a variable
Dim test as Boolean
test = me.CheckBox1.Value
You can insert this into the code of your go button

Sub or function not defined: Buttons()

I had this sub in another spreadsheet where I could click a button to collapse and expand certain columns. I copied it into a new spreadsheet to use to collapse some rows but now I get the error "Sub or function not defined". It highlights Buttons
Sub HideDetails()
Range("3:8").Select
If Selection.EntireColumn.Hidden Then
Selection.EntireColumn.Hidden = False
Buttons("btnToggleDetails").Caption = "-"
Else
Selection.EntireColumn.Hidden = True
Buttons("btnToggleDetails").Caption = "+"
Range("A1").Select
Application.CutCopyMode = False
End If
Range("A1").Select
Application.CutCopyMode = False
End Sub
There are no other scripts in this workbook. This one was originally in Module1 but I tried moving it to a new module.
Edit: I changed the button name in the code but not the screenshot. Both references are to btnToggleDetails now but it still throws the same error.
It's telling you that the identifier Buttons() can't be found in the current scope. If Buttons() is something that you've declared somewhere else, you either need to make it public or you need to fully qualify the object that contains the Buttons() object, for example:
Sheet1.Buttons("btnToggleDetails").Caption = "+"
Had to add my answer as was sure I could shorten the lines of code:
If you consider that Selection.EntireColumn.Hidden returns TRUE/FALSE or 0/-1.
CHR(45) is a minus sign.
CHR(43) is a plus sign.
ABS turns -1 into 1.
So:
If TRUE (0) then 45-(0*2) = 45
If FALSE (-1) then 45-(1*2) = 43
This will swap the columns from hidden to visible and vice-versa and display the correct button caption in the immediate window:
Sub HideShowColumns()
Selection.EntireColumn.Hidden = Not (Selection.EntireColumn.Hidden)
Debug.Print Chr(45 - (Abs(CLng(Selection.EntireColumn.Hidden)) * 2))
End Sub
This should work in your procedure:
Sub HideDetails()
Dim rng As Range
Set rng = ActiveSheet.Range("3:8")
rng.EntireColumn.Hidden = Not (rng.EntireColumn.Hidden)
Buttons("btnToggleDetails").Caption = Chr(45 - (Abs(CLng(rng.EntireColumn.Hidden)) * 2))
End Sub

Excel VBA Object Helper Function

I have a UserForm where one of my ComboBox's can have different values depending on other variables that the user has selected. Rather than update the contents of a single ComboBox every time the user makes a change, I have created two ComboBox's and simply set the appropriate one as visible. These two ComboBox's have the names "width1_cb" and "width2_cb" respectively.
I have created a helper function to return the currently active ComboBox so that other pieces of my code can use it. Here is the helper function:
Function myGetActive(ByVal control As String) As ComboBox
If control = "width" Then
If width1_cb.Visible = True Then
Set myGetActive = Me.width1_cb
ElseIf width2_cb.Visible = True Then
Set myGetActive = Me.width2_cb
Else
Set myGetActive = Nothing
End If
End If
End Function
Unfortunately, this function is not functioning as expected. I have another line of code:
Set currentWidth = myGetActive("width")
currentWidth.Value = 5
which fails on the second line. I cannot figure out what I am doing incorrectly here - my best guess is that I am somehow not returning the actual combobox instance in my helper function but instead some sort of copy, but in my research I have not been able to figure out the correct way to accomplish this. Does any one know how I can make this function work as expected?
Update: Debugging efforts I have taken including stepping through the code line-by-line and putting a "watch" within the "myGetActive" function on both the width1_cb and the myGetActive variables. What I find is that the myGetActive variable gets set to type "ComboBox/Combobox" while the width1_cb is "Object/Combobox". What's more, the context for width1_cb is "Input_Window.UserForm_Initialize" while the context for the myGetActive is "Input_Window.myGetActive". The function does exit without any errors though.
Initially I just wanted to make a comment about 2 distinct ways for declaring variables:
Private currentWidth As ComboBox
or
Private currentWidth As MSForms.ComboBox
but I can't duplicate the issue you're having. Here is the code I tested with
Option Explicit
Private currentWidth As ComboBox
'Private currentWidth As MSForms.ComboBox
Private Sub UserForm_Click()
testCombos
End Sub
Private Sub UserForm_Initialize()
With Me.width1_cb
.AddItem "test1"
.AddItem "test2"
.AddItem "test3"
End With
With Me.width2_cb
.AddItem "test1"
.AddItem "test2"
.AddItem "test3"
End With
End Sub
Private Sub testCombos()
Set currentWidth = myGetActive("width")
currentWidth.Value = 5
Set currentWidth = myGetActive(vbNullString)
currentWidth.Value = 7
End Sub
Function myGetActive(ByVal control As String) As ComboBox
If control = "width" Then
If width1_cb.Visible = True Then
Set myGetActive = Me.width1_cb
ElseIf width2_cb.Visible = True Then
Set myGetActive = Me.width2_cb
Else
Set myGetActive = Nothing
End If
Else
If width2_cb.Visible = True Then
Set myGetActive = Me.width2_cb
ElseIf width1_cb.Visible = True Then
Set myGetActive = Me.width1_cb
Else
Set myGetActive = Nothing
End If
End If
End Function
.