Excel Vba click radio button with application.caller - vba

I have a macro which run function (clear each named range depend ot application.caller.name) if radio button was clicked
Sub Clear_Click()
Dim s, f, arr
s = ActiveSheet.Shapes(Application.Caller).Name
arr = Array("NamedArray1", "NamedArray2", "NamedArray3", "NamedArray4")
Select Case s
Case "Clear7"
For i = LBound(arr) To UBound(arr)
ThisWorkbook.Worksheets("info").Range(arr(i)).value = ""
Next i
Case Else
f = arr(Right(s, 1) - 1)
ThisWorkbook.Worksheets("info").Range(f).value = ""
End Select
End Sub
It works ok.
Now i need to click Clear7 radio button from other function
So if i do
Sub test()
Application.Run ActiveSheet.Shapes("Clear7").OnAction
End Sub
I got error on s = ActiveSheet.Shapes(Application.Caller).Name as there are no Application.Caller i think.
So how to click radio button from other function?

If you're using Application.Caller but you want to run the code without someone needing to click the button then here's how you can do it.
NOTE: since Clear_Click has an argument, it won't show up in the "assign macro" list when attaching it to a button, but you can type its name directly in the box and that will work fine.
Sub Clear_Click(Optional callerName As String = "")
Dim s, f, arr, cn As String, i
Dim sht As Worksheet
cn = IIf(Len(callerName) > 0, callerName, Application.Caller)
'Debug.Print cn
Set sht = ThisWorkbook.Worksheets("info")
arr = Array("NamedArray1", "NamedArray2", "NamedArray3", "NamedArray4")
Select Case cn
Case "Clear7"
For i = LBound(arr) To UBound(arr)
sht.Range(arr(i)).Value = ""
Next i
Case Else
f = arr(Right(s, 1) - 1)
sht.Range(f).Value = ""
End Select
End Sub
Sub test()
ClickIt "Clear7"
End Sub
'run a macro attached to a shape and pass its name as a parameter
Sub ClickIt(sName As String)
Application.Run ActiveSheet.Shapes(sName).OnAction, sName
End Sub

Related

How to replace simplify code when calling command bar combobox

I have this code in a class module
Public WithEvents evtHandler As VBIDE.CommandBarEvents
Private Sub evtHandler_Click(ByVal CommandBarControl As Object, _
handled As Boolean, CancelDefault As Boolean)
On Error Resume Next
Application.Run CommandBarControl.OnAction
handled = True
CancelDefault = True
End Sub
I have this code in a module
Sub CommandBarComboBox_Create()
Dim cmdBar As commandBar: Set cmdBar = Application.VBE.CommandBars("Custom")
Dim arr As Variant: arr = Array("item_1", "item_2", "item_3")
Dim i As Byte
Dim newCtrl As CommandBarControl: Set newCtrl = cmdBar.Controls.Add(msoControlComboBox)
With newCtrl
.caption = "myList"
For i = LBound(arr) To UBound(arr)
.AddItem arr(i), i + 1
Next i
.OnAction = "'processSelection'"
.tag = "myTag"
End With
' Create event handler
Set MenuEvent = New VBE_cmdHandler
Set MenuEvent.evtHandler = Application.VBE.Events.CommandBarEvents(newCtrl)
EventHandlers.Add MenuEvent
End Sub
Sub processSelection()
Dim cmdBar As commandBar: Set cmdBar = Application.VBE.CommandBars("Custom")
Dim userChoice As Long: userChoice = cmdBar.Controls(2).ListIndex
Select Case userChoice
Case 1
Debug.Print "OPTION 1"
Case 2
Debug.Print "OPTION 2"
Case Else
Debug.Print "OPTION 3"
End Select
End Sub
This works just fine but I would like to change it, so when sub processSelection is called, it implicit knows the calling control, so I don't have to specify it.
How can it be done?
Regards
Elio Fernandes
I just found a way to solve my problem, using the tag property of the control.
I replaced the first 2 lines of code of the sub processSelecion with 3 new lines, but without the need to identify with command bar and which control was last used.
With tag property, I can find which control was last used and consequently which ListIndex item was selected by the user.
Sub processSelection()
Dim curTag$: curTag = Application.VBE.CommandBars.ActionControl.tag
Dim myControls As Object: Set myControls = Application.VBE.CommandBars.FindControls(tag:=curTag$)
Dim userChoice As Long: userChoice = myControls.item(1).ListIndex
Select Case userChoice
Case 1
Debug.Print "OPTION 1"
Case 2
Debug.Print "OPTION 2"
Case 3
Debug.Print "OPTION 3"
Case Else
Debug.Print "OTHER"
End Select
End Sub

