VBA: Disable button in Excel after first click - vba

I am trying to disable a button placed on my sheet1 once the user click on it.
I went through few old Stackoverflow answers but dosent work as my expectation.
The code:
Sub Button2_Click()
Call FindADate
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
It actually grayed out the button which give a feel that the button is disabled but User can click again and again and it run my code.
Kindly let me know a solution to get the button disabled after 1 click, the button will be active again only once I close and re open the excel. (I am using MS Office professional Plus 2013)
Thanks in advance.

You need to record somehow not to process the click. You could examine the button's text colour and if grey then ignore the click. Alternatively, you could set a variable either a global, module or static local variable. I chose the static local variable in the code below, called vDisable.
Option Explicit
Sub Button2_Click()
Static vDisable As Variant
If IsEmpty(vDisable) Then
Call FindADate
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
vDisable = True
End If
End Sub

after Dim line just write:
if myshape.TextFrame.Characters.Font.ColorIndex = 15 then exit sub
that should be enough

I know this is an old question, but I had the same situation and solved it by the following:
With myshape
.OnAction = "" '---> Removes any macro from the button
.TextFrame.Characters.Font.ColorIndex = 15 '---> Grey out button label
End With
This removes the need for a global/static variable.

Related

Automatically Show ShapeSheet of Current Shape

