How to prevent ActiveX events firing in VBA? - vba

I am searching for a better way to disable ActiveX events from triggering in an Excel workbook (though this would apply to all Office apps with ActiveX objects).
Hopefully something similar to Application.EnableEvents = false, though this does not work with ActiveX.
In the below example it's trivial to use a global boolean but I have a lot of event handlers for my ActiveX objects and it would be immensely easier for something I could universally apply to temporarily disable ActiveX events. I don't really want to add an if/exit sub statement to every single one of these methods.
To demonstrate this problem, create an ActiveX combobox in a worksheet and add the following to that sheet module
Public initializingContent As Boolean
Private Sub intializeAllActiveXContent()
'this doesn't apply to activeX events :'(
Application.EnableEvents = False
'this could work but is not really elegant
'change this to false to show my problem in
'the intermediate window (called not once but twice)
initializingContent = True
ComboBoxTest.Clear
ComboBoxTest.AddItem ("item1")
ComboBoxTest.AddItem ("item2")
ComboBoxTest.AddItem ("item3")
'select the top value in the box
ComboBoxTest.value = "item1"
initializingContent = False
Application.EnableEvents = True
End Sub
Private Sub ComboBoxTest_Change()
'I really don't want to have to wrap EVERY single ActiveX method
'with something like this for a whole variety of reasons...
If initializingContent Then Exit Sub
Debug.Print "do stuff I don't want to happen when intializeAllActiveXContent() runs " & _
"but I do when user changes box"
End Sub

I know this is really old. But anyone who looks this up (first hit on google) might want a simple answer:
Lets say you have a Private Sub ActiveXControl_Change() that is getting called during an Application.EnableEvents = False and you want it to skip this just go:
Private Sub ActiveXControl_Change()
If Application.EnableEvents = True Then
'enter you code here
End If
End Sub

Why not disable them? That ways you don't have to worry about their individual codes as well.
Try this
Sub DisableActiveXControls()
Dim ws As Worksheet
Dim OLEobj As OLEObject
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
For Each OLEobj In ws.OLEObjects
If TypeOf OLEobj.Object Is MSForms.ComboBox Then
OLEobj.Enabled = False
End If
Next OLEobj
End With
End Sub
Before/After ScreenShots:
FOLLOWUP FROM COMMENTS:
Also turns out this breaks hard core on objects which are grouped together but I can ungroup objects (they are no longer in "Sheet1.OLEobjects" I guess). I still don't really like this since it relies on this fact and there will be times when I do want to group objects.. – enderland 17 mins ago
To disables ActiveX Controls in a group, you don't need to ungroup them. Use this code. The below code will disable Comboboxes in a group.
Sub Disable_ActiveX_Controls_In_A_Group()
Dim shp As Shape, indvShp As Shape
Dim OLEobj As OLEObject
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
For Each shp In ws.Shapes
If shp.Type = msoGroup Then
For Each indvShp In shp.GroupItems
Set objOLE = indvShp.OLEFormat.Object
If objOLE.progID = "Forms.ComboBox.1" Then _
objOLE.Enabled = False
Next
End If
Next
End Sub

came across this post when searching for a similar issue. I decided the answer posted here would not suit my situation, and came up with something else. My approach may be useful here also.
In my workbook, I have a set of 20 (Activex) checkboxes. These essentially filter on/off 20 categories of product to be included in a report. There is a routine that runs each time one of these checkboxes is changed, simply by calling the routing from the CheckBox_Click routine.
Then I also have a combobox that selects various groups of these checkboxes. The trouble is that when EACH of the 20 checkboxes is (un)selected by the combobox code, the calculation routine is triggered.
What I wanted was to run the calculation routine only ONCE at the end of the combobox, but still have it work if I change an individual checkbox manually.
My solution - put in a TRUE/FALSE code in some cell on a hidden worksheet, somewhere it's out of the way and won't interfere.
Then the CheckBox_Click code becomes (for each of the 20 checkboxes):
Private Sub CheckBox6_Click()
If (Sheets("Data").Range("G60")) Then
Call RangeFind
End If
End Sub
The combobox code modifies this same cell, appropriately:
Private Sub ComboBox28_Change()
Sheets("Data").Range("G60").Value = False
Select Case Sheets("Data").Range("F50").Value
Case "1"
CheckBox1.Value = False
CheckBox2.Value = False
CheckBox3.Value = False
....
End Select
' This turns the checkboxes back on
Sheets("Data").Range("G60").Value = True
' This now actually calls the calculation ONCE
Call RangeFind
ActiveSheet.Range("A1").Activate
End Sub
Cheers,
Michael

