Get reference to Forms checkbox in VBA event handler - vba

I have some Forms Checkboxes in Excel 2010. I need to perform some common code when they are clicked. To do this, I'd like to pass a reference to the Checkbox, but so far I'm only able to get it typed as a shape.
To preempt the question, yes, they need to be Form Checkboxes and not ActiveX Checkboxes.
I'm a novice with VBA, so any help is appreciated.
Sub CheckBox1_Click()
'I really want this reference to be a Checkbox, not a Shape
Dim shape As Shape
Set shape = ActiveSheet.Shapes("Check Box 1")
DoSomething(shape)
End Sub
Sub DoSomething(MSForms.CheckBox)
'I need the reference to be a checkbox as I need to check
'whether it's checked or not here
End Sub

In such a scenario, don't have different click event for all checkboxes. Have just one. And use Application.Caller to get the name of the ckeckbox which called it. Pass that as a String to the relevant sub and then work with it.
UNTESTED
Sub CheckBoxMain_Click()
Dim sName As String
sName = Application.Caller
DoSomething (sName)
End Sub
Sub DoSomething(sCheck As String)
Dim shp As shape
Set shp = ActiveSheet.Shapes(sCheck)
With shp
'~~> Do something
End With
End Sub
You could also combine the two into one as well and link it with all checkboxes.
Sub DoSomething()
Dim shp As shape
Set shp = ActiveSheet.Shapes(Application.Caller)
With shp
'~~> Do something
End With
End Sub

This is similar to Siddharth's but adds the ControlFormat property of the Shape. ControlFormat gets you the Intellisense for the CheckBox, in this case Value:
Sub CheckBox1_Click()
Dim chk As Shape
Set chk = ActiveSheet.Shapes(Application.Caller)
With chk.ControlFormat
If .Value = True Then
MsgBox "true"
Else
MsgBox "false"
End If
End With
End Sub

Related

VBa to clear all activex checkboxes in Word document

I'm trying to create a button to clear all the activex check-boxes in a .docm file, but nothing seems to work. I saw many posts in the fórum, but none seems to work. Can anyone help me? Obs.: the original file have at least 30 check boxes and I don't want to type all the check-boxes names.
See the code below and the example file attached
Ps.: I tried ThisDocument.Fields; Me.Control and many others.
See attached image as example: ActiveX CheckBox
Private Sub CommandButton1_Click()
Dim Ctl As MSForms.Control
For Each Ctl In ThisDocument.FormFields
If Ctl.Name = "CheckBox" Then Ctl.Value = False
Next Ctl
End Sub
After many tests, the code below solved my problem:
Private Sub Limpar_Click()
Dim iShp As InlineShape
For Each iShp In ActiveDocument.InlineShapes
If iShp.OLEFormat.ClassType = "Forms.CheckBox.1" Then
iShp.OLEFormat.Object.Value = False
End If
Next
End Sub

Multiple ActiveX buttons visible/hidden

