Disable button using Excel VBA - excel

I want to disable a button with VBA code like this:
ActiveSheet.Shapes("Button 1").ControlFormat.Enabled = False
I tried:
Set b1 = ActiveSheet.Buttons("Button 1")
b1.Enabled = False
And:
Me.Shapes("Button 1").ControlFormat.Enabled = False
My button name is correct, because it doesn't give me an error message, so the code is completely run through.
After this script I can click on that button and the assigned macro runs. Nothing should happen when I click on it.

Disabling a Form button (not talking ActiveX here) does not prevent the assigned macro to run and does not gray out the button. The code below does exactly that based on the version got from Excel. If you did not assign a name to your Form button, you can also use (Buttons(1).
If Excel version = 16 or higher the button is "enabled" by making it black and assigning my macro, else the button is "disabled" by making it gray and assigning no action to it.
Code can e.g. reside in Private Sub Worksheet_Activate() within sheet "Test Sheet"
If Application.Version < 16 Then
Worksheets("Test Sheet").Buttons("button_name").Font.Color = 8421504
Worksheets("Test Sheet").Buttons("button_name").OnAction = ""
Else
Worksheets("Test Sheet").Buttons("button_name").Font.Color = 0
Worksheets("Test Sheet").Buttons("button_name").OnAction = "'Name of the workbook.xlsm'!my_macro_name"
End If

Probably you are using ActiveX Button. Try this:
Sheets("Sheet1").CommandButton1.Enabled = False '--->change sheet name as required
EDIT:
______________________________________________________________________________
For a Form control Button the following line
ActiveSheet.Shapes("Button 1").ControlFormat.Enabled = False
disables the button i.e. click event will no longer work but the appearance of the button does not change which gives an impression that the button is still active. So work around for that is to change the color of the text of the button as follows:
Sub disable_button_2()
Dim myshape As Shape: Set myshape = ThisWorkbook.Worksheets("Sheet1").Shapes("Button 2")
With myshape
.ControlFormat.Enabled = False '---> Disable the button
.TextFrame.Characters.Font.ColorIndex = 15 '---> Grey out button label
End With
End Sub
And to bring back button to its original state write:
Sub activate_button_2()
Dim myshape As Shape: Set myshape = ThisWorkbook.Worksheets("Sheet1").Shapes("Button 2")
With myshape
.ControlFormat.Enabled = True '---> Enable the button
.TextFrame.Characters.Font.ColorIndex = 1 '---> Highlight button label
End With
End Sub

I suggest to create a shadow button/shape with exactly same size/position, but different color (fill and/or text to your liking) and no macro/action attached. Then just change the .visible property of your primary shape. Visible = button is active; not visible button is e.g. grayed out and has no action/is passive.

Only tested on Excel 2016 x86
I continued to receive errors utilizing .ControlFormat. solutions.
After much searching I found another solution that worked great for my needs of disabling Shapes/Buttons.
To mimic the .Enabled property of a uf control, you might toggle the .OnAction property of a shape.
Function ShapeIsEnabled(aShape As Shape) As Boolean
ShapeIsEnabled = (aShape.OnAction <> "")
End Function
Sub EnableShapeMacro(aShape As Shape)
aShape.OnAction = aShape.AlternativeText
End Sub
Sub DisableShapeMacro(aShape As Shape)
aShape.AlternativeText = aShape.OnAction
aShape.OnAction = vbNullString
End Sub
Note the use of the .AlternativeText property to store the macro name.
source: mikerickson
https://www.excelforum.com/excel-programming-vba-macros/1267897-disable-action-of-macro-enabled-shape.html#post5080833

Related

Change caption of toggle button

I have two toggle buttons, each on a different sheet.
The code of the toggle button is stored on the sheet level:
Private Sub MoveButton_Click()
ClickToggleButton "move", ActiveSheet.Name
'ToggleButtonPressed sSHEET2NAME
End Sub
The ClickToggleButton function is stored on the module level (because I want to use the same function for both buttons).
In my case while clicking one toggle button, the other button on the other sheet must be pressed, this works out well:
'switch button state to the same over the 2 sheets
Select Case sheetName
Case sSHEET1NAME
Worksheets(sSHEET2NAME).OLEObjects(sBUTTONMOVENAME).Object.Value = Worksheets(sSHEET1NAME).OLEObjects(sBUTTONMOVENAME).Object.Value
Case sSHEET2NAME
Worksheets(sSHEET1NAME).OLEObjects(sBUTTONMOVENAME).Object.Value = Worksheets(sSHEET2NAME).OLEObjects(sBUTTONMOVENAME).Object.Value
End Select
Now I only need to change the text (caption) on both buttons depending on the value you are in, I got error 438 "Object doesn't support this property or method" on this line:
Worksheets(ActiveSheet.Name).OLEObjects(sBUTTONMOVENAME).Caption = sButtonDescription
I guess it has to do with the fact where my code was stored ? I can change the value of the object but can't change the caption.
Thanks for your help.
You set the caption of the button like you set the value - you need to use the Object-property of the OLEObject.
The OLEObject is just a wrapper around different kind of objects, while the Object-property is the button (or checkbox, or textbox or...) itself:
ActiveSheet.OLEObjects(sBUTTONMOVENAME).Object.Caption = sButtonDescription
You can also set other properties like Font, Color and the like:
With ActiveSheet.OLEObjects(sBUTTONMOVENAME).Objectws.OLEObjects(1).Object
.Font.Size = 14
.FontBold = True
.FontName = "Broadway"
.ForeColor = vbRed
.BackColor = vbYellow
End With

How to start macro with a left click NOT on a cell in excel?

I am trying since 2 days to find how to do the following without finding anything that suits the aim:
Steps by order :
user open excel file
he chose between folowing :
Paste an image directly in the worksheet (may be an limited area)
activate some video in the workbook (may be a webcam for start)
he select with a button to activate his clicks detection
he clicks anywhere on the picture and i get the coordinates of clicked points
So far i've seen ppl using (and tested myself) :
mouse event ==> this does not work as i need to know the name of what he is clicking on and it may be a brand new picture he just pasted
BeforeDoubleClick (same, i'd prefer avoid doubleclick but even then it doesnt work when i click on something else but cells)
Selectionchange ==> doesnt work if im not clicking on cells
Place hidden button over the area i want : i cant click a button if its not visible, and it becomes visible when i click it if i put as transparent
If anyone has ideas about this...
(nb: im not a pro of vba so i may have missed something)
Just forgot : my issue is not getting the coordinates of mouse, its just triggering the macro when i want, for now im jsut trying to get a simple msgbox to see if trigger works.
Thanks if anyone has any ideas
BR
Not sure if this fits your need (for example couldn't test it with a video).
a) Place a "button" of any kind on your sheet. I usually use a square shape for that and format it a little bit (color, shade, text). Assign the subroutine SetEvents to it.
b) Declare a global variable that remembers that click-activation is active
Option Explicit
Global EventCatchingActive As Boolean
c) In the event routine of your button, set the OnAction-method for all shapes of the sheet - see the routine setEvents. This ensures that even newly added images handle the click event.
Sub setEvents()
' This routine is called from the magic button.
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(1) ' Set this to whatever sheet you need
Dim button As Shape
Set button = ws.Shapes(Application.Caller)
If EventCatchingActive Then
EventCatchingActive = False
button.TextFrame2.TextRange.Characters.Text = "Start Clicking"
Else
Debug.Print "Setting EventHandler"
Dim sh As Shape
For Each sh In ThisWorkbook.Sheets(1).Shapes
' Debug.Print sh.Name, sh.Type
If sh.Name <> button.Name Then sh.OnAction = "ClickedMe"
Next
EventCatchingActive = True
button.TextFrame2.TextRange.Characters.Text = "Stop Clicking"
End If
End Sub
d) Declare a routine that is called if any of the shapes is clicked. With Application.Caller you can check what was clicked.
Sub ClickedMe(Optional target As Range = Nothing)
If Not EventCatchingActive Then Exit Sub
If target Is Nothing Then
Debug.Print "I clicked on " & Application.Caller
Else
Debug.Print "I clicked on cell " & target.Address
End If
End Sub
(note that code of steps b) to d) goes into a regular module)
e) If you also want to handle clicks on a cell, add the following into the sheet-module of the worksheet you are dealing with.
Private Sub Worksheet_SelectionChange(ByVal target As Range)
ClickedMe target
End Sub