Here is one option:
Private Sub ToggleButton1_Click()
If Application.EnableEvents = True Then
'This next line forces at least 1 of the toggle's to be selected at all
'times; remove it from all routines if this is not desired.
If Not ToggleButton1.Value Then ToggleButton1.Value = True
Application.EnableEvents = False
ToggleButton2.Value = False
ToggleButton3.Value = False
Application.EnableEvents = True
End If
End Sub
Private Sub ToggleButton2_Click()
If Application.EnableEvents = True Then
If Not ToggleButton2.Value Then ToggleButton2.Value = True
Application.EnableEvents = False
ToggleButton1.Value = False
ToggleButton3.Value = False
Application.EnableEvents = True
End If
End Sub
Private Sub ToggleButton3_Click()
If Application.EnableEvents = True Then
If Not ToggleButton3.Value Then ToggleButton3.Value = True
Application.EnableEvents = False
ToggleButton1.Value = False
ToggleButton2.Value = False
Application.EnableEvents = True
End If
End Sub

Related

Prevent OptionButton preselection in UserForms

I have the following code in a UserForm:
Private Sub CommandButton1_Click()
Warning_Box.Hide
End Sub
Private Sub OptionButton1_Click()
KeepGoing = 0
End Sub
Private Sub OptionButton2_Click()
KeepGoing = 1
End Sub
The first time this code runs, it works fine as none of the OptionButtons is preselected by the VBA code. The second time however, the previous choice is preselected. This appears to stop the correct setting of the KeepGoing value (as an earlier section sets KeepGoing = 2).
Basically, how do I make it so no OptionButton is preselected after the first run?
You will need to change
Warning_Box.Hide
to
Unload Me
You may have good reasons not to use Unload Me. If so, you can just set values of all option buttons to false somewhere in your code.
Warning_Box.OptionButton1.Value = False
for every option button. You can also loop trough Warning_Box.Controls and set value to false if it is option button.
Dim con As Control
For Each con In ufMain.Controls
If TypeName(con) = "OptionButton" Then con.Value = False
Next con

Menu to navigate through sheets doesn't work proper

I've created a menu to navigate through sheets. But when I use one of the buttons to go to another sheet and type something in this another sheet the things that I type appear in the first one. Although when I use the tabs to jump to one sheet to another it works fine. Seems to be that the macro is considering a relative reference instead a absolute one.
Here's what my macro does (or at least should):
Private Sub cadastrar_clientes_Click()
Application.ScreenUpdating = False
Menu.Hide
Sheets("Clientes").Select
Range("A1048576").Select
Selection.End(xlUp).Select
ActiveCell.Offset(1, 0).Range("A1").Select
ActiveCell.Select
End Sub
Notes:
I've tried to use ".activate" instead of ".select".
I've tried to use only "Sheets("Clientes").Select", even so the bug occurs.
To execute "Excel /unregserver" on the Windows CMD solved my problem once, but I couldn't do this again. It doesn't seems to work anymore.
I did a menu like this one once, but I didn't had these problems.
When the workbook opens the following code is executed:
Private Sub Workbook_Open()
Application.DisplayFullScreen = True
Application.DisplayFormulaBar = False
ActiveWindow.DisplayHeadings = False
ActiveWindow.DisplayGridlines = False
ActiveWindow.DisplayWorkbookTabs = False
End Sub
That's it. I hope that somebody could help me.
Replace all code on VBA module Menu with this (tested in the file you provided)
Option Explicit
Private Sub fechar_menu_Click()
Menu.Hide
End Sub
Private Sub novo_pedido_Click()
goToTab ActiveWorkbook.Worksheets("Novo pedido"), "B5"
End Sub
Private Sub ver_pedidos_Click()
goToTab ActiveWorkbook.Worksheets("Consultar pedido"), "F1"
End Sub
Private Sub cadastrar_clientes_Click()
goToTab ActiveWorkbook.Worksheets("Clientes")
End Sub
Private Sub cadastrar_produtos_Click()
goToTab ActiveWorkbook.Worksheets("Produtos")
End Sub
Private Sub cadastrar_transportadoras_Click()
goToTab ActiveWorkbook.Worksheets("Transportadoras")
End Sub
Private Sub painel_financeiro_Click()
goToTab ActiveWorkbook.Worksheets("Painel Financeiro"), "B3"
End Sub
Private Sub goToTab(ByRef ws As Worksheet, Optional cel As String = vbNullString)
Menu.Hide
Application.ScreenUpdating = False
With ws
.Activate
If Len(cel) = 0 Then
.Range("A" & .Rows.Count).End(xlUp).Offset(1, 0).Select
Else
.Range(cel).Select
End If
End With
Application.ScreenUpdating = True
End Sub
Well, I guess I know a lot more about the problem now. I've tested the workbook over various computers and came to the conclusion that the problem is within the Office 2013. I haven't seem this issue when running the 2007 or 2010 version. So far I haven't come to a solution. I would like to thanks Paul Bika for helping.

