I have a VBA Add-In which is supposed to add functionality to several worksheets. I have a class to listen for worksheet events and trigger macros. This works but I can't seem to call private macros with parameters from it.
My event listener is in a class module and is this:
Option Explicit
Private WithEvents App As Application
Private Sub Class_Initialize()
Set App = Application
End Sub
Private Sub App_SheetChange(ByVal Sh As Object, ByVal Source As Range)
On Error GoTo Finish
App.EnableEvents = False
Call Application.Run("Worksheet_Change", "Source")
Finish:
App.EnableEvents = True
End Sub
It is initialized on opening the workbook in a module like so:
Sub Auto_Open()
Set clsAppEvents = New clsApplicationEvents
End Sub
And the macro I'm trying to call is in a separate module again and takes the form:
Private Sub Worksheet_Change(ByVal Target As Range)
'Do some work on range
End Sub
I've tried the following ways of calling the macro and none have worked so far:
Call Application.Run("Worksheet_Change", "Source")
Application.Run "Worksheet_Change", "Source"
Application.Run "Worksheet_Change" "Source"
The arguments to Run don't all have to be strings, so
Application.Run "Worksheet_Change", "Source"
Should be
Application.Run "Worksheet_Change", Source
Related
The following VBA code snippet should be executed in all open workbooks within a single Excel file (*.xlsm):
Private Sub Worksheet_Change(ByVal Target As Range)
...
End Sub
We do not want to copy the code in each workbook to reduce code duplication.
When trying to create a new Macro via the Excel "Macro" dialog it offers the possibility to locate the Macro in:
all open workbooks
this/current workbook
current file
When choosing (1) in combination with a Macro name, e.g. "MultiSelect" Excel jumps in the VBA editor and scaffolds a basic method according to the given name:
Sub MultiSelect()
...
End Sub
Our question: how to guarantee reacting on "Worksheet_Change" events within this macro?
With the help of "Robin Mackenzie" I found a solution :) Especially, reading section Application Events In A New Class Module helped. So, I created a new class named "CExcelEvents":
Private WithEvents App As Application
Private Sub App_SheetChange(ByVal Sh As Object, ByVal Target As Range)
'gets the code more robust when the SheetChange event is called twice
If Me.EnableEvents = False Then
Exit Sub
End If
Application.EnableEvents = False
...//code to centralize
Application.EnableEvents = True
Me.EnableEvents = False
End Sub
Private Sub Class_Initialize()
'setting a variable for this object
Me.EnableEvents = True
Set App = Application
End Sub
and added in each worksheet - where the central code located in CExcelEvents has to be executed - the following object creation scaffold:
Private XLApp As CExcelEvents
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Set XLApp = New CExcelEvents
Application.EnableEvents = True
End Sub
To prevent eventloops, see: Run a macro when certain cells change in Excel but from my Personal workbook
Ms Word does not want to load my add-in. I want to call a userform on print event. Here is my code:
in module 1
Option Explicit
Private Sub App_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
'Debug.Print Now & " " & "App_DocumentBeforePrint: " & Wb.FullName
Userform1.Show
End Sub
Sub InitializeApp()
Dim X As New EventClassModule
Set X.App = Word.Application
End Sub
in Document module
Private Sub Document_Open()
Call InitializeApp
End Sub
in EventClassModule
Public WithEvents App As Word.Application
in Userform1 Mode
Option Explicit
Private Sub UserForm1_Initialize()
End Sub
I used this 2 links to help me write this code
1) https://msdn.microsoft.com/en-us/library/bb221264%28v=office.12%29.aspx
2) https://msdn.microsoft.com/en-us/library/gg597509%28v=office.14%29.aspx
Can anyone tell why my code does not work?
As explained in the first link you show, the procedure App_DocumentBeforePrint needs to be in the CLASS module (EventClassModule, in your explanation), not in Module 1.
Other than that, it's not clear what you mean by "my add-in". Usually, I'd think of a template (or COM add-in) when this term is used that's being loaded as an add-in. I'm concerned whether Document_Open is actually being triggered to initialize your events. This event, in the ThisDocument module (in reality, it's a class) will only fire when the document containing this code is opened...
For anybody else who comes across this thread like I did, this is what worked for me:
in module 1
(your module shouldn't contain the event-based sub; also, X needs to be declared as a global variable rather than within the 'InitializeApp' sub)
Option Explicit
Dim X As New EventClassModule
Sub InitializeApp()
Set X.App = Word.Application
End Sub
in Document module
Private Sub Document_Open()
Call InitializeApp
End Sub
in EventClassModule
(your Class Module should contain the event-based sub)
Public WithEvents App As Word.Application
Private Sub App_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
'''Your procedure here
End Sub
I have set up an application level event class to monitor when new workbooks are created/ opened by following CPearson's guide. This works fine in isolation. However, it is intended as part of add-in I'm writing where several other subs are also called in the 'Workbook_Open' sub, see below code:
Private XLApp As baseCXlEvents
Private Sub Workbook_Open()
Set XLApp = New baseCXlEvents
test
AddLocalReferences
AddModules
AddClassModules
Debug.Print "testing"
End Sub
So the XLApp variable is called in the module scope as a baseCXlEvents class. I have added a Class_Terminate event to this class and this is triggered after the Debug.print "testing" is run, i.e. XLApp is terminated after the Workbook_Open sub has run. This does not happen when I quote out the subs AddLocalReferences, AddModules, and AddClassModules, which do exactly as their names would imply. The sub test only prints a messages in debug to test whether calling additional subs caused XLApp to be terminated.
My current 'hunch' is that adding references, modules, or class modules counts as "editing", causing it to be terminated, as explained in this MS Support document. But, if so, why doesn't XLApp get terminated until the end of the sub? As opposed to as soon as AddLocalReferences is run.
Any suggestions why the class is terminated? I need it to 'stay alive' and also need to load additional modules and references for the addin upon workbook_open. If needed more details of this code can be provided.
I've decided to add my baseCXlEvents class module's code:
Option Explicit
Private WithEvents App As Application
Private Sub App_NewWorkbook(ByVal Wb As Workbook)
MsgBox "New Workbook: " & Wb.Name
End Sub
Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
MsgBox "Workbook opened: " & Wb.Name
End Sub
Private Sub Class_Initialize()
Debug.Print "Initializing baseCXlEvents instance.."
Set App = Application
End Sub
Private Sub Class_Terminate()
Debug.Print "Terminating baseCXlEvents instance.."
End Sub
Well then try to separate the Workbook_Open event handler stuff (where you add references etc.) from the creation of the instance of the class baseCXlEvents using Auto_Open.
Workbook_Open runs first, Auto_Open runs then.
Note: baseCXlEvents Instancing must be set to Public.
ThisWorkbook class
Public XLApp As baseCXlEvents
Private Sub Workbook_Open()
Test
AddLocalReferences
AddModules
AddClassModules
End Sub
Standard module
Sub Auto_Open()
Set ThisWorkbook.XLApp = New baseCXlEvents
End Sub
I have VBA code in the Sheet1 module and I want to call a sub procedure in that Sheet1 module when the workbook open so I do:
Private Sub Workbook_Open()
Call MyMacro
End Sub
behind SHeet1 I have
Public Sub MyMacro()
........
End Sub
When the workbook opens I get the error:
sub or function not defined "call GetReutersData"
How can I call MyMacro from the Open() event?
I need to have the MyMacro code in the sheet1 module just becuase that's the way it has to be. I cannot create a new module.
Private Sub Workbook_Open()
sheet1.MyMacro
End Sub
Please try this
Write the below code in Thisworkbook
Private Sub Workbook_Open()
Call Sheet1.MyMacro
End Sub
'----- Sheet 1 Code ---
Public Function MyMacro()
MsgBox "hi"
End Function
Is Absolutely Working on My system
What I am trying to accomplish is fairly simple. When a user selects a sheet, I would like a message box to appear. Meaning: I'm currently viewing Sheet1, I click on the Sheet2 tab and a message pops up before I can do anything. I can't seem to find the event that fires when moving to a different sheet.
Events I've tried: Workbook_SheetActivate and Worksheet_Activate
Private Sub Workbook_SheetActivate(ByVal sh As Object)
MsgBox ("Example Message")
End Sub
Or
Private Sub Worksheet_Activate()
MsgBox ("Example Message")
End Sub
I've done some googling and most things are about when cell values change or the cell selection changes.
This should work:
Private Sub Worksheet_Activate()
MsgBox "you never visit...you never call....you never write"
End Sub
However:
code must be in the worksheet code area
macros must be enabled
events must be enabled
You could use the following in the "ThisWorkbook" module to fire a message whenever you change sheets within the workbook.
Sub Workbook_SheetActivate(ByVal Sh As Object)
MsgBox Sh.Name & " activated!"
End Sub
This will solve the problem without having to add Private Sub Worksheet_Activate() to every worksheet's code module.
Here is a link to all the worksheet events available in Excel:
http://dmcritchie.mvps.org/excel/event.htm
Private Sub Worksheet_Activate()
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) -- (additional examples)
Cancel = True 'turn off Edit mode when using “Edit directly in a cell”
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
Cancel = True 'turn off Edit mode when using “Edit directly in a cell”
Private Sub Worksheet_Calculate()
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False 'should be part of Change macro
Application.EnableEvents = True 'should be part of Change macro
Private Sub Worksheet_Deactivate()
Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Doesn't Worksheet_Activate work for you?
You need to have the event in the worksheet that is being activated - that is, if you put it is sheet 2, it will fire only when that sheet is opened.
This worked in sheet 2 of my workbook.
Sub worksheet_activate()
MsgBox "activated!"
End Sub