I've added a button to an Excel file which, when clicked, reads a text file and populates a column with lines from a text file. I need to add a checkbox to cells adjacent to certain lines, depending on what the line contains.
Can I create components like checkboxes in code, and if so, how?
Any responses are appreciated.
While the link #Siva provided is certainly valid I just prefer to have an answer on StackOverflow instead of an external link. Hence, here is the solution you might be looking for:
Option Explicit
Public Sub tmpSO()
Dim i As Long
Dim chk As CheckBox
With ThisWorkbook.Worksheets(1)
.CheckBoxes.Delete
For i = 1 To .Cells(.Rows.Count, "A").End(xlUp).Row
If .Cells(i, "A").Value2 = "need checkbox" Then
Set chk = .CheckBoxes.Add(Left:=.Cells(i, "B").Left, Top:=.Cells(i, "B").Top, Width:=.Cells(i, "B").Width, Height:=10)
chk.OnAction = "runThisSub"
chk.Name = "CheckBowInRow" & i
chk.Caption = "CheckBowInRow" & i
End If
Next i
End With
End Sub
Sub runThisSub()
MsgBox "You clicked the checkbox " & Application.Caller _
& Chr(10) & "in cell " & ThisWorkbook.Worksheets(1).CheckBoxes(Application.Caller).TopLeftCell.Address
End Sub
Copy both subs into a Module into your Excel file and change in the first sub
the sheet where the text is imported to (here it is Worksheet(1)),
the column where the condition can be found (here column A), and also
what the condition is (here the value in column A must be need checkbox).
The code will now look through all cells in column A in sheet Worksheet(1) and check if the value is need checkbox. If so, the code will automatically add a checkbox into column B adjacent to that cell.
If you click on any of the newly created checkboxes then the second sub fires up and will show you in a message box which checkbox in which row has been clicked.
Related
I have a table with checkboxes in certain columns (see sample table)-- they are linked to their cells and also move/size with the cells. I also added text box "headings" throughout the table so visually when you filter for checked boxes, you see under which heading the checked item is in (I know I could create a separate column for that, but it works if I add text to the cells underneath the heading that I keep checked when filtering).
I want to be able to add rows at the end of each section, or before the next heading, since the formatting changes slightly in each section. However, I also want to add the checkboxes, and my code currently doesn't do that. It's okay if they're not linked to the new cell-- I have another macro I can run to do that.
Here's what my code would look like in the sample table:
Sub Add_Row_Pepperoni()
Rows(7).Insert , xlFormatFromLeftOrAbove
End Sub
Sub Add_Row_Pineapple()
Rows(13).Insert , xlFormatFromLeftOrAbove
End Sub
And I would like to add "Next" to "Call" this code:
Sub Link_CheckBoxes()
Dim chk As CheckBox
Dim lCol As Long
lCol = 0 'number of columns to the right for link
For Each chk In ActiveSheet.CheckBoxes
With chk
.LinkedCell = _
.TopLeftCell.Offset(0, lCol).Address
End With
Next chk
End Sub
My other concern is the row I'm referencing (here rows 7 and 13) will change every time I add a row above it (I'll no longer be referencing the "header" row). Any tips?
Here's the scenario. When a row is inserted in the worksheet there's a worksheet_change event that calls a sub that inserts five pairs of buttons on the row that was inserted. When one of those buttons is clicked it runs a sub that issues a MsgBox that displays the TopLeftCell.Row and Column of the button. Multiple rows can be inserted, each with its five sets of buttons (ten in total). Any button in any row can be selected at any time.
What I'm seeing is that after I open the workbook and press one of the buttons, the MsgBox always displays the correct column, but it seems to get "stuck” on one particular row no matter which row the button that I'm clicking is actually in. If I delete the row it is stuck on then it gets "stuck" on a different row (as long as it also contains buttons). But not all of the buttons will be stuck to the same row.
If I copy two adjacent rows with buttons that are “stuck” on the same row to another location, those buttons are still stuck together except on a different row.
It seems like there’s a problem with the button collection. If I save the workbook the problem goes away. If I insert a new row and the Add_Buttons routine runs again, the problem reappears but involving different rows. So my button routine is probably leaving something temporary behind that gets cleared up when I do a save.
Here's the code that builds the buttons.
Public activeWS As Worksheet
Public activeRG As Range
Public Sub Add_Buttons(ByVal myRow As Long)
'Add the five sets of Submit IM and Submit Webins buttons to a new row. The code
'uses named ranges to locate the cells where the buttons should be added so that
'new columns can be added to the spreadsheet without requiring changes to the code.
'The headings must be labeled 'IM#' and 'Webins#'.
Dim i As Long
Dim t As Range
Dim btn As Button
'In each range, place the button below the column label.
Application.ScreenUpdating = False
For i = 1 To 5
Set activeWS = Sheet1
Set activeRG = activeWS.Range("Scan" & i & "_Hdngs")
'The start of the range plus the position of the specified column in
'the range gives the absolute column location to add the button
'Create the Submit IM button
nCol = activeRG.Cells(1, 1).Column + findCol("IM#", activeRG) - 1
Set t = activeWS.Range(Cells(myRow, nCol), Cells(myRow, nCol))
Set btn = activeWS.Buttons.Add(t.Left, t.Top, t.Width, t.Height)
With btn
.OnAction = "Create_Primary_IM"
.Caption = "Submit IM"
.Name = "BtnIM" & myRow & i
.Font.Size = 10
End With
'Create the Submit Webins button
nCol = activeRG.Cells(1, 1).Column + findCol("Webins#", activeRG) - 1
Set t = activeWS.Range(Cells(myRow, nCol), Cells(myRow, nCol))
Set btn = activeWS.Buttons.Add(t.Left, t.Top, t.Width, t.Height)
With btn
.OnAction = "Create_Primary_WAS"
.Caption = "Submit Webins"
.Name = "BtnWAS" & myRow & i
.Font.Size = 10
End With
Next i
Application.ScreenUpdating = True
End Sub
Here's the code executed by the buttons:
Public Sub Create_Primary_IM()
MsgBox ("Row, Col of pressed button: " & ActiveSheet.Shapes(Application.Caller).TopLeftCell.Row _
& ", " & ActiveSheet.Shapes(Application.Caller).TopLeftCell.Column)
End Sub
Public Sub Create_Primary_WAS()
MsgBox ("Row, Col of pressed button: " & ActiveSheet.Shapes(Application.Caller).TopLeftCell.Row _
& ", " & ActiveSheet.Shapes(Application.Caller).TopLeftCell.Column)
End Sub
Here's what I believe to be the cause of the problem, its effect on the spreadsheet, and the solution.
The cause was duplicate button names. I had been naming the buttons based on their row and column at the time of creation. The problem is that rows and their buttons could be inserted or deleted anywhere in the sheet. It's not hard to see (except that I didn't see it for a while) that it was possible to insert a row and create its buttons in the same absolute row multiple times. This resulted in buttons with the same .name property.
The effect was that when I clicked one of the duplicate buttons it found the TopLeftCell.Row of the original button with that name, not of the row that the button was actually on. When I saved the file (not closed it) and clicked the same button, it had been renamed to something like 'Button nnn' and the correct row was returned. If I saved the file and re-opened it, the duplicate button name condition was still present. So Excel was replacing duplicate names in that collection when I saved the file, but not committing those changes when I closed the file.
The quickest solution was the easiest as well. I let Excel do the naming. I don't really need the buttons to have names. All I need is the row number. Another solution would be to generate a unique name, but what's the point if that's what Excel is going to do for me anyway?
I have input a combobox in an Excel sheet. I want it to work so that the user who does not have access to the VBA can select a value from the dropdown and then the value in another cell will perform a vlookup on this value.
In the first instance I have inserted a box and am trying to set a cell value based on this.
Sub InsertComboBox()
#inserts dropdown box on the front page and sets the values as the list of DMA from the pipe_totals sheet
#this should be the most complete list so will not change dependant on asset
Dim arearange As Range
Set arearange = Sheets("pipe_totals").Range("a:a")
lastrowi = Application.WorksheetFunction.CountA(arearange)
Sheets("front page").Activate
With Range("f5:g5")
Set Combo = ActiveSheet.DropDowns.Add(.Left, .Top, .Width, .Height)
End With
Combo.List() = Sheets("pipe_totals").Range("A2:A" & lastrowi).Value
.Range("k9").Value = Combo.Value 'only works on current combobox value which is 0
End Sub
Is there a way I can set this so the vlookup is dynamic depending on the users selection?
In this example, just set the right combo name. It should be ok, provided that your combobox lists values from "Range("A2:A" & lastrowi)" as you mention above.
Sub "comboname"_Change()
Dim list_val As Long
list_val = Worksheets("front page").Shapes("comboname").ControlFormat.Value
Range("K9") = Worksheets("pipe_totals").Cells((list_val + 1), 1)
End Sub
Sub test()
Dim z As Shape
For Each z In Worksheets("front page").Shapes
Debug.Print z.Name
Next z
End Sub
As far as I understand, you want that everytime the combobox value changes, cell K9 will have the same value also. Is that right? If this the case, then right click on the combobox and select "Assign Macro". Then select "Create". Then inside the sub created, which should look like this:
Sub "comboname"_Change()
End Sub
You should also paste the final code line.
.Range("k9").Value = Combo.Value
Doing so, means you want that line of code executed every time the combobox value changes.
I am using a userform with multiple checkboxes in it. My goal is to have all checkboxes return their values (unique two letter acronyms) to a single cell. I am not sure how to accomplish this. I have no VBA experience prior to today.
You can record a macro to get your other relevant code for VBA but this should help:
Range("A" & LastRow).Value = CheckBox1.Value & CheckBox2.Value & CheckBox3.Value 'etc.
'Concatenate CheckBox values with "&" (the values will be True or False though)
Set linkcell of each checkbox to a different cell -.e.g. checkbox1 to cell A1, checkbox2 to cell A2, etc
For each link cell, use If formula in its adjacent cell to test the link cell's content and return a string or a blank,
e.g. if(A1=True,"AA","") in cell B1, if(A2=True,"BB","") in cell B2, etc
Finally, concatenate results of 'if' Formulas in another cell: e.g. B1&","&B2&","&B3, using comma as separaters
To do this, you can make a collection of all of the Checkboxes in the form. Heres my code:
Private mcolCHK As Collection 'This creates a modular level collection, which will keep track of all of the checkboxes
Private Sub cmdOK_Click()
Dim objA As Object, strResults As String, i As Integer
i = 1
For Each objA In mcolCHK
strResults = strResults & i & Left(objA.Value, 1)
i = 1 + i
Next
Unload frmTestForm 'rename this the name of your form
MsgBox strResults
'instead of using a message box, you can say "strResults = Sheets(sheet1).range("A1").value
'This part may be customized as needed
End Sub
Private Sub UserForm_Initialize()
Set mcolCHK = New Collection
mcolCHK.Add chkAtt1 'you will have to add one of these for each checkbox (simply replace "chkAtt1" with the name of your first checkbox
mcolCHK.Add chkAtt2 'and repeat for each checkbox
End Sub
Checkboxes always give a value of True or False. with this method, you will get the number of the checkbox (in order of how you added them to the collection in the UserForm_Initialize() sub) and the first letter of the result (T or F). When i ran this, I had two checkboxes, and checked each one when the form ran. This gave me a result of "1T2T". This can be changed as needed. All you really need is how this all works. just make sure to change all the names to match the names of the variables you used.
This question already has answers here:
Get corresponding Range for Button interface object
(3 answers)
Closed 3 years ago.
I am trying to make a button in Excel which copies a certain range of cells from the active workbook to another workbook. The copying of this range works perfectly when I specify a fixed range, but I am stumped on how to figure out the row of the clicked button.
Every row contains 7 or so cells, and the 8th cell contains a shape with a macro attached to it (the button).
When the user presses this button the 7 cells on the same row as the row containing the pressed button need to be copied.
Using ActiveCell is of no use, since pressing the button doesn't actually set that cell as active. I searched around a lot but I can't seem to find how to obtain this value.
Once I have the row number of the clicked button I can figure the rest out on my own.
Each Shape has TopLeftCell property. It contains a cell within which the top left corner of the shape resides.
Try this:
Sub Mainscoresheet()
' Mainlineup Macro
Dim b As Object, cs As Integer
Set b = ActiveSheet.Buttons(Application.Caller)
With b.TopLeftCell
cs = .Column
End With
MsgBox "Column Number " & cs
End Sub
Excellent answer. Btw It also works for Rownumber!
'Same for rownumbers!
Sub Mainscoresheet()
' Mainlineup Macro
Dim b As Object, RowNumber As Integer
Set b = ActiveSheet.Buttons(Application.Caller)
With b.TopLeftCell
RowNumber = .Row
End With
MsgBox "Row Number " & RowNumber
End Sub
This works too! Selects the cell that the generated button resides in (knew it was in column "K" but that could be calculated too!.
ActiveSheet.Range("K" & ActiveSheet.Buttons(Application.Caller).TopLeftCell.Row).Select