Passing Values in VBA

In the code I am posting, I am using a check box called "ACDS Test" and whenever it is checked it creates a sheet, then when it becomes unchecked it calls the upper function and deletes the sheet.
I am trying to add a message box that essentially works like a fail safe to ensure they want to delete the page. If they say they do not want to delete the page then I want the checkbox to stay checked.
For some reason I am getting this error message when I try to pass the value to make sure the checkbox stays checked and I cannot figure out why.
The error comes up on the line:
Sub ACDSTest_Click(CorrectValue As Integer)
And the specific error is: "Compile error: Procedure Declaration does not match description of event or procedure having the same name".
Any help is much appreciated! IF any more clarification is needed please feel free to ask!
Sub DeleteWorksheet(NameSheet As String)
Dim Ans As Long
Dim t As String
Dim CorrectValue As Integer
Dim i As Long, k As Long
k = Sheets.Count
Ans = MsgBox("Would you like to take this test off of the form?", vbYesNo)
Select Case Ans
Case vbYes
'Code reads through each page and finds one with corresponding name to string t
'Once it finds the correct page, it deletes it
For i = k To 1 Step -1
t = Sheets(i).Name
If t = NameSheet Then
Sheets(i).Delete
End If
Next i
CorrectValue = 0
Case vbNo
CorrectValue = 1
End Select
End Sub
Sub ACDSTest_Click(CorrectValue As Integer)
Dim NameSheet As String
Dim NameValue As String
NameSheet = "ACDS"
NameValue = "ACDS Test"
If ACDSTest.Value = True Then
CreateWorksheet (NameSheet), (NameValue)
Worksheets("Sheet1").Activate
Else
DeleteWorksheet (NameSheet)
If CorrectValue = 1 Then
ActiveSheet.Shapes("ACDS Test").ControlFormat.Value = 1
End If
End If
End Sub
The issue here is that the CorrectValue variable as you define it in DeleteWorksheet does not exist in the context of the
variable does not exist in context of the ACDSTest_Click subroutine. This is because variables defined within subroutines or functions are local to those functions. To correct this I would convert DeleteWorksheet to a function such as the below.
Further, the event that fires Private Sub ACDSTest_Click() cannot handle passing a value to that function, so changing it to Sub ACDSTest_Click(CorrectValue As Integer) causes an error.
Function DeleteWorksheet(ByVal SheetName As String) As Boolean
On Error GoTo SheetDNE
SheetName = Sheets(SheetName).Name 'Check if sheet exists w/o other objects
On Error GoTo 0
Select Case MsgBox("Would you like to take this test off of the form?", vbYesNo)
Case vbYes
Application.DisplayAlerts = False
Sheets(SheetName).Delete
Application.DisplayAlerts = True
DeleteWorksheet = True
Case Else: DeleteWorksheet = False
End Select
Exit Function 'Exit The Function w/o error
SheetDNE: 'Sheet Does Not Exist
MsgBox "The indicated sheet, " & SheetName & ", does not exist", vbOKOnly
End Function
And
Private Sub ACDSTest_Click()
Dim NameSheet As String
Dim NameValue As String
NameSheet = "ACDS"
NameValue = "ACDS Test"
If ACDSTest.Value = True Then
CreateWorksheet (NameSheet), (NameValue)
Worksheets("Sheet1").Activate
Else
If Not DeleteWorksheet(NameSheet) Then _
ActiveSheet.Shapes("ACDS Test").ControlFormat.Value = 1
End If
End Sub

Setting a VBA form object using a string

Hello,
I am trying to set up a form which is a calendar from which the user can select a date (by default the current month appears). The form consists of 42 command buttons (I have left the default name ie. CommandButton1) which I am setting the day number.
At the moment I have a long-winded section of code for each button (I used Excel to generate this rather than type it all out) which locks and hides the button if it is outside of the month in question which looks like this:
NewDate.CommandButton1.Caption = Format(DATlngFirstMonth - DATintDayNumFirst + DATintX, "dd")
If DATintX < DATintDayNumFirst Then
With NewDate.CommandButton1
.Locked = True
.Visible = DATbooShowExtraDays
.ForeColor = RGB(150, 150, 150)
End With
Else
With NewDate.CommandButton1
.Locked = False
.Visible = True
.ForeColor = RGB(0, 0, 0)
End With
End If
I know that I can refer to a command button by:
Dim objCommandButton As Object
Set objCommandButton = NewDate.CommandButton1
..which neatens the code up somewhat. But what I would like to do is refer to the command button as a string so I can loop through all 42, ie.
Dim n as integer
n = 1
Do Until n > 42
Set objCommandButton = NewDate.CommandButton & n
'Some operations
n = n + 1
Loop
Many thanks in advance for assistance.
You can loop through all controls of the form. Try
Sub LoopButtons()
Dim it As Object
For Each it In NewDate.Controls
Debug.Print it.Name
Next it
End Sub
Then you can put conditional expression (if ... then) in place of Debug.Print or whatever. For example
If Instr(it.Name, "CommandButton") Then
'do your code
end if
Here's code which iterates over ActiveX controls on active sheet:
Sub IterateOverActiveXControlsByName()
Dim x As Integer
Dim oleObjs As OLEObjects
Dim ctrl As MSForms.CommandButton
Set oleObjs = ActiveSheet.OLEObjects
For x = 1 To 10
Set ctrl = oleObjs("CommandButton" & x).Object
Next
End Sub

