I would like my macro to run automatically if it detects that the user inserted a new worksheet into the workbook (existing & new).
Sub macro_run()
Dim Newws As Worksheet
Dim wb As Excel.Workbook
Dim sample1 As Worksheet
With ThisWorkbook
Set sample1 = .Sheets("Template")
For Each wb In Application.Workbooks
If Newws = sample1 Then
Application.Run "PERSONAL.XLSB!Opennew"
End If
Next wb
End With
End Sub
As mentioned in the comments you need to handle WorkbookNewSheet at Application level.
'-- Create a new Class.
'-- Name it clsGlobalHandler.
'-- Following Code goes in that class
'/ Create a variable to hold Application Object
Public WithEvents xlApp As Application
'/ Handle NewSheet event. Invoked whenever a new sheet is added
Private Sub xlApp_WorkbookNewSheet(ByVal Wb As Workbook, ByVal Sh As Object)
MsgBox Sh.Name
End Sub
'-- Create a new module
'-- Following code goes there
Option Explicit
'/ A new instance for the Class that we created.
Dim oGh As New clsGlobalHandler
'/ To start tracking sheet additions call this method first. Most likely in WorkBook_Open
'/ Once called any new sheet across the app insatnce will be intercepted.
Sub SetGlobalHandler()
Set oGh.xlApp = Application
End Sub
'/ Call this to remove the global handler.
Sub ResetGlobalHandler()
Set oGh.xlApp = Nothing
End Sub
Related
I can't seem to figure out why my UserForm code fails at the very end of the procedure. The end result is perfect. Here is what I'm trying to accomplish...
1) Using the active workbook, the procedure identifies the sheet names in the workbook and displays them in the Listbox, which is located on the userform.
UserForm Pic
2) Once the sheet is selected, the user will click the "Select Sheet" CommandButton
3) The CommanButton activates the sheet, renames the sheet to "LegacyBillHist"
4) The form closes, and cell A2 is selected
I get the Run-time error 91 message on the very last line.
I've tried a few different approaches to resolve the issue, but I can't seem to figure this one out using the info in StackOverflow and other sites. Any help would be greatly appreciated.
Here is the code..
Option Explicit
Private Sub CommandButton1_Click()
Worksheets(ListBox1.Value).Activate
ActiveSheet.Name = "LegacyBillHist"
Unload BillSelect
End Sub
Public Sub UserForm_Initialize()
Dim wb As Workbook
Dim sh As Worksheet
Set wb = ActiveWorkbook
For Each sh In wb.Sheets
ListBox1.AddItem sh.Name
Next sh
Load BillSelect
BillSelect.Show
sh.Range("A2").Select
End Sub
Mathieu
Great info. I ended up changing my approach significantly. However, I have a different problem that I haven't been able to figure out. Here is the Code...I got it from the article you referenced...
Option Explicit
Private cancelled As Boolean
Public Property Get IsCancelled() As Boolean
IsCancelled = cancelled
End Property
Private Sub CommandButton2_Click()
OnCancel
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
OnCancel
End If
End Sub
Private Sub OnCancel()
cancelled = True
Hide
End Sub
Private Sub CommandButton1_Click()
Dim wb As Workbook
Dim ws As Worksheet
Worksheets(ListBox1.Value).Activate
ActiveSheet.Name = "LegacyBillHist"
Set wb = ActiveWorkbook
Set ws = wb.Sheets("LegacyBillHist")
ws.Activate
ws.Range("A1").Select
UserForm1.Hide
End Sub
Private Sub UserForm_Initialize()
Dim wb As Workbook
Dim lastSheet As Worksheet
Dim sh As Worksheet
Set wb = ActiveWorkbook
For Each sh In wb.Worksheets
ListBox1.AddItem sh.Name
Set lastSheet = sh
Next
UserForm1.Show
End Sub
Everything works great up to the End Sub under the CommandButton1 routine. Instead of hiding UserForm1, it reopens the form.
I tried incorporation the code you provided, but it keeps cycling through until I get the Out of stack space error 28. Perhaps I'm not putting it in the correct sequence.
Private Sub UserForm_Initialize()
Dim wb As Workbook
Dim lastSheet As Worksheet
Dim sh As Worksheet
Set wb = ActiveWorkbook
For Each sh In wb.Worksheets
ListBox1.AddItem sh.Name
Set lastSheet = sh
Next
With New UserForm1'<~ forms are objects too; avoid using their global state
.Show
End With
End Sub
Appreciate all the help.
For Each sh In wb.Sheets
ListBox1.AddItem sh.Name
Next sh
The object sh only ever makes sense inside the For...Next loop.
In theory, as per language specifications, sh should indeed still hold a reference to the last item in the iterated collection:
When the <for-each-statement> has finished executing, the value of <bound-variable-expression> is the data value of the last element in <collection>.
https://learn.microsoft.com/en-us/openspecs/microsoft_general_purpose_programming_languages/MS-VBAL/b132463a-fd25-4143-8fc7-a443930e0651
However it appears when VBA was implemented, that bullet point wasn't: a For Each variable that is Nothing before the loop, will still be Nothing after the loop - and any member call made against Nothing will always raise error 91.
To be honest, I think it's better that way, too: it forces your code to be more explicit:
Dim lastSheet As Worksheet
Dim sh As Worksheet
For Each sh In wb.Worksheets '<~ note: 'Sheets' collection can have charts, not just worksheets
ListBox1.AddItem sh.Name
Set lastSheet = sh
Next
With New BillSelect '<~ forms are objects too; avoid using their global state
.Show
End With
lastSheet.Activate
lastSheet.Range("A1").Select
Note: Newing-up the BillSelect can surface hidden bugs in your form code, read this article for more info.
The Initialize handler shouldn't be doing this work, especially if you don't New up the form and use its default instance: you do not control when that default instance gets created, VBA does.
Given this code:
UserForm1.Show
If no code ever referred to UserForm1 before, then the Initialize handler runs at UserForm1, before the reference is returned to the caller and the .Show call runs; if the form's default instance isn't destroyed, then the next time the form is shown, the initialize handler will not run again, because the instance is already initialized.
Consider implementing your logic in the Activate handler instead, which will make the logic run after the .Show call is entered, and every time the form is activated (and since that's a modal dialog, that means every time the form is actually shown).
I have a class module that acts as a Worksheet_Change event for an external workbook. I am reworking my project, and the current setup only allows for one external workbook sheet_change event. I would, however, like this event listen for changes on multiple workbooks.
The amount of workbooks is unknown until midway in the code, so I can't create a predetermined amount of classes for each workbook.
Module Functions:
Dim oWb2 As New UpdaterUnkowns
Public Function
'Code...
Set oWb2.Workbook = newfile
End Function
Class module UpdaterUnknowns:
Public WithEvents m_wb As Workbook
Public CellVal As String
Public Property Set Workbook(wb As Workbook)
Set m_wb = wb
End Property
Public Property Get Workbook() As Workbook
Set Workbook = m_wb
End Property
Public Sub m_wb_SheetChange(ByVal Sh As Object, ByVal Target As Range)
'Code...
End Sub
Set oWb2.Workbook = newfile sets the workbook for the class module. Could I pass multiple workbooks to the event?
To handle every open workbook, you could do something like this:
Dim UU_collection As Collection
sub mysub()
Set uu_collection = New Collection
Dim wb As Workbook
For Each wb In Application.Workbooks
Dim oWb2 As UpdaterUnknowns
Set oWb2 = New UpdaterUnknowns
Set oWb2.Workbook = wb
uu_collection.Add oWb2
Next wb
End Sub
I need to set an excel file that is already open on the computer as the workbook object.
Dim wb As Workbook
Dim sh As Worksheet
Set wb = *the open excel file*
Set sh = wb.Worksheets("FlatFile-FichierPlat")
Set wb = Workbooks("yourWorkbookName")
You can just use GetObject to get a reference to the Excel application running it, and then iterate the workbook collection:
Dim wb As Workbook
Dim sh As Worksheet
Set wb = GetObject( ,"Excel.Application").ActiveWorkbook
Set sh = wb.Worksheets("FlatFile-FichierPlat")
For more information, see MSDN.
If your code is opening the file, then you already have the object reference:
Dim book As Workbook
Set book = Application.Workbooks.Open(path) 'reference is returned by the Open function
If the user can open the file at any arbitrary point in time, then you need to handle the Application.WorkbookOpen event - you can do that by declaring a Private WithEvents {name} As Excel.Application object variable at module scope in ThisWorkbook, and setting its reference to Application when ThisWorkbook opens, i.e. in the Workbook_Open handler:
Option Explicit
Private WithEvents app As Excel.Application
Private Sub Workbook_Open()
Set app = Application
End Sub
Private Sub app_NewWorkbook(ByVal Wb As Workbook)
'Wb holds the object reference for the new workbook that was created
End Sub
Private Sub app_WorkbookOpen(ByVal Wb As Workbook)
'Wb holds the object reference for the workbook that was opened
End Sub
I want to set ActiveWorkbook to a variable When workbook opens simultaneously ActiveWorkbook assign to a variable and that variable i can use in whole VBA excel project.
I tried to assigned in ThisWorkbook excel object on Workbook_open() function but it does not work.I provide that code below.
Private Sub Workbook_Open()
On Error Resume Next
Set WRBK = ActiveWorkbook
#If Mac Then
#Else
'unprotectVBProjProp
UnlockVBA ' Sujith ID: 12482
AddReferences ' Sujith ID: 12482
' protectVBProjProp
#End If
'MsgBox "xla Workbook opened"
Set eventInstance = New bwEvents
End Sub
So how can i set activeworkbook to a variable??
I am not so sure what are all the commands in the middle, like #If Mac Then , and UnlockVBA.
If you want to set the ActiveWorkbook to object WRBK, you will need to define WRBK in a regulare module as Public, and then use something like the code below:
Code in ThisWorkbook Module
Private Sub Workbook_Open()
Set WRBK = ActiveWorkbook
TestWorkbookName ' call sub <-- this is just to test the the workbook was assigned correctly
End Sub
Code in Regular Module
Option Explicit
Public WRBK As Workbook
Sub TestWorkbookName()
MsgBox WRBK.Name
End Sub
I am trying to clear Print Area And Autofilter when excel opens:
Am total novice in Excel vba so Assmebled the followingcode from googling around
This code I have put in ThisWorkbook of Personal.xlsb in the XLstart folder and ofcourse the macro security has been set to enable all macros
Option Explicit
Public WithEvents xlApp As Excel.Application
Private Sub Workbook_Open()
Set xlApp = Application
End Sub
Private Sub Workbook_Close()
Set xlApp = Nothing
End Sub
Private Sub xlApp_WorkbookOpen(ByVal Wb As Workbook)
Application.EnableEvents = False
Call ClrPrntArea
Application.EnableEvents = True
End Sub
Here is the ClrPrntArea
Sub ClrPrntArea()
Dim ws As Object
For i = 1 To ActiveWorkbook.Worksheets.count
With Worksheets(i)
.PageSetup.PrintArea = ""
.PageSetup.FitToPagesWide = 1
End With
Next
End Sub
I will also be putting another macro call to module in personal xlsb for resetting the autofiter once above starts working..Any inputs will be really helpfull
in PERSONAL.xlsb, module ThisWorkbook, try the below; it's nearly the same code as in your request, with some modif's:
application object declared Private
event routine uses the local WB object variable handed over as parameter, instead of the ActiveWorkbook object
replaced For ... Next by For Each ... Next and working with local object variables
trap processing of PERSONAL.xlsb itself
Once you're happy remove all the MsgBox statements (and the Else), they are just to show what is happening and when.
Private WithEvents Excel_App As Excel.Application
' runs when Excel_App encounters a Workbook_Open() event
Private Sub Excel_App_WorkbookOpen(ByVal WB As Workbook)
Dim WS As Worksheet
If WB.Name <> "PERSONAL.xlsb" Then
MsgBox "PERSONAL.xlsb: Excel_App_WorkbookOpen(): " & WB.Name
For Each WS In WB.Worksheets
WS.PageSetup.PrintArea = ""
WS.PageSetup.FitToPagesWide = 1
If WS.FilterMode Then
WS.ShowAllData
End If
Next
Else
MsgBox "PERSONAL.xlsb: Excel_App_WorkbookOpen(): myself"
End If
End Sub
' runs when PERSONAL.xlsb is opened
' assign current Excel application to object variable Excel_App
Private Sub Workbook_Open()
MsgBox "PERSONAL.xlsb: Workbook_Open()"
Set Excel_App = Application
End Sub
Note:
When the event handler doesn't start when you double-click an Excel file (e.g. on your desktop), close all Excel applications and inspect the task manager for additional orphaned Excel processes which need to be killed. It happened to me while playing around with this code