1

I have a lot of checkboxes on a sheet, 414 to be exact, and I don't want to have to write out checkbox1 etc every time I want to reference them so I would like to shorten their names to CB1 etc. so is there a way to use vba to rename all of the checkboxes with a looping statement?

ill add a bit of context as to why I have so many checkboxes so if you think there is a better way of doing it then please let me know.

I am trying to set up a way of generating all of the working days in a year by selecting a check box for how many days are going to be worked in a week. the different options are 0, 1, 2, 3, 4 and 5 for each week. I have the rest of this years weeks in as well as all 52 weeks for 2024. so the idea being that whoever is using the sheet to generate their expected dates of completion can go though the check boxes and select the correct number of days for each week. after doing this they can hit a macro button and it will create a long list of dates in one column that the rest of the sheet can use as a reference.

this is the code for the check boxes

Private Sub CB1_Click()
If CB1 = True Then
CB2 = False
CB3 = False
CB4 = False
CB5 = FALSE
CB6 = False
Range("AW4") = "0"
End If
End Sub

Private Sub CB2_Click()
If CB2 = True Then
CB1 = False
CB3 = False
CB4 = False
CB5 = False
CB6 = False
Range("AW4") = "1"
End If
End Sub

ETC I assume you can see what the trend would be after this.

I have never attempted to change an active x control's name with vba before and I cannot seem to find anything helpful on google about how to go about doing this so any help or suggestions would be appreciated also if there is a way to write the code for all 414 buttons using vba any info or help on that would be greatly appreciated as well.

13
  • It is easy to name all check boxes as you need, but I must confess that I did not understand anything from the context you tried explaining... So besides naming, using a class it is easy to automatically allocate a click event to all of them, using that sequence as we ca see in your code. But, this can be done only if we can understand what exactly you want for each such check boxe. Should it make all the other check boxes False, it is true, and also change THE SAME RANGE ("AW4")? If so, based on what to make it 1 or 0? Commented Sep 19, 2023 at 8:41
  • 2
    You really have 414 checkboxes on a sheet. I would cry "Havoc" as a user. I pretty sure that is the wrong approach. Apart from that you can create a kind of control arrays for these controls even in VBA so that you do not have to implement a click event for each and every control. Commented Sep 19, 2023 at 8:43
  • bettersolutions.com/excel/macros/vba-control-arrays.htm -- stackoverflow.com/a/71486541/6600940 Commented Sep 19, 2023 at 8:49
  • @FaneDuru the first 6 checkboxes fill effect AW4 the next 6 will effect AW5 and so on, if cb1 is true then aw4=0 if cb2 is true then aw4=1 if cb3 is true then aw4=2 if cb4 is true then aw4=3 if cb5 is true then aw4=4 if cb6 is true then aw4=5 and obviously I only want 1 checkbox to be active at a time so when a check box is activated it needs to make the other 5 checkboxes that it is linked to false Commented Sep 19, 2023 at 8:50
  • @Storax yeah you are probably correct, unfortunately the article that you posted went right over my head and I also don't understand what a custom class is either (I am a self taught beginner). I will see if I can find anything online about what that is and see if the article makes sense after that, thanks for taking the time. Commented Sep 19, 2023 at 9:07

2 Answers 2

1

Please, use the next approach:

  1. Insert a class module and name it ChkBClass. Then, paste the next code in it:
Option Explicit

Public WithEvents cBEvent As MSForms.CheckBox

Private Sub cBEvent_Click()
    Dim ws As Worksheet, cbNo As Long, arrGr, i As Long
    
    Set ws = cBEvent.Parent 'the sheets where the clicked check box belongs
    cbNo = Mid(cBEvent.name, 3) 'the numeric part of the clicked check box
    
    arrGr = WhichGroup(cbNo) 'the array of the group elements where the clicked check box belongs
    
    Debug.Print Join(arrGr(0), "|") 'only to visually see that it is correct...
    If cBEvent.value = True Then  'only if the clicked text box became true:
        Application.EnableEvents = False 'to avoit the other check boxes being unchecked to trigger events
        For i = LBound(arrGr(0)) To UBound(arrGr(0))
            If arrGr(0)(i) <> cbNo Then 'all check boxes from the group, except this owne will be unticked:
                ws.OLEObjects("CB" & arrGr(0)(i)).Object.value = False
            End If
        Next i
        'write the correct specfic number in correct AW row:
        ws.Range(retAddress).Offset(arrGr(1) - 1).value = Application.match(cbNo, arrGr(0), 0) - 1
        Application.EnableEvents = True
    End If