How can I run a macro as a workbook opens for the first time only?

I've got a workbook which runs a macro to show the userform Open1 as it opens, using the (very basic) code:
Private Sub Workbook_Open()
Open1.Show
End Sub
This does its job fine - each time I open the workbook, the userform pops up and runs perfectly.
But, I want the userform to appear the first time the workbook is opened only. Is there a way to allow this to happen?
You could use a dummy module which gets deleted the first time you open the spreadsheet...
Something like:
If ModuleExists("DummyModule") Then
Open1.Show
DoCmd.DeleteObject acModule, "DummyModule"
End If
Function ModuleExists(strModuleName As String) As Boolean
Dim mdl As Object
For Each mdl In CurrentProject.AllModules
If mdl.Name = strModuleName Then
ModuleExists = True
Exit For
End If
Next
End Function
Update: as stated, DoCmd isn't used in excel vba. That will teach me to write code without testing it!
The following updated code will work, but in order to access the VB environment, excel needs to be trusted.
There is a setting in the Trust Center>Macro Settings that you can tick for this code to work under Developer Macro Settings
As such, this may not be the way to go as it opens up the possibility of security issues...
Sub RemoveModule()
If ModuleExists("DummyModule") Then
Open1.Show
Dim vbCom As Object: Set vbCom = Application.VBE.ActiveVBProject.VBComponents
vbCom.Remove VBComponent:=vbCom.Item("DummyModule")
End If
End Sub
Function ModuleExists(strModuleName As String) As Boolean
Dim mdl As Object
For Each mdl In Application.VBE.ActiveVBProject.VBComponents
If mdl.Name = strModuleName Then
ModuleExists = True
Exit For
End If
Next
End Function
Try this:
If Sheets("Hide").Cells(1,1) = "1" Then
Open1.Show
Sheets("Hide").Cells(1,1) = "0"
End if
You must create the sheet Hide, and give the cell A1 the value 1, in that case the form will be shown.
After you create the sheet, hide it with this
Sheets("Hide").Visible = xlVeryHidden
And show it with this
Sheets("Hide").Visible = True
Here's an alternative bit of code that will persist between saves and allow you to reset it. No need to create a hidden sheet.
Put this in a module (invoke the DisplayFormIfFirstTime from your Workbook_Open event handler....)
Option Explicit
Private Const cMoniker As String = "FormHasBeenDisplayed"
Private Sub DisplayFormIfFirstTime()
If HasBeenOpened = False Then DisplayForm
End Sub
Public Sub DisplayForm()
MsgBox "Ok, its not a form but a dialog box...", vbInformation
End Sub
Public Function HasBeenOpened() As Boolean
Dim oName As Name
On Error Resume Next
Set oName = Application.Names(cMoniker)
On Error GoTo 0
If Not oName Is Nothing Then
HasBeenOpened = True
Else
Call Application.Names.Add(cMoniker, True, False)
End If
End Function
'Call this to remove the flag...
Public Sub ResetOpenOnce()
On Error Resume Next
Application.Names(cMoniker).Delete
End Sub
Based on the idea supplied by PaulG, I have coded an upgrade that will check for the name and if not found run a function, add the name and save the workbook for a more seemless approach to this problem...
Placed in ThisWorkbook
Private Sub Workbook_Open()
Run "RunOnce"
End Sub
Placed in a module
Sub RunOnce()
Dim Flag As Boolean: Flag = False
For Each Item In Application.Names
If Item.Name = "FunctionHasRun" Then Flag = True
Next
If Flag = False Then
Call Application.Names.Add("FunctionHasRun", True, False)
Application.DisplayAlerts = False
ActiveWorkbook.Save
Application.DisplayAlerts = True
Call RunOnceFunction
End If
End Sub
Private Function RunOnceFunction()
Open1.Show
End Function
Sub ResetRunOnce()
For Each Item In Application.Names
If Item.Name = "FunctionHasRun" Then
Application.Names.Item("FunctionHasRun").Delete
Application.DisplayAlerts = False
ActiveWorkbook.Save
Application.DisplayAlerts = True
End If
Next
End Sub