I do a lot of Visio ShapeSheet editing and it would save me a tremendous amount of time to automatically switch to the current shape's sheet when I select a new shape. Let's assume I only have 1 ShapeSheet open, only select 1 Shape, and have all the windows docked on the Visio app (I don't have RegEdit powers to change this).
So far, I've got the following VBA code in ThisDocument:
Private WithEvents vsoWin as Visio.Window
Private Sub ThisDocument_RunModeEntered(ByRef doc as IVDocument)
'Just assume this is the correct window
Set vsoWin = ActiveWindow
End Sub
Private Sub vsoWin_SelectionChanged(ByRef win as IVWindow)
'If nothing is selected, leave
If vsoWin.Selection.Count < 1 Then Exit Sub
'Look for a ShapeSheet (Window.SubType = 3)
For each oWin in Application.Windows
If oWin.Subtype = 3 Then
Application.ScreenUpdating = False 'Pause screen to prevent jitter
oWin.Close 'Delete old ShapeSheet
vsoWin.Selection(1).OpenSheetWindow 'Make new ShapeSheet
Application.ScreenUpdating = True 'Update visuals
Exit For 'Stop looking for ShapeSheets
End If
Next
Exit Sub
(The above code is written from memory since I don't have access to Visio at the moment. Please forgive any minor errors)
This code works, but I'm hoping for a less jittery result. Application.ScreenUpdating = False doesn't seem to do anything in this case: I still briefly witness the old ShapeSheet closing, the drawing window resizing, then the new ShapeSheet opening. Swapping the order (open new window > close old window) is a little less chaotic, but not great. Using Application.Minimize to hide the swap instead is slightly better on the eyes, but still not a smooth transition.
My question: Is there a smoother way to display the active shape's ShapeSheet?
This code works at my side! I just add variable which related with Visio Application - vsoApp.
Private WithEvents vsoWin As Visio.Window
Private WithEvents vsoApp As Visio.Application
Sub st()
Set vsoWin = ActiveWindow ' initialize Window variable
Set vsoApp = Application ' initialize Application variable
End Sub
Private Sub ThisDocument_RunModeEntered(ByRef doc As IVDocument)
'Just assume this is the correct window
Set vsoWin = ActiveWindow
End Sub
Private Sub vsoApp_SelectionChanged(ByVal Window As IVWindow)
'If nothing is selected, leave
If vsoWin.Selection.Count < 1 Then Exit Sub
'Look for a ShapeSheet (Window.SubType = 3)
For Each oWin In Application.Windows
If oWin.SubType = 3 Then
Application.ScreenUpdating = False 'Pause screen to prevent jitter
oWin.Close 'Delete old ShapeSheet
vsoWin.Selection(1).OpenSheetWindow 'Make new ShapeSheet
Application.ScreenUpdating = True 'Update visuals
Exit For 'Stop looking for ShapeSheets
End If
Next
End Sub
My workaround:
Press Alt+F8 keys and run St sub-routine.
Open ShapeSheet window for selected shape.
Select another shapes and so on...
Update with your code i get error like this.

Change Color of ActiveX Command Button with Macro

As a part of a spreadsheet I'm making, I want a macro to change the color of an ActiveX button. Right now I have the button change colors when it is clicked. I want it to change back to the original color when a separate macro is run.
Any thoughts are appreciated, thank you!
Let's assume that the Button is white:
Macro1:
Sheet(n).CommandButton1.BackColor = 'something
Macro2:
Sheet(n).CommandButton1.BackColor = &H00FFFFFF&
Shouldn't this be the only thing you have to do?
(More)
You are probably looking for something like this:
Option Explicit
Sub tmpSO()
Dim Sh As Worksheet
Dim Obj As OLEObject
For Each Sh In ThisWorkbook.Worksheets
For Each Obj In Sh.OLEObjects
If TypeName(Obj.Object) = "CommandButton" Then
Debug.Print Obj.Name
If Obj.Object.BackColor = -2147483633 Then
Obj.Object.BackColor = 6740479
Else
Obj.Object.BackColor = -2147483633
End If
End If
Next Obj
Next Sh
End Sub
Note, that the .Name resides directly on the .OLEObject while the .BackColor is a sub-element of .OLEObject.Object.
The above code will toggle all buttons background color between the greyish (default) color and an orange color.
Let me know if you have any questions.

VBA Grey Checkboxes

I would like to grey out my checkboxes in Excel VBA. When using Checkbox.Enabled = False, the checkbox is not editable, but it is also not grey. How do I get the greyed out effect?
Using form controls with Excel 2010. Inserted via developer tab directly into excel worksheet. Not used in a VBA userform.
Thanks!
Whenever anyone says "it is impossible", it hits my stubborn streak. So may I present to you: "The Impossible".
"Visible" and enabled checkbox:
"Disabled" checkbox (you can tweak the degree of visibility by changing values in the code for both color and transparency of the cover shape):
Basic idea: you place a semi transparent shape over the checkbox, and assign a dummy macro to it. Now you can't change the value of the checkbox. The "toggle" button is there to change the state - either place the shapes, or remove them. It uses a global variable to track the current state.
Finally - note that you can't use For Each when you delete (or add) shapes as you should not modify the collection you are iterating over. I circumvented that with a simple "count shapes, then iterate backwards by numerical index".
Is it a hack? You bet! Does it do what you asked? Yes!
Dim checkBoxesVisible As Boolean
Option Explicit
Sub toggleIt()
' macro assigned to "Toggle visibility" button
checkBoxesVisible = Not checkBoxesVisible
toggleCheckboxes checkBoxesVisible
End Sub
Sub grayOut(cb)
' put a "cover" shape over a checkbox
' change the color and transparency to adjust the appearance
Dim cover As Shape
Set cover = ActiveSheet.Shapes.AddShape(msoShapeRectangle, cb.Left, cb.Top, cb.Width, cb.Height)
With cover
.Line.Visible = msoFalse
With .Fill
.Visible = msoTrue
.ForeColor.RGB = RGB(255, 255, 255)
.Transparency = 0.4
.Solid
End With
End With
cover.Name = "cover"
cover.OnAction = "doNothing"
End Sub
Sub doNothing()
' dummy macro to assign to cover shapes
End Sub
Sub unGray(cb)
' find the cover shape for the checkbox passed as the argument
' and delete it
' "correct shape" has the name "cover" and is properly aligned with top left
Dim sh As Shape
For Each sh In ActiveSheet.Shapes
If sh.Name = "cover" And sh.Left = cb.Left And sh.Top = cb.Top Then
sh.Delete
Exit For
End If
Next sh
End Sub
Sub toggleCheckboxes(onOff)
Dim s As Shape
Dim n As Integer, ii As Integer
n = ActiveSheet.Shapes.Count
' loop backwards over shapes: if you do a "For Each" you get in trouble
' when you delete things!
For ii = n To 1 Step -1
Set s = ActiveSheet.Shapes(ii)
If s.Type = msoFormControl Then
If s.FormControlType = xlCheckBox Then
If onOff Then
unGray s
Else
grayOut s
End If
End If
End If
Next ii
End Sub
A slight hack - but the following does work. I created a simple userform with two controls - a regular checkbox (CheckBox1), and a button I called "DisableButton" with the following code:
Private Sub DisableButton_Click()
CheckBox1.Enabled = Not (CheckBox1.Enabled)
If CheckBox1.Enabled Then
CheckBox1.ForeColor = RGB(0, 0, 0)
Else
CheckBox1.ForeColor = RGB(128, 128, 128)
End If
End Sub
When I clicked the button, the checkbox was grayed out and unavailable. Clicking it again "brought it back to life". I think this is the effect you were looking for. If it's not - that's what comments are for.
Here is what it looks like:
I am afraid it is impossible what you are trying to do within a worksheet. You can refer to the Floris' answer if you are using an UserForm.
For more details on the properties of (Form/worksheet) check boxes see MSDN
Maybe this is what you want.
Private Sub CheckBox1_Click()
If CheckBox1.Value = True Then
CheckBox2.Value = False
CheckBox2.Enabled = False
CheckBox2.ForeColor = rgbBlue
Else
CheckBox2.Visible = True
CheckBox2.ForeColor = rgbAntiqueWhite
CheckBox2.Enabled = True
End If
Code tels that when checkbox1 is checked, checkbox2 is disabled; unchecked and the forecollor changes. the colors can be what you want.
Did this with the checkboxes directly in the excel worksheet.
Based on Floris' idea.
The code assumes all the controls are on ActiveSheet and they are called CheckBox1 and CheckBox2, if not, change it accordingly.
You can call this when you click on CheckBox1 or you can call it from another sub, with an optional ticked status (True/False) to check or uncheck CheckBox1.
Draw an object on top of CheckBox2 and name it "mask" (you can name it anything else but then you have to change the code accordingly)
Give mask the same fill color as your background color and opacity of around 50%.
Public Sub CheckBox1_Click(Optional ticked As Variant)
Application.ScreenUpdating = False
ActiveSheet.Unprotect
If Not IsMissing(ticked) Then
If ticked = True Then ActiveSheet.Shapes("CheckBox1").OLEFormat.Object.Value = 1 Else ActiveSheet.Shapes("CheckBox1").OLEFormat.Object.Value = -4146
End If
If ActiveSheet.Shapes("CheckBox1").OLEFormat.Object.Value > 0 Then
ActiveSheet.Shapes("mask").OLEFormat.Object.ShapeRange.ZOrder msoSendToBack
Else
ActiveSheet.Shapes("mask").OLEFormat.Object.ShapeRange.ZOrder msoBringToFront
End If
ActiveSheet.Protect DrawingObjects:=True, Contents:=True, Scenarios:=True
Application.ScreenUpdating = True
End Sub
Now each time you tick CheckBox1, mask comes to front to hide CheckBox2 and when you untick it, mask goes to back to unhide it. Since it is opaque, it gives you the greyed out effect and you don't even have to worry about enable/disable either.
Worksheet should be protected so that user can't accidentally move or edit mask, but should be unprotected for SendToBack/BringToFront to work, so the code does that. Please check the protection settings at the Application.Protect part.

Word crashes on removing a Shape with VBA from a header

(disclaimer: i'm not a VBA programmer by occupation)
Attached to buttons in the Ribbon I have code to toggle the company logo in a Word Document.
One button for the logo type A, a second button for logo type B and a third for no logo (logo is preprintend on paper)
First I remove the logo with removeLogo and then i add it the requested logo with setLogoAt.
The first button click is fine (e.g. for Logo Type A), a logo is added to the header of the document. When i click an other button (e.g for Logo Type B) Word crashes (probably on removing the current logo)
What is wrong with my code (or less probably: with Word?)
Sub setLogoAt(left As Integer, path As String)
Dim logoShape As Shape
Dim anchorLocation As Range
Dim headerShapes As Shapes
Set logoShape = ActiveDocument. 'linebreks for readability
.Sections(1)
.Headers(wdHeaderFooterPrimary)
.Shapes
.AddPicture(FileName:=path, LinkToFile:=False,
SaveWithDocument:=True, left:=0,
Top:=0, Width:=100, Height:=80)
logoShape.name = "CompanyLogo"
logoShape.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
logoShape.RelativeVerticalPosition = wdRelativeVerticalPositionPage
logoShape.Top = CentimetersToPoints(0.1)
logoShape.left = CentimetersToPoints(left)
End Sub
Sub removeLogo()
Dim headerShapes As Shapes
Set headerShapes = ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary).Shapes
Dim shapeToDelete As Shape
If (headerShapes.Count > 0) Then
If Not IsNull(headerShapes("CompanyLogo")) Then
Set shapeToDelete = headerShapes("CompanyLogo")
End If
End If
If Not (shapeToDelete Is Nothing) Then
shapeToDelete.Delete
End If
End Sub
edit
I steped trough my code. All is fine until I reach the line shapteToDelete.Delete in removeLogo. Here Word crashes hard, even while debugging. I'm using Word 2007 (and that is a requirement)
edit2
I cleared all macros, all normals.dot, all autoloading templates, then created a new document with the two routines above and this test method:
Sub test()
setLogoAt 5, "C:\path\to\logo.jpg"
removeLogo
setLogoAt 6, "C:\path\to\logo.jpg"
End Sub
When I run test it crashes in removeLogo at shapeToDelete.Delete.
Edit 3
I 'solved' the problem by first making the headers/footers view the active view in Word, then deleting the Shape and then returning to normal view. Very strange. It works but as a programmer I'm not happy.
Another potential solution is to try and select the shape first and then delete the selection:
shapeToDelete.Select
Selection.Delete
You would probably want to switch off screen updating if this works, else you'll get flickering as Word moves around the document.
I've experienced this problem before and normally with an automation error: "The object invoked has disconnected from its clients". I haven't yet found a solution.
However a good workaround is to hide the shape rather than delete it.
So:
shapeToDelete.Visible = False
This works:
I only have 2 boxes to hide so this isn't generic
Private Sub btnPrint_Click()
Dim hdrShapes As Shapes
Dim S As Shape
Dim aTohide(2) As String
Dim iNdx, i As Integer
iNdx = 0
' Hide buttons and print
Set hdrShapes = ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary).Shapes
' GET BUTTON NAMES (ACTUALLY TEXT BOXES
For Each S In hdrShapes
If S.Type = msoTextBox Then
aTohide(iNdx) = S.Name
iNdx = iNdx + 1
End If
Next
' now hide , use the arrays as the for each statement crashes
For i = 0 To 1
hdrShapes(aTohide(i)).Visible = msoFalse
Next
' print it
With ActiveDocument
.PrintOut
End With
' and unhide the buttons
For i = 0 To 1
hdrShapes(aTohide(i)).Visible = msoTrue
Next
Set hdrShapes = Nothing
End Sub

Right click on sheet-tabs disabled in Excel

I used this vba code in the ThisWorkbook module to disable the right click menu in an Excel workbook.
Private Sub Workbook_Activate()
With Application.CommandBars.FindControl(ID:=847)
.Visible = False
End With
End Sub
Private Sub Workbook_Deactivate()
With Application.CommandBars.FindControl(ID:=847)
.Visible = True
End With
End Sub
Works like a charm.
Problem is, I can't access the right click menu on tabs in ANY workbook now.
The second part of the code is supposed to turn it back on, I assumed? Yet it doesn't.
Even when I remove the code entirely, no workbook, not even a new one, has a menu when I click right on one of the tabs.
Is there a general vba codesnippet that "resets" excel maybe? Or a general "enable all menus" thing?
REVISION:
This code posted here doesn't disable the rightclick menu, it removes the "delete" option from that specific menu.
omg
Application.CommandBars("Ply").Enabled = True
-.-
Started googling different keywords after the last edit and BAM.
Late again as usual, but tackled with the same problem today. Here's the solution to get your right-click functionality back:
Option Explicit
'
Sub tester()
'
Dim cBar As CommandBar
'
For Each cBar In CommandBars
Debug.Print cBar.Name
If (cBar.Type = msoBarTypePopup) Then cBar.Enabled = True
Next
End Sub
Also note that the below also exist. Some macro from work had them all disabled in my Excel.
Application.CommandBars("Cell").Enabled = True
Application.CommandBars("Row").Enabled = True
Application.CommandBars("Column").Enabled = True