Change the text in a button with conditions

I have a small piece of VBA code that allows me to expand and collapse rows by clicking a button (by assigning the Macro to the button):
Sub Expand()
Range("4:4").EntireRow.Hidden = Not (Range("4:4").EntireRow.Hidden)
Range("9:9").EntireRow.Hidden = Not (Range("9:9").EntireRow.Hidden)
End Sub
Currently, I have just manually typed in the text "EXPAND" onto the button, however I would like the text top dynamically change to say "COLLAPSE" when the rows are visible and "EXPAND" when the rows are hidden.
Thank you.
If you are using Form Controls Button then assign this macro (in regular/standard module) to the button
Edited as suggested by #KekuSemau in the comments on the question
Sub Macro1()
With ActiveSheet.Shapes("Button 1")
If .TextFrame.Characters.Text = "Expand" Then
.TextFrame.Characters.Text = "Collapse"
ActiveSheet.Range("4:4,9:9").EntireRow.Hidden = False
Else
.TextFrame.Characters.Text = "Expand"
ActiveSheet.Range("4:4,9:9").EntireRow.Hidden = True
End If
End With
End Sub
If you are using ActiveX Controls Command Button then Paste this macro in the relevant sheet VBA module. Make sure the button name is correct.
Private Sub CommandButton1_Click()
If CommandButton1.Caption = "Expand" Then
CommandButton1.Caption = "Collapse"
ActiveSheet.Range("4:4,9:9").EntireRow.Hidden = False
Else
CommandButton1.Caption = "Expand"
ActiveSheet.Range("4:4,9:9").EntireRow.Hidden = True
End If
End Sub