I have a Worksheet in excel 2013, with 25 activex buttons on it. depending on a cell value for each button, i would like it to be visible or hidden. In my case the value of cell U6 makes my commandbutton1 visible, U7 would make commandButton2 visible.... Only my CommandButton1 works properly. I have tried different combinations of code without succes.
Private Sub CommandButton1_Click()
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
'ActiveX button1
If Range("U6") = 1 Then
Sheets("Feuil1").CommandButton1.Visible = True
Else
Sheets("Feuil1").CommandButton1.Visible = False
End If
End Sub
If Range("U6") = 1 Then
Shouldn't that check if the Target (i.e. the modified cell) is in column U?
Sheets("Feuil1").CommandButton1.Visible = True
That road leads to pastaland, you don't want to go there: extract a method. You'll want to query the OLEObjects collections to get the ActiveX control by name, rather than hard-coding the button names 25+ times.
Private Sub SetControlVisibility(ByVal controlName As String, ByVal isVisible As Boolean)
Dim axControl As OLEObject
On Error Resume Next 'next statement may throw error #9
Set axControl = Me.OLEObjects(controlName)
If axControl Is Nothing Then Exit Sub
On Error GoTo 0 'restore error handling
axControl.Object.Visible = isVisible
End Sub
Now you have a method that can toggle the visibility of any ActiveX control on the sheet, given its name.
So in the Worksheet_Change handler, you now just need to work out the name of the ActiveX control, and whether or not you want it visible:
Private Sub Worksheet_Change(ByVal Target As Range)
'bail out if the modified cell isn't interesting, or if it's more than 1 cell:
If Intersect(Target, Me.Range("U6:U31") Is Nothing Or Target.Count <> 1 Then Exit Sub
Dim buttonName As String
buttonName = "CommandButton" & Target.Row - 5
Dim isVisible As Boolean
isVisible = Target.Value = 1
SetControlVisibility buttonName, isVisible
End Sub
Or something like it. Note: code written in the answer box, untested & for illustrative purposes only. Copy-pasta at your own risk.

Function to clear UserForms checkbox in VBA

I am creating a program which has several UserForms.
At the end of the program I need to clear every Checkbox inside some UserForm. I have created a Function, but it cannot recognise which UserForm it should clear, can you help me there? Here is the code:
Function ClearUserForm(ByVal userf As String)
Dim contr As Control
For Each contr In userf.Controls
If TypeName(contr) = "CheckBox" Then
contr.Value = False
End If
Next
End Function
And I am calling the function like this, for example:
ClearUserForm ("UserForm2")
It seems not to recognize which UserForm it should act upon.
Shai Rado's advice is good and you should have a look at how he creates the object from its 'key'.
I only post this answer to check if you're aware that you could pass the object itself in the call. So your code could be like so:
Option Explicit
Public Sub RunMe()
ClearCBoxes UserForm1
End Sub
Private Sub ClearCBoxes(frm As MSForms.UserForm)
Dim ctrl As Control
For Each ctrl In frm.Controls
If TypeOf ctrl Is MSForms.ComboBox Then
ctrl.Value = False
End If
Next
End Sub
You don't need a Function (since you are not returning any arguments), in your case a Sub will do.
You need to qualify an Object to the User_Form selected by using:
Set objUserForm = UserForms.Add(userf)
Whole code
(Tested)
Option Explicit
Sub ClearUserForm(ByVal userf As String)
Dim contr As Control
Dim objUserForm As Object
Set objUserForm = UserForms.Add(userf)
For Each contr In objUserForm.Controls
If TypeName(contr) = "CheckBox" Then
contr.Value = False
End If
Next
' just to check that all checkboxes are cleared
objUserForm.Show
End Sub

Self-referencing from inside an Excel VBA control

I'm trying to get a property value of a button control from inside the button's click event without using the button's name (since I want to use the same code for each of many buttons on the Excel sheet).
After much research, I see many references to try the following:
Me.ActiveControl.name
or
Me.Shapes(Application.Caller).Name
However, both of those throw an error when executed from within Excel. Note that I'm using Excel 2010.
Thanks for any help in advance.
Lee
What you want is possible but for that you need to create a Class
Do this.
Insert a Class Module and paste this code there.
Option Explicit
Public WithEvents MyButton As MSForms.CommandButton
Private Sub MyButton_Click()
MsgBox MyButton.Name
End Sub
Next Insert a module and place this code there
Dim shpButtons() As New Class1
Sub StartCode()
Dim shp As Shape
Dim btnCount As Long
ReDim shpButtons(1 To 1)
btnCount = 0
For Each shp In ActiveSheet.Shapes
If shp.OLEFormat.Object.OLEType = xlOLEControl Then
btnCount = btnCount + 1
ReDim Preserve shpButtons(1 To btnCount)
Set shpButtons(btnCount).MyButton = shp.OLEFormat.Object.Object
End If
Next
End Sub
Sub StopCode()
Dim iBtn As Long
On Error Resume Next
For iBtn = LBound(shpButtons) To UBound(shpButtons)
Set shpButtons(iBtn).TheText = Nothing
Next
End Sub
Now simply run the Sub StartCode()
Next when you click the ActiveX CommandButton then you will get it's name.
Try ActiveSheet.Shapes(Application.Caller).Name

Determine which button was pressed?

I'm wondering if there's a simple way for a Word macro to determine which button was just pressed? I have a document template with several button which should all fire a macro.
The thing is, I want to create ONE macro which is called in each button. I don't want tons of macros for each button.
Now, this macro, when the button is pressed, it inserts a picture and the size of this picture is selected based on the buttons size. Meaning, this ends up as a picture placeholder. But, I want to write the macro dynamically so that the same code will work on each button without doing more than just calling the macro.
The complete macro is already done, I just need to know this one last thing, if anyone has any info on how to accomplish this? :) Thanx in advance!
UPDATE: This is the code at the moment
Private Sub ImageButton1_Click()
PicturePlaceholder ImageButton1
End Sub
Private Sub ImageButton2_Click()
PicturePlaceholder ImageButton2
End Sub
Public Sub PicturePlaceholder(ByVal oButton As CommandButton)
Dim oShape As Word.Shape
Dim Dlg As Office.FileDialog
Dim strFilePath As String
Dim oDoc As Document
Dim rgePlace As Range
Dim buttonHeight As String
Dim buttonWidth As String
Set Dlg = Application.FileDialog(msoFileDialogFilePicker)
Set oDoc = ActiveDocument
Set rgePlace = Selection.Range.Fields(1) _
.Result.Paragraphs(1).Range
Response = MsgBox("Do you want to delete the button/Picture?", vbYesNoCancel, "Do you want an image here?")
If Response = vbYes Then rgePlace.Fields(1).Delete
If Response = vbCancel Then Exit Sub
If Response = vbNo Then
With Dlg
.AllowMultiSelect = False
If .Show() <> 0 Then
strFilePath = .SelectedItems(1)
End If
End With
If strFilePath = "" Then Exit Sub
Set oShape = oDoc.Shapes.AddPicture(FileName:=strFilePath, _
LinkToFile:=False, SaveWithDocument:=True, _
Anchor:=rgePlace)
With oShape
.Height = oButton.Height
.Width = oButton.Width
End With
rgePlace.Fields(1).Delete
End If
End Sub
OK, so they're CommandButtons in the document.
In that case, there's nothing you can do - you need to have handlers called Button1_Click, Button2_Click, etc. (or whatever the button names are).
However, you can do something like this:
Private Sub Button1_Click(...)
DoStuff Button1
End Sub
Private Sub Button2_Click(...)
DoStuff Button2
End Sub
Private Sub DoStuff(ByVal oButton As CommandButton)
' All your shared code goes here
MsgBox oButton.Caption
End Sub
See also this tech note for how to create your buttons in code.
EDIT: updated to pass CommandButton reference so that the shared function can access the button properties.
EDIT 2: updated to show complete code using InlineShapes. Note that this no longer passes in the Button object, since the width/height of the button can be obtained directly from the field.
Private Sub CommandButton1_Click()
PicturePlaceholder
End Sub
Private Sub CommandButton2_Click()
PicturePlaceholder
End Sub
Public Sub PicturePlaceholder()
' Get the selected field, which must be a button field
Dim oField As Field
Set oField = Selection.Fields(1)
Debug.Assert oField.Type = wdFieldOCX
' Ask the user what he wants to do
Select Case MsgBox("Do you want to delete the button/Picture?", vbYesNoCancel, "Do you want an image here?")
Case vbCancel
Exit Sub
Case vbYes
oField.Delete
Exit Sub
End Select
' Get the filename of the picture to be inserted
Dim strFilePath As String
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
If .Show() <> 0 Then
strFilePath = .SelectedItems(1)
End If
End With
If strFilePath = "" Then
Exit Sub
End If
' Figure out where to insert the picture, and what size to make it
Dim oRange As Range
Set oRange = oField.Result
Dim sglWidth As Single
sglWidth = oField.InlineShape.Width ' oButton.Width
Dim sglHeight As Single
sglHeight = oField.InlineShape.Height ' oButton.Height
' Delete the button field
oField.Delete
' Insert and resize the picture
Dim oInlineShape As Word.InlineShape
Set oInlineShape = oRange.InlineShapes.AddPicture(FileName:=strFilePath, LinkToFile:=False, SaveWithDocument:=True, Range:=oRange)
With oInlineShape
.Width = sglWidth
.Height = sglHeight
End With
End Sub
EDIT 3: Updated as requested to use Shapes rather than InlineShapes. (Both the CommandButton and the inserted Picture are now Shapes).
Private Sub CommandButton1_Click()
PicturePlaceholder
End Sub
Private Sub CommandButton2_Click()
PicturePlaceholder
End Sub
Public Sub PicturePlaceholder()
' Get the selected shape, which must be a button shape
Debug.Assert Selection.Type = wdSelectionShape
Dim oButtonShape As Shape
Set oButtonShape = Selection.ShapeRange(1)
' Ask the user what he wants to do
Select Case MsgBox("Do you want to delete the button/Picture?", vbYesNoCancel, "Do you want an image here?")
Case vbCancel
Exit Sub
Case vbYes
oButtonShape.Delete
Exit Sub
End Select
' Get the filename of the picture to be inserted
Dim strFilePath As String
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
If .Show() <> 0 Then
strFilePath = .SelectedItems(1)
End If
End With
If strFilePath = "" Then
Exit Sub
End If
' Insert the picture at the same size/position
Dim oPictureShape As Shape
Set oPictureShape = ActiveDocument.Shapes.AddPicture _
( _
FileName:=strFilePath, _
LinkToFile:=False, _
SaveWithDocument:=True, _
Left:=oButtonShape.Left, _
Top:=oButtonShape.Top, _
Width:=oButtonShape.Width, _
Height:=oButtonShape.Height, _
Anchor:=oButtonShape.Anchor _
)
' Copy across the button shape formatting
oButtonShape.PickUp
oPictureShape.Apply
' Copy across other layout details
oPictureShape.LayoutInCell = oButtonShape.LayoutInCell
oPictureShape.LockAnchor = oButtonShape.LockAnchor
oPictureShape.RelativeHorizontalPosition = oButtonShape.RelativeHorizontalPosition
oPictureShape.RelativeVerticalPosition = oButtonShape.RelativeVerticalPosition
oPictureShape.WrapFormat.Type = oButtonShape.WrapFormat.Type
oPictureShape.WrapFormat.Side = oButtonShape.WrapFormat.Side
oPictureShape.WrapFormat.DistanceTop = oButtonShape.WrapFormat.DistanceTop
oPictureShape.WrapFormat.DistanceLeft = oButtonShape.WrapFormat.DistanceLeft
oPictureShape.WrapFormat.DistanceBottom = oButtonShape.WrapFormat.DistanceBottom
oPictureShape.WrapFormat.DistanceRight = oButtonShape.WrapFormat.DistanceRight
oPictureShape.WrapFormat.AllowOverlap = oButtonShape.WrapFormat.AllowOverlap
' Delete the button shape
oButtonShape.Delete
End Sub
I assume you mean that the button is a Command Bar button (aka toolbar button).
If so, you can use Application.CommandBars.ActionControl to get a reference to the button that was clicked. From there you can examine the caption, tag, or whatever.
You could put your base macro into a separate sub and then just call the macro from each button's click event, passing as a parameter the desired size. Then the only code you would have in the buttons is the call to the base sub.
You can have a button in Vba to pass arguments when it calls the macro which takes arguments.
For eg: if you have a function called as function test(x as string)
then the button which calls the macro will have a syntax as onclick("sheetx!test", "whatever"). So that way you can either have a generic macro to be called. Hope this helps you.
Placing the following in the various click/got_focus/change events of ActiveX buttons and textboxes works for me:
MsgBox ThisDocument.ActiveWindow.Selection.Fields.Item(1).OLEFormat.Object.Name