Excel VBA: call sub when change to another worksheet - excel

Pretty basic question. I'm looking for a sub which will be triggered when the user changes the active worksheet to a certain worksheet (calles worksheet3).
Doing some research in the internet could not help me, unfortunately.
The event sub I am looking for should be very similar to the workbook_open sub. Obviously it is triggered everytime the workbook opens. So my question: is there a similar event sub which is triggered when I open a certain worksheet? Kind of like worksheet3_open?

You can use the Worksheet_Activate() event in the Worksheet3 code page.
Choose your worksheet by double clicking in the PRoject window:
From the drop down at the top, choose "Worksheet"
From the second drop down just to the right choose "Activate".
You'll have a new subroutine created called Worksheet_Activate() that will fire every time that tab is activated by the user.
You can then call your subroutine inside of that code so it runs as well.

Private Sub Workbook_SheetActivate(ByVal Sh As Object)
End Sub
or
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
End Sub
Nothing on the net????? :)

Place the following code under your workbook:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
If Sh.Name = "worksheet3" Then
YourSub
End If
End Sub

Related

How can I manually trigger the Activate event of a worksheet in VBA?

I have a worksheet with:
Private Sub Worksheet_Activate()
MsgBox "Ran"
End Sub
I have a button on my toolbar that I made. What I want it to do is trigger this method on the currently selected WorkSheet.
I figured I could do Call ActiveWorksheet.Activate or Call Worksheet.Activate but while these seem to execute without errors, the method is not called.
As a workaround I considered adding a public DoActivate method, but it seems a bit lame and I would likely have to fiddle with CallByName to get it to work (and developers would have to remember to implement this method on every worksheet).
Is there a reason why my Activate method is not calling manually via the above code, or a suitable workaround to get what I'm looking for?
Move your code to a new Sub called OnActivate
Private Sub Worksheet_Activate()
OnActivate
End Sub
Private Sub OnActivate() 'or Public if you call from another module
MsgBox "Ran"
End Sub
The Worksheet_Activate() event handler can be called manually from inside the module by Worksheet_Activate like any other sub (although this is IMO not a nice way to do it)
If you want to ensure all worksheets have the same method, then you can make them Implement an interface: e.g.
Class module: IActivateHandler
Public Sub OnActivate()
End Sub
Then in Sheet1, 2, 3 etc:
Implements IActivateHandler
Private Sub IActivateHandler_OnActivate()
MeOnActivate
End Sub
Private Sub Worksheet_Activate()
MeOnActivate
End Sub
Private Sub MeOnActivate()
MsgBox "Ran"
End Sub
And the button:
Private Sub Button1_Click()
Dim sheetToCall As IActivateHandler
' Debug.Assert TypeOf ActiveSheet Is IActivateHandler
Set sheetToCall = ActiveSheet 'gets the IActivateHandler of the sheet, ensuring it is defined. Will error if it isn't
sheetToCall.OnActivate 'runs the IActivateHandler_OnActivate() method of sheet1
End Sub
You can call the activating event of any active sheet (without knowing its name) in this way:
Create the next event in ThisWorkbook code module. Or, simple copy the following code. Take care that such an event does not already exist:
Public Sub Workbook_SheetActivate(ByVal Sh As Object)
MsgBox Sh.Name & " activated..."
'the necessary code here...
End Sub
Then, call it from a standard module in the next way:
ThisWorkbook.Workbook_SheetActivate ActiveSheet
If you want excepting some sheets, you can adapt the event code to do it:
If sh.Name <> "MySheetName" then
MsgBox Sh.Name & " activated..."
'the necessary code here...
End if
If many sheets should be excepted, an array of sheet names should be built and use Application.Match to differentiate between the sheets to use their event and the other ones.
Edited:
If you need a piece of code written in an add-in (or any macro enabled workbook), able to catch the Activate event of a sheet in any (other) open workbook, you should proceed in the next way:
Copy the next declaration on top of the add-in ThisWorkbook code module (in the declarations area):
Public WithEvents appEvHandler As Application
In the same code module, copy the next code:
Private Sub appEvHandler_SheetActivate(ByVal sh As Object)
If sh.Parent.Name <> ThisWorkbook.Name Then
MsgBox sh.Parent.Name & " workbook, sheet " & sh.Name & " activated..."
Else
Debug.Print "changed in this workbook..."
End If
End Sub
Copy also the next Sub, which will activate the event:
Sub activateAppEvHandler()
Set appEvHandler = Application 'It can be placed in `Workbook_Open` event to be run when workbook opens
End Sub
If you want to inactivate it (for some reason...), use the next Sub:
Sub InactivateAppEvHandler()
Set appEvHandler = Nothing
End Sub
Please, test it and send some feedback. I must confess I am not sure I correctly understood what you need. I was asking for a scenario to be followed, but I tried imagining that this is what you want...

I have a function in excel VBA which takes input from user using textbox

