I'm newer to vba and need assistance. Currently, I have a drop-down list in a specific column (E1:E519) where staff can choose a check mark or leave it blank. However, if someone has 400 people or so to check boxes for, this can be annoying. So this prompted me to create a command button on the side using vba to select and deselect all in that specific column range.
How do I create a vba code that only allows checks to fill in the blanks in a selected range in cells that have a drop down list option (there is only 1 option in the drop down list, which is a check mark). The drop down list must remain for users who prefer to check each box individually and not use a command button. Column E either gets a check or is left blank. It'd be much easier if it recognized that if column B has data, then a check mark should be added to column E in the same row. If there is a code for that I would sure appreciate all the help I can get. The exact check mark I use is Arial Unicode MS font with a subset Dingbat character code 2713.
Can someone please help me and show me how to do it properly? I would also appreciate a bit of an explanation so that I can understand the code language and further learn. Thank you!
Current Code I'm Using (shows "?" instead of a check that is located in cell E14 (row 14, column 5) which is a check mark):
Private Sub CommandButton1_Click()
Dim c As Range
Dim check As Long
check = 0 'Define 0 for crossmark or 1 for checkmark
For Each c In Range("E17:E519") 'Define your range which should look value not equal to 1, then loop through that range.
If c <> 1 Then 'check if value in range is not equal to 1
With c 'Define what you want to do with variable c
If check = 1 Then 'If check = 1, then
.Font.Name = "Arial Unicode MS" 'Apply font "Arial Unicode MS"
.Font.Size = 12 'Font size
.FormulaR1C1 = "ü" 'special character for checkmark
ElseIf check = 0 Then 'If cehck = 1, then
.Font.Name = "Arial Unicode MS" 'Apply font "Arial Unicode MS"
.Font.Size = 12 'Font size
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeRight).LineStyle = xlContinuous
.FormulaR1C1 = "?"
End If
End With
End If
Next c
End Sub
Next code
Sub change_cells_ref2()
Dim ws As Worksheet
Dim c As Range
Dim c_row_number As Long
Dim rangeinput As Variant
Set ws = Worksheets("NFLES ILT Form") 'Define the worksheet the code should be applied to
Application.ScreenUpdating = False 'Turn off screen update, makes the calculations more smooth and faster.
Set rangeinput = Range("E17:E519") 'Set Range where you want to check if the variable c is empty. If you have headers, set "B2:B519"
For Each c In rangeinput 'This line defines your range where you are looking for "", then loop through that range.
c_row_number = c.Row 'Gives us the current row number for the loop variable c which we are looping.
If c <> "" Then 'Checks if the value in variable c is empty
ws.Cells(14, "E").Copy 'Copy from cell(14,5) where cells(row number, column number). This will copy row 14, column 5, which is cell E14
ws.Cells(c_row_number, "E").PasteSpecial xlPasteAll 'Paste into current row in loop and column 5 (column E)
End If 'End the if statement where we check which value variable c has.
Next c 'Go to next c in the range
Application.CutCopyMode = False 'Cancel any copy selection
Application.ScreenUpdating = True 'Turn off screen update
End Sub
The tricky part here is what kind of character you have used for crossmark/ticker. So I list two approaches, which the first one I have used earlier.
As I want it to be standardized in both macro and dropdown list I choose a character set in the cells B1
and B2
as dummy variables.
B1
= checkmarks (✓) = 1
and B2
= crossmarks (✗) = 0
. The great benefit is that I can use the same characters in my drop down-list (see picture) and the VBA code. Notice that both my cells, B1
and B2
has drop-down lists. When my code copy these cells, the drop-down list will follow to the new cells.
When I run the code I first need to choose 1
or 0
. What you choose depends if the code will copy checkmarks (which is value 1
) or crossmarks (value 0
).
Next window is where you define your range. You can either write it like: E20:E50
or you can select it by selecting with your mouse.
Then the code processes and the result will be changed cells:
VBA Code:
Sub change_cells_ref()
Dim c As Range
Dim check_or_cross As Variant
Dim c_row_number As Long
Dim rangeinput As Variant
check_or_cross = Application.InputBox("Enter ""1"" for checkmark or ""0"" for crossmark") 'Input box for checkmarks (enter: 1) or crossmarks (enter: 0)
On Error Resume Next 'If error occurs, this is not a good way to mask errors... but if you press cancel in the inputbox when you are setting a range, VBA automatically throws an error: 13 before we can catch it, so we mask any errors that can occurs.
Set rangeinput = Application.InputBox(prompt:="Select range or Enter range, i.e. E17:E150", Type:=8) ' Input box for Range, Type:=8 tells us that the value has to be in range format. You could either select or write range.
For Each c In rangeinput 'Range("E17:E150") - remove "rangeinput" to have a static range. This line defines your range where you are look for "zxyx", then loop through that range.
c_row_number = c.Row 'Gives us the current row for the loop variable c which we are looping.
If c <> "zxyz" Then 'Checks if the value is combination that is very unlikely to occur. It will overwrite all those values that are not "zxyz".
'If you replace the above code line with [If c = "" Then] the code would only overwrite cells that has not checkmark or crossmark...i,e only empty cells, could be good if you have some workers who answered, and some that hasn't. And only want to fill in those who didn't answer quickly.
With c 'Define what you want to do with the variable c
If check_or_cross = 1 Then 'If the user wrote 1, then copy checkmarks
.Font.Name = "Times New Roman" 'Set font that you want to use, remember all fonts doesn't support special characters/crossmark/checkmarks
.Font.Size = 12 'Set the Font size
Cells(1, 2).Copy 'Copy from cell(1,2) where cells(row number, column number). This will copy row 1, column 2, which is cell B1
Cells(c_row_number, 5).PasteSpecial xlPasteAll 'Paste into current row in loop and column 5 (column E)
ElseIf check_or_cross = 0 Then 'If the user wrote 0, then copy crossmarks
.Font.Name = "Times New Roman" 'Set font that you want to use, remember all fonts doesn't support special characters/crossmark/checkmarks
.Font.Size = 12 'Set the Font size
Cells(2, 2).Copy 'Copy from cell(2,2) where cells(row number, column number). This will copy row 2, column 2, which is cell B2
Cells(c_row_number, 5).PasteSpecial xlPasteAll 'Paste into current row in loop and column 5 (column E)
End If 'End the if statement (if check_or_cross is 1 or 0)
End With 'Close the With c part
End If 'End the if statement where we check which value c has.
Next c 'Go to next c in the range
On Error GoTo 0
End Sub
If you always want a static range and skip the input box for the range part, you could remove these 3 lines:
On Error Resume Next
Set rangeinput = Application.InputBox(prompt:="Select range or Enter range, i.e. E17:E150", Type:=8)
'...code....
On Error GoTo 0
And then replace this part
For Each c In rangeinput
-> For Each c In Range("E17:E517")
- where E17:E517
is your range that you want to change the check/crossmarks
Alternative approach:
This code uses the font size "Wingding".
The disadvantage here is that you are not able to use this style in a "good" way in drop-down list. You will have values "ü" = ✓ and for û = ✗. That means in the drop-down list you will have u's, but in macro it will show correct values when the result is presented.
Advantage is that you don't need any dummy cells, as code will not copy any cells. It writes the values directly from the code. If you have case where you only want to use macro and no drop-down list, this could be a perfect approach.
Sub change_cells()
Dim c As Range
Dim check As Long
check = 0 'Define 0 for crossmark or 1 for checkmark
For Each c In Range("E17:E150") 'Define your range which should look value not equal to 1, then loop through that range.
If c <> 1 Then 'check if value in range is not equal to 1
With c 'Define what you want to do with variable c
If check = 1 Then 'If cehck = 1, then
.Font.Name = "Wingdings" 'Apply font "Wingdings"
.Font.Size = 12 'Font size
.FormulaR1C1 = "ü" 'special character for checkmark
ElseIf check = 0 Then 'If cehck = 1, then
.Font.Name = "Wingdings" 'Apply font "Wingdings"
.Font.Size = 12 'Font size
.FormulaR1C1 = " û " 'special character for crossmark
End If
End With
End If
Next c
End Sub
Another light approach is shown in the result below:
The code will look if the cell in column B is not empty. If cell is not empty (formulas that returns: ""
are treated as empty) it will copy the value from dummy cell A1
and paste in the column E in the same row.
Notice to setup a dummy cell with data-validation and the checkmark ✓. The reason is that the character 2713 is a special character and in VBA it would have result in "?" character. Therefore we copy it in the excel environment where it can be treated correctly including the drop-down list
Variables to in the code set:
Worksheet name, pre-defined as: "Sheet1"
Range where to look for data: "B1:B519"
ws.Cells(1, "A").Copy
- cell where dummy variable is located ("A1").
ws.Cells(c_row_number, "E").PasteSpecial xlPasteAll
- Set column where checkmark should be pasted to.
VBA Code:
Sub change_cells_ref2()
Dim ws As Worksheet
Dim c As Range
Dim c_row_number As Long
Dim rangeinput As Variant
Set ws = Worksheets("Sheet1") 'Define the worksheet the code should be applied to
Application.ScreenUpdating = False 'Turn off screen update, makes the calculations more smooth and faster.
Set rangeinput = Range("B1:B519") 'Set Range where you want to check if the variable c is empty. If you have headers, set "B2:B519"
For Each c In rangeinput 'This line defines your range where you are looking for "", then loop through that range.
c_row_number = c.Row 'Gives us the current row number for the loop variable c which we are looping.
If c <> "" Then 'Checks if the value in variable c is empty
ws.Cells(1, "A").Copy 'Copy from cell(1,1) where cells(row number, column number). This will copy row 1, column 1, which is cell A1
ws.Cells(c_row_number, "E").PasteSpecial xlPasteAll 'Paste into current row in loop and column 5 (column E)
End If 'End the if statement where we check which value variable c has.
Next c 'Go to next c in the range
Application.CutCopyMode = False 'Cancel any copy selection
Application.ScreenUpdating = True 'Turn off screen update
End Sub