End Sub
  1. Declare the next variables on top of a standard module (in the declarations area):
Private chkBArr() As New ChkBClass
Private arrGroups
Public Const retAddress As String = "AW4"

To rename all check boxes on the pattern you defined, please copy the next code in the same standard module as the above declarations (only to be all the staff in the same area...):

Sub renameChkBoxes()
  Dim olObj As OLEObject, ws As Worksheet
  
  Set ws = ActiveSheet
  For Each olObj In ws.OLEObjects
    If TypeName(olObj.Object) = "CheckBox" Then
        If Len(olObj.name) >= 9 Then
            olObj.name = "CB" & Mid(olObj.name, 9)
            olObj.Object.Caption = olObj.name
        End If
    End If
  Next
End Sub

It will rename all check boxes having the name using the pattern "CheckBox###", where the numeric part (###) should be in the interval 1 to 414.

If there are some other check boxes you want to use in a different scope, the above code can be adapted to exclude them.

Run the above code and see the result. Take care, that in the next steps the code will place in an array all the intervals of 6 such check boxes. As 1-6, 7-12 and so on. If the total number of check boxes will not be multiple of six, some problems may appear... The code does not check this aspect, so you must do it.

  1. Now the part which allocate a similar event to all check boxes in discussion:

Please, copy the next code in the same standard module where you declared the variables (issue 2):

Sub AssignChkBoxClickEvent()
  Dim ws As Worksheet, k As Long, oObj As OLEObject
  
  Set ws = ActiveSheet 'use here your necessary sheet
                       'Worksheets("your worksheet name")
  ReDim chkBArr(ws.Shapes.count) 'maximum shapes to be processed
  
  For Each oObj In ws.OLEObjects
    If TypeName(oObj.Object) = "CheckBox" Then
        'exclude check boxes you need to be excluded from this common event (if the case):
        If (oObj.name <> "CheckBox_x") And (oObj.name <> "CheckBox_Y") Then
            Set chkBArr(k).cBEvent = oObj.Object: k = k + 1 'place the check box object in the class array!
        End If
    End If
   Next
   ReDim Preserve chkBArr(k - 1) 'keep only the above processed check boxes...
End Sub

It assigns the class click event to all click boxes. Run it (for testing reason)!

This Sub should be called from Workbook_Open event, when the respective workbook is open!

Now, copy the rest of code (in the same standard module). Fist Sub load in an array all possible groups of 6 check boxes and the Function is called from the class, determining the group where from the clicked check box belongs:

Sub loadArrGroups()
    Dim nrChkBoxes As Long, i As Long, iStart As Long
    nrChkBoxes = 414
    iStart = 1
    ReDim arrGroups(nrChkBoxes / 6 - 1)
    For i = 0 To UBound(arrGroups)
        arrGroups(i) = iStart & ":" & iStart + 5
        iStart = iStart + 6
    Next i
    'Debug.Print Join(arrGroups, "|") 'uncomment to visually see its return
End Sub
Function WhichGroup(chkbNo As Long) As Variant
  If IsEmpty(arrGroups) Then loadArrGroups
  Dim El, arr, mtch, i As Long
  For Each El In arrGroups
    i = i + 1
    arr = Evaluate("ROW(" & El & ")")
    mtch = Application.match(chkbNo, arr, 0)
    If Not IsError(mtch) Then
        WhichGroup = Array(Application.Transpose(arr), i)
        Exit Function
    End If
  Next El
End Function

As I said above, the main sub assigning all check boxes to the common Click event is good to be called from the Workbook Open event (in ThisWorkbook code module) as:

Private Sub Workbook_Open()
  AssignChkBoxClickEvent
End Sub

Now run the above Sub manually and start playing with check boxes. Next time you will open the workbook the assignation will be done automatically.

I tried commenting all code lines which you may not understand them. If something still unclear and you like understanding, do not hesitate to ask for clarifications...

I tested the above solution and it works as it should. But until I finished posting here the code I observed that I forgot about writing in "AW" column and adapted the code in parallel with posting here. I think I did not miss anything, but working in such a way I cannot be sure. Anyhow the testing project in my workbook works as it should...

Sign up to request clarification or add additional context in comments.

14 Comments

so i have just implemented your code and then closed the sheet and re opened it and it works for the first three groups of 6 perfectly but when i click any button on a group after the first 3 it breaks and gives a type mismatch and then highlights this line of code Debug.Print Join(arrGr(0), "|") 'only to visually see that it is correct...
That could be a VBA-bug, Did you leave a breakpoint active when you closed excel?
@hennep I don't think so? I closed excel because after I implemented the code the buttons weren't working so I figured id close the sheet and re open to get it to reinitialise and then when I did that the first three rows of buttons started working but after I click on a button on row after the first three it throws up the error and then it stops the first three rows from working as well
btw when I saw button I mean checkbox fyi in both of my comments @hennep
I was triggered by "reopening the file and a code line was highlighted". That often happened to me. In your case there was a real error, a type mismatch.
|
0

The (form controls) checkboxes are in the Shapes collection:

    Dim i As Integer
    With Application.ActiveSheet.Shapes
         For i = 1 To .Count
             If Left(.Item(i).Name, 9) = "Check Box" Then
                Debug.Print .Item(i).Name
             End If
         Next i
    End With

You can rename these in the same loop but I would also change the Left and Top property to order them on the sheet on the NewIndex number:

    Dim i As Integer, NewIndex As Integer
    NewIndex = 1
    With Application.ActiveSheet.Shapes
         For i = 1 To .Count
             If Left(.Item(i).Name, 9) = "Check Box" Then
                Debug.Print .Item(i).Name
                .Item(i).Name = "CB" & NewIndex
                NewIndex = NewIndex + 1
             End If
         Next i
    End With

ADDITION:

Sub RenameChkBox()
    Dim i As Integer, NewIndex As Integer, NewLeft As Integer, NewTop As Integer
    NewIndex = 1
    With Application.ActiveSheet.Shapes
         For i = 1 To .Count
             NewTop = (((i - 2) Mod 10)) * 20 + 10
             NewLeft = (i - (((i - 2) Mod 10))) * 10 + 10
             If Left(.Item(i).Name, 9) = "Check Box" Or Left(.Item(i).Name, 2) = "CB" Then
                Debug.Print .Item(i).Name
                .Item(i).Name = "CB" & NewIndex
                .Item(i).DrawingObject.Caption = "CB" & NewIndex
                .Item(i).Top = NewTop
                .Item(i).Left = NewLeft
                NewIndex = NewIndex + 1
             End If
         Next i
    End With
End Sub

10 Comments

hi I am trying to implement these, but I am unsure of how, do I just run them in a module? or should I run them in the sheet? and when you say change the left and top property what does that mean? should I already have the checkboxes made or should I delete them all and re add them? (sorry I am a beginner still so some things go over my head)
I assumed you already had a sheet with 414 check boxes. In that case you need to run the code above only once, just put in in a sub and run it from the immediate pane. @Storax mentioned the click events, Do you want to add a click event to every check box or do you read the state of the boxes with a similar loop?
yes I do have the sheet with all the checkboxes on already, but when I run them it doesn't re name the checkboxes I assume I am doing something wrong, I have pasted the second bit of code you have posted in module 4 on my sheet and then I have gone to the sheet with the boxes on and ran the code from the macros menu but when I use the properties function to check the name it still says checkbox1.
Have look at the addition. You can run that multiple times. It will also set the caption, and that is what you see, not the name of the control.
In the addition I did a quick and dirty calculation of the new position. You can place them any way you want. But this way the index number in the name is synchronous with the position on the screen
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.