I have written a macro that takes input from user and returns a cell data.
Is there any way that triggers the process to run from macro
That is the the inputbox opens up directly with one click without having to go to VBA and run it?
Put this in Worksheet code:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Call showMsg
End Sub
Put this in your module:
Sub showMsg()
Dim data As String
data = InputBox("Hello", "Title")
End Sub
You can use other worksheet or workbooks events as well e.g
(It will run macro whenever you open file)
Private Sub Workbook_Open()
Call showMsg
End Sub

Why can I not use Private Sub Workbook_Open(ByVal Sh As Object) any workaround?

I want the code to run when workbook loads. I am using Private Sub Workbook_Open(ByVal Sh As Object), but it throws an error "Procedure error does not match description of event" - Any ideas please, as Private Sub Workbook_SheetActivate(ByVal Sh As Object) works.
But I want code to run when workbook opens.
I know that Private Sub Workbook_Open(ByVal Sh As Object) is not allowed.
See my comment, as previously stated by a few, you can't just change a signature of a standard Excel event handler.
However, you can work within that handler and get access to the worksheets within the workbook.
Private Sub Workbook_Open()
Dim objSheet As Worksheet
For Each objSheet In ThisWorkbook.Sheets
' Do something with the sheet that you're interested in.
Next
End Sub
I hope that helps.

Userform visibility

My userform opens other workbooks but then remains over them. Can this be stopped? This also happens when clicking between open workbooks.
the code below works for me when activating a different sheet but not a different workbook.
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
If Sh.Name <> "HTFD" And Flight_Deck.Visible = True Then
Unload Flight_Deck
End If
If Sh.Name = "HTFD" And Flight_Deck.Visible = False Then
Flight_Deck.Show vbModeless
End If
End Sub
Since you were using code in the Private Sub Workbook_SheetActivate(ByVal Sh As Object), I'm assuming you know how to insert code into the ThisWorkbook Module. As well as the Workbook_SheetActivate there are also subs for the workbook activation and deactivation events.
Private Sub Workbook_Activate()
If Sh.Name = "HTFD" Then
Flight_Deck.Show vbModeless
End If
End Sub
Private Sub Workbook_Deactivate()
Flight_Deck.Hide
End Sub
You should also be able to insert code into the module for a particular sheet. If you do that, you could use the following code in the sheet module for which you want the userform to show, and since the code would only be activated when that particular sheet is activated, you won't have to do a check on the sheet's name. (The check on the sheet's name is required for the workbook_Activate code because that runs whenever the workbook is activated, not just for a particular sheet.)
Private Sub Worksheet_Activate()
Flight_Deck.Show vbModeless
End Sub
Private Sub Worksheet_Deactivate()
Flight_Deck.Hide
End Sub
Of course, with this setup, the userform will always be visible on that sheet in that workbook whenever anyone opens it. If you only want to initialize the userform after other code has ran, and/or you want to specifically close the userform at times; you should check if the userform is currently loaded.
This code was posted by gijsmo (April 24th, 2011, 14:08) on ozgrid.com (response #2)
Function IsUserFormLoaded(ByVal UFName As String) As Boolean
Dim UForm As Object
IsUserFormLoaded = False
For Each UForm In VBA.UserForms
If UForm.Name = UFName Then
IsUserFormLoaded = True
Exit For
End If
Next
End Function 'IsUserFormLoaded
Explanation
Using the Flight_Deck.Hide/Flight_Deck.Show combination should retain any information on the userform for when it's shown next. Exception: if the code is paused/stopped in between hiding and showing i.e. for debugging, the information will be lost.
Private Sub Worksheet_Activate() and Private Sub Worksheet_Deactivate() are triggered when the active worksheet changes, but the active workbook does not. Private Sub Workbook_Activate() and Private Sub Workbook_Deactivate() are triggered only when the active workbook changes. When either Private Sub Workbook_Activate() or Private Sub Workbook_Deactivate() are triggered, then neither Private Sub Worksheet_Activate() nor Private Sub Worksheet_Deactivate() are activated.
Thus, since you only want the userform to show over one particular sheet in one particular workbook, you will need code in both places.
Also, with this logic, I don't think it's necessary to check the status of Flight_Deck.Visible; however, I could be wrong.

Open UserForm from any worksheet

I have a Workbook with the following code in Sheet1:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Excel.Range, Cancel As Boolean)
UserForm1.Show
End Sub
When I double click on a row, this opens my Userform but only if I'm on Sheet1.
How can get this to work for any active worksheet without adding it to every sheet?
If you want your code to be executed for the active sheet in your workbook, then you need to remove the code you have for the single sheet and do the following:
Open the VBA Editor and find the ThisWorkbook object under "Microsoft Excel Objects".
Edit it and add the following code inside it:
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
UserForm1.Show
End Sub
This means that the double-click event will be detected for all sheets in the workbook. If you leave your code in the sheet, the sheet event gets fired first and then the workbook one.

Resources