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
Related
I'm using excel and I'm having trouble, I need buttons that will change color when clicked. I can use a command button but it needs me to label each of them individual "CommandButton1, CommandButton2 ,CommandButton3 ...CommandButton1000." I will be using many of them and wanted to know what I should be doing so I could have one general macros program a can slap on a shape/command button. This program only needs to change the color back and forth when clicked. This is what I'm working with.
'Private Sub CommandButton_Click()
Select Case CommandButton1.BackColor
Case -2147483633 'Default Grey
col = 228 'FP Red
Case Else
col = -2147483633 'Default Grey
End Select
CommandButton1.BackColor = col
End Sub
I would recommend inserting a module into the workbook and write generic color changing code there. Then in the sheet with the buttons, simply call that code and pass the sub the button clicked. The module sub would look something like this:
Public Sub ColorChange(ByRef btn As Object)
Select Case btn.Name
Case "CommandButton1"
btn.BackColor = RGB(200, 0, 0)
Case "CommandButton2"
btn.BackColor = RGB(0, 200, 0)
Case "CommandButton3"
btn.BackColor = RGB(0, 0, 200)
Case "CommandButton4"
btn.BackColor = RGB(200, 0, 200)
End Select
End Sub 'ColorChange
The button click would look something like this:
Private Sub CommandButton1_Click()
Call ColorChange(Me.CommandButton1)
End Sub
You can put whatever changes you like depending on which button is clicked. Also, you can name the buttons whatever you want. Right click the button and go to properties and you can change the name. Typical naming convention for a button is to prefix the control with cmd or btn and a name. For example, btnColor1. But that's all up to you, of course.
P.S. Control arrays for large numbers of controls is probably a good idea. Check this out:
https://bettersolutions.com/excel/macros/vba-control-arrays.htm
I have a userform with multiple control types (TextBox, ComboBox, Button, Check box, Label).
I want to check the value in each TextBox and ComboBox and change the color of the box to red if there is no value.
The problem using "Controls" collection is that some controls do not have a value property i.e. Label. So I want to write code where there will be no need to define the type of control inside the body of the loop as the type is already specified at the declaration level.
Loop through the controls and if textbox or combobox and value ="" then change color to red
Private Sub CommandButton1_Click()
Dim crt As Control
For Each crt In Me.Controls
If TypeName(crt) = "TextBox" Or _
TypeName(crt) = "ComboBox" Then
If crt.Value = "" Then
crt.BackColor = vbRed
Else
crt.BackColor = vbWhite
End If
End If
Next
End Sub
I have a macro that produces two multi-line TextBoxes of related data (sometimes hundreds of rows long). The boxes always have the same number of lines of text in them, with each line corresponding to the adjacent line in the other TextBox. I looked into using a two-column ListBox, but decided to use TextBoxes so that the data can be copied out/highlighted/selected as desired by the user.
I want to make it so that if a user scrolls down, both TextBoxes scroll together (i.e., the lines stay synced up).
After much digging and experimenting, I figured it out! By adding a ScrollBar, I was able to use the ScrollBar_Change() event to adjust the text boxes. On my form, I now have two TextBoxes and a ScrollBar object. Then I have a few necessary subs in my Userform code:
'This constant affects whether the ScrollBar appears or _
not, as well as some of the movement graphics of the _
ScrollBar.
'This MUST be reset if the TextBoxes are resized
'I made it a UserForm-level Const because I use it _
elsewhere, but it could also live in SetUpScrollBar
Private Const TEXTBOX_MAX_LINES_IN_VIEW as Long = 21
Private Sub SetUpScrollBar()
'I call this whenever I show my Userform (happens after a _
separate macro determines what to put in the TextBoxes). _
It determines whether the ScrollBar should be shown, and _
if so, sets the .Max property so it scrolls in accordance _
to the number of lines in the TextBoxes.
Dim linesInTextBox as Long
With Me.TextBox1
.SetFocus
linesInTextBox = .LineCount - 1
'Need to subtract 1 or you'll get an error _
when dragging the scroll bar all the way down.
End With
'If there are fewer lines than the max viewing area, hide the scroll bar.
Select Case linesInTextBox > TEXTBOX_MAX_LINES_IN_VIEW
Case is = True
ShowScrollBar True
With Me.ScrollBox
.Min = 0 'I believe this is the default, but I set it just in case
.Max = maxLinesInTextBox
.Value = 0
End With
Case is = False
ShowScrollBar False
End Select
End Sub
Private Sub ShowScrollBar(show As Boolean)
'A simple way of showing or hiding the scrollbar
With Me.ScrollBar1
.Enabled = show
.Visible = show
End With
End Sub
Private Sub ScrollBar1_Change()
'When the scrollbar position changes (either by dragging _
the slider or by clicking it), set the CurLine property _
of each TextBox to the current ScrollBar value.
With Me.TextBox1
'Need to set focus to the box to get or adjust the CurLine property
.SetFocus
.CurLine = Me.ScrollBar1.value
End With
With Me.TextBox2
'Need to set focus to the box to get or adjust the CurLine property
.SetFocus
.CurLine = Me.ScrollBar1.value
End With
End Sub
This seems to work quite well for my purposes. It allows me to keep the text-selecting/copying benefits of using TextBoxes while keeping my data synced together.
Some issues I've yet to solve:
Scrolling works fine, but if you try to click the arrows (particularly to go in the opposite direction that you just scrolled), you have to click until your cursor gets to the top of the TextBoxes. For me, this is 21 clicks. A bit annoying, but I'm sure there's a workaround.
Scrolling is not live like with a normal scrollbar. This means you can drag the scrollbar, but it won't update the TextBoxes until you let go.
If a user clicks into a TextBox and starts to navigate with their arrow keys, the two boxes will become out of sync. They'll resync the next time the user clicks the ScrollBar. This is very problematic if the user tries to select more lines than are visible in the window: one TextBox will scroll as they drag their selection but the other TextBox stays in place
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
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.