Drawing shapes to screen falling behind other code

I am trying to create a small tutorial for one of my Excel Applications and I am running into the issue where I'm trying to draw a text shape to the screen to give advice on what to enter into an InputBox but the InputBox gets displayed before the text shape, however, when running in debug mode and stepping through the code it all works fine.
There is one userform ufNext which only contains one button, ufNext. The click event code for this button contains a Select Case clause to determine what to do each time it is clicked. The value the clause is checking is a Public variable, tutSectionsRun
Option Explicit
Private Sub btnNext_Click()
Select Case tutSectionsRun
Case 1
Call Section2
Case 2
Call Section3
Call MPFilterString
' Case N
' ...
End Select
End Sub
The code starts in Section1 which just sets the position of ufNext and shows the form then sets the global variable tutSectionsRun to 1.
The user clicks the "Next" button on the ufNext form and it calls Section2 which re-positions the form (there would normally be other code in these "Section" procedures), and sets the global variable to 2.
Again, the user clicks the "Next" button but this time there is the issue where before the shapes are drawn to the screen, I get the InputBox popping up first and only after it closes the text shape tutText is drawn to the screen.
Option Explicit
Public tutSectionsRun As Long
Sub Section1()
ufNext.Left = 550
ufNext.Top = 450
ufNext.Show
tutSectionsRun = 1
End Sub
Sub Section2()
ufNext.Left = 910
ufNext.Top = 350
tutSectionsRun = 2
End Sub
Sub Section3()
Dim tutText As Shape
Set tutText = ActiveSheet.Shapes.AddLabel(msoTextOrientationHorizontal, 600, 300, 200, 100)
tutText.TextFrame2.TextRange.Text = "Enter the string ""gr"" into the input box."
tutText.Locked = False
ufNext.Hide
tutSectionsRun = 3
End Sub
Sub MPFilterString()
Dim s As Variant
Application.ScreenUpdating = False
s = Application.InputBox("Enter string to filter out.", "Filter String.")
If s = False Then Exit Sub
End Sub
**Edit : I forgot to mention that the userform is non-modal. Otherwise execution would pause on the call to ufNext.Show and clicking next would call the event handler before the tutSectionsRun variable had been set to 1
Thanks to #BrakNicku who confirmed my suspicions in the comments, saying that the InputBox was preventing the screen from being refreshed for the text shape from ActiveSheet.Shapes.AddLabel to be displayed.
Their link to this answer offered some suggestions.
What I found was that adding either of these before the InputBox was called would force the screen to refresh but only if Application.ScreenUpdating = False was removed, or at least just moved further down in the code.
- ActiveSheet.Calculate
- ActiveWindow.SmallScroll
- Application.WindowState = Application.WindowState
I always like to call Application.ScreenUpdating = False at the top of my procedures, so I went with a different approach, thinking that the problem was that the time to refresh the screen with shapes drawn was longer than the time between the instruction to do so and the instruction to draw the InputBox to screen. So, I thought a slight delay before calling the InputBox might be a better choice for me, probably not for everyone but I felt better about doing it this way. (Application.ScreenUpdating = False is a good friend of mine and I didn't want to see her go, or even be relocated) So I just made a small wait procedure.
Sub Wait(secs As Single)
Dim finishTime As Single
finishTime = Timer + secs
Do While Timer < finishTime
DoEvents
Loop
End Sub
And called it at the top of the MPFilterString procedure. It only takes about 50ms for the shapes to show on screen but I give it 100ms to be safe.
Sub MPFilterString()
Dim s As Variant
WaitFor (0.1)
Application.ScreenUpdating = False
s = Application.InputBox("Enter string to filter out.", "Filter String.")
If s = False Then Exit Sub
' more code ...
End Sub

General function to color applicable comboxes

I'm running some VBA code in Excel and I made a a combo box that will turn red and set the focus on it when there is no value entered.
If cmb = "" Then
cmb.BackColor = vbRed
lbl.ForeColor = vbRed
cmb.SetFocus
Exit Sub
Else
cmb.BackColor = vbWhite
lbl.ForeColor = vbBlack
End If
As I have many combo boxes on my form, I want to build a function or procedure that I can call for any combo box that I want.
Can anyone help?
Here's a general function that you can pass a ComboBox to:
Function ValidateComboBox(c As ComboBox) As Boolean
If Len(c.Text) = 0 Then
c.BackColor = vbRed
Controls(c.Tag).ForeColor = vbRed ' Set associated label color, also
c.SetFocus
ValidateComboBox = False
Else
c.BackColor = vbWhite
Controls(c.Tag).ForeColor = vbBlack ' Set associated label color, also
ValidateComboBox = True
End If
End Function
You call it like this, for example when the form is submitted:
' [OK] clicked. Submit form...
Private Sub cmdOK_Click()
If Not ValidateComboBox(ComboBox1) Then Exit Sub
If Not ValidateComboBox(ComboBox2) Then Exit Sub
If Not ValidateComboBox(ComboBox3) Then Exit Sub
...
End Sub
The tricky part is that you have a label that corresponds to each combo box that needs to be updated as well. You can either design the function to accept both a ComboBox control and a Label control and pass both each time, or you take advantage of the combo box's Tag property, as I've done above. For each combo box, just enter the name of the corresponding Label control into its Tag property using the Properties window in the designer.
For example, if ComboBox1 has a label named Label1, then enter "Label1" (without the quotes) into ComboBox1's Tag property. The routine above will look for the label/control with that name and set its color appropriately as well.

Resources