Worksheet.RefreshAll triggers Worksheet_changed Event - how do I stop this from happeing?

I have an excel worksheet that is being used as a database front end for access. When a user changes data in a cell it will run the Worksheet_changed event to run codes that updates the access database.
However - I also have a refresh button that, you guessed it, refreshes the spreadsheet. This also causes the worksheet_changed event to run which will sometimes error out the program.
Private Sub RefreshButton_Click()
Refreshbuttons
ActiveWorkbook.RefreshAll
End Sub
How do I stop the work sheet changed event from happening when the refresh button is pressed? I have tried a Boolean flag which will stop the worksheet changed event from running when refreshed button is pressed - but it stops it from running at all (example of what I did)
Private Sub RefreshButton_Click()
Dim Flag as Boolean
Flag = True
Refreshbuttons
ActiveWorkbook.RefreshAll
Flag = False
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Flag = true then
Exit Sub
Else
[...] {Rest of code below here}
I am stuck - any help is greatly appreciated!!!
Thanks,
Ethan
EDIT
Thanks Tim! you pointed me in the right direction. I ended up going with (code below) and it worked beautifully. I appreciate everyones help!
Private Sub RefreshButton_Click()
For Each objConnection In ThisWorkbook.Connections
'Get current background-refresh value
bBackground = objConnection.OLEDBConnection.BackgroundQuery
'Temporarily disable background-refresh
objConnection.OLEDBConnection.BackgroundQuery = False
'Refresh this connection
objConnection.Refresh
If ActiveSheet.FilterMode = True Then
ActiveSheet.ShowAllData
Else
End If
'Set background-refresh value back to original value
objConnection.OLEDBConnection.BackgroundQuery = bBackground
Next
MsgBox "Refresh Complete"
End Sub
Private Sub RefreshButton_Click()
On Error Goto haveError
Refreshbuttons
Application.EnableEvents = False
ActiveWorkbook.RefreshAll
haveError:
Application.EnableEvents = True
End Sub
Declare Flag as global like below. It should work.
Public Flag as Boolean
All office applications have a built-in function to control this behavior. Simply add:
Application.EnableEvents = False to the beginning of the RefreshButton_Click event and
Application.EnableEvents = True to the end of the event.

Remove shadow from ActiveX Option Button in Excel 2010 VBA

I was trying to emphasis the option button from activeX control when it is selected by user. I decided to show the shadow when it is selected and then hide the shadow when user selects other option button. The first process is working whereas the shadow cannot be removed even though I select other button. My VBA code is shown below:
Private Sub OptionButton1_Click()
OptionButton1.Shadow = False
If OptionButton1.Value = True Then
OptionButton1.Shadow = True
Else
OptionButton1.Shadow = False
End If
End Sub
Can anyone please help me to solve this?
In case of FORMS buttons you can use
Sub RemoveFormsButtonShadows()
'A.Leine 21/10/2015
For Each Button In ActiveSheet.Shapes
Button.Select
Selection.ShapeRange.Shadow.Visible = False
Next Button
End Sub
For that you have to create one sub which needs to be called from all the option buttons that you have. This common sub will simply remove the shadow from all option buttons. Here I am taking the example of 3 option buttons.
Option Explicit
Private Sub OptionButton1_Click()
RemoveShadow
If OptionButton1.Value = True Then _
OptionButton1.Shadow = True
End Sub
Private Sub OptionButton2_Click()
RemoveShadow
If OptionButton2.Value = True Then _
OptionButton2.Shadow = True
End Sub
Private Sub OptionButton3_Click()
RemoveShadow
If OptionButton3.Value = True Then _
OptionButton3.Shadow = True
End Sub
Sub RemoveShadow()
Dim objOpt As OLEObject
With ActiveSheet
For Each objOpt In .OLEObjects
If TypeName(objOpt.Object) = "OptionButton" Then
objOpt.Shadow = False
End If
Next
End With
End Sub