drop down list combo box excel

I have a searchable combo box with suggestions to select from as I type letters in it (vba below). However i want to be able to click the arrow of the combo box (if i don't type anything else in it of course) and see the entire drop down list. For some reason the code below does not show me the entire list if I click the arrow.
Any suggestions much appreciated.
Dim ws As Worksheet
Dim x, dict
Dim i As Long
Dim str As String
Set ws = Sheets("Lists")
x = ws.Range("Listing").value
Set dict = CreateObject("Scripting.Dictionary")
str = Me.cbo1.value
If str <> "" Then
For i = 1 To UBound(x, 1)
If InStr(LCase(x(i, 1)), LCase(str)) > 0 Then
dict.Item(x(i, 1)) = ""
End If
Next i
Me.cbo1.List = dict.keys
Else
Me.cbo1.List = x
End If
Me.cbo1.DropDown
What you want is that if the arrow is clicked when nothing is yet selected or written in the combo by the user, to show all the items of the list, which you load from the named range "Listing" without any filtering.
To do so, add this event handler to your userform's code:
Private Sub Cbo1_DropButtonClick()
'If Len(Trim(cbo1.text)) = 0 Then
If Trim(cbo1.text) = "type here" Then
cbo1.List = Sheets("Lists").Range("Listing").Value
Exit Sub
End If
' Your code to add only items that match the characters typed by the user
' ...
End Sub

How to create a loop on e.g.,. TextBoxes' name placed within the Worksheet in Excel?

I have TextBoxes on UserForm and in Excel File (unfortunately).
I can do the loop on those in UserForm, and it works perfectly:
Dim txt(1 To 20) As String
txt(3)=("txtCompany")
txt(4)=("txtDataSource")
....
For i = 1 To 20
If frmInfo.Controls(txt(i)).Value <>
Worksheets(SheetNameDataBaze).Cells(ERow, i).Value Then ....
However, there is a huge problem with controls placed on the worksheet.
I tried:
Worksheets(SheetNameDataBaze).Controls(txt(i)).Value
Worksheets(SheetNameDataBaze).TextBox(txt(i)).Value
Worksheets(SheetNameDataBaze).OLEObjects(txt(i)).Value
Worksheets(SheetNameDataBaze).Shapes(txt(i)).Value
Worksheets(SheetNameDataBaze).txt(i).Value
nothing worked.
How should I define it?
It would be much easier then preparing the if statement for each TextBox.
I'm assuming that your textboxes on the worksheet are ActiveX controls and not forms controls. If so, then does this work for you?
Sub ReferToTextboxes()
Dim txt As MSForms.TextBox
Dim o As OLEObject
For Each o In Sheet1.OLEObjects
If o.progID = "Forms.TextBox.1" Then
Set txt = o.Object
'now you can refer to txt and do what you need
Debug.Print txt.Text
End If
Next o
End Sub
I finally used:
Private Sub FunctionalProgramNew()
Dim bLoop As Double
Dim eLoop As Double
bLoop = 8
eLoop = 13
Dim txt(8 To 13) As String
txt(8) = ("txtFuel_1")
txt(9) = ("txtFuel_2")
txt(10) = ("txtFuel_3")
txt(11) = ("txtProduct_1")
txt(12) = ("txtProduct_2")
txt(13) = ("txtProduct_3")
Dim txtBox(8 To 13) As MSForms.TextBox
For i = bLoop To eLoop
Set txtBox(i) = Worksheets(SheetNameModel).OLEObjects(txt(i)).Object
Next i
For i = bLoop To eLoop
If txtBox(i).Value <> CStr(Cells(ActiveCell.row, ActiveCell.Column + i - 2).Value) Then
MsgBox ("Error code: " & txt(i))
End If
Next i
End Sub