Userform visibility - excel

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.

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...

Worksheet.Activate does not trigger the Worksheet_Activate event

I created macros in vba but they don't work.
In the ThisWorkbook code I wrote:
Private Sub Workbook_Open()
Worksheets("Sheet1").Activate
End Sub
In the code of Sheet1 (Sheet1) I wrote:
Private Sub Worksheet_Activate()
MsgBox ("hello")
End Sub
but when I open the file nothing happens ...
If Sheet1 is already active when you open the workbook, then
Worksheets("Sheet1").Activate
does exactly nothing. Because you cannot activate what is already active.
Test it by adding 2 Sheets Sheet1 and Sheet2. Then select Sheet2 save the file and close it. Now open it again, it will run Worksheets("Sheet1").Activate and this will trigger the Worksheet_Activate properly.
Also note that MsgBox ("hello") should be without parenthesis as it does not return a value to a variable: MsgBox "hello"
An alternative solution is:
Write in a module:
Public Sub Sheet1_Activate()
MsgBox "Sheet1 Activate"
End Sub
In Sheet1 write:
Private Sub Worksheet_Activate()
Sheet1_Activate
End Sub
And in ThisWorkbook write:
Private Sub Workbook_Open()
If ThisWorkbook.ActiveSheet.Name = "Sheet1" Then
Sheet1_Activate
Else
ThisWorkbook.Worksheets("Sheet1").Activate
End If
End Sub
The idea is to have a new procedure Sheet1_Activate that takes the actual code and is triggered by the Worksheet_Activate as well as by the Workbook_Open in case the sheet is already the active sheet.
Sub auto_open()
MsgBox "HueHueHue"
End Sub
You can't activate the same thing twice.

Get the last deactivated worksheet

Private Sub Worksheet_Deactivate()
Msgbox(worksheet.Name)
End Sub
How can I get the last deactivated Sheet once I press on any sheet other than the sheet of interest.
You firstly create a Public variable on top of ThisWorkbook code module (in the declarations area):
Public lastSheetName As String
Put the next code in the Workbook_SheetDeactivate event (also in ThisWorkbook code module):
Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
lastSheetName = Sh.name
End Sub
Then you can return the name of the last deactivated sheet with a simple Sub or inside another event code. Try pasting the next code in a standard module and run it. Of course, after you deactivated at least a sheet...
Sub LastDeactivatedSheet()
MsgBox ThisWorkbook.lastSheetName
End Sub
3.a Or put the same code in the Workbook_SheetActivate event , in this way:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
MsgBox "You are coming from " & ThisWorkbook.lastSheetName
End Sub
Each time you activate another sheet, it will inform you from which sheet you come...

How to run a macro when a cell updates through refreshing of data from web?

When the column is refreshing nothing is happening but when I go to the cell and change the value then it is changing.
I want when cells update through refresh it should run.
The column updates but the code doesn't trigger the macro.
Also tried Worksheet_Calculate().
The column is linked with online stock data from NSE website.
Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("B:B")) Is Nothing Then
MsgBox "Cell Value Changed"
Call MyMacro()
End If
End Sub
On internet just told to use Worksheet_Calculate().
Also if trying to update the cell which is equal to a cell in Range("B:B"), the value changes but macro doesn't trigger.
Maybe give this a try by using Workbook_SheetChange instead of Worksheet_Change
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("B:B")) Is Nothing Then
MsgBox "Cell Value Changed"
Call MyMacro()
End If
End Sub
Note that you need to put your code in ThisWorkbook and not your module
Edit : to test the Answer :
Sub TryMe()
For i = 1 To 100
Cells(2, 2).Value = i
Next
End Sub
TryMe Should be added inside a module like below
Workbook_SheetChange hould be added inside ThisWorkbook like below
When we execute test module we should have stuff like this:
and so on..
EDIT 2 If Value are changed by formula :
Give this a try :
This code should be placed in the sheet you are using (in my exemple Sheet1)
Private Sub Worksheet_Calculate()
Dim rng As Range
Set rng = Range("B:B")
If Not Intersect(rng, Range("B:B")) Is Nothing Then
MsgBox "Cell Value Changed"
End If
End Sub
In a Module execute this code once :
Sub TryMe()
ActiveWorkbook.RefreshAll
Application.Calculation = xlAutomatic
End Sub
then this should work
You can use events of QueryTable object behind the table linked to a web source. To do that, you first need to create a class module. Let's call it clsQryTebleEvents. In that module place a WithEvents variable of type Excel.QueryTable and set it to the QueryTable for which you want to capture events. Here's the code for clsQryTableEvents:
Option Explicit
Private WithEvents qryTable As Excel.QueryTable
Private Sub Class_Initialize()
'QueryTable connected to a webpage is on Sheet1, and it's the only table on that sheet, so we can access it with ListObjects(1)
Set qryTable = Sheet1.ListObjects(1).QueryTable
End Sub
Private Sub Class_Terminate()
'Free Memory
Set qryTable = Nothing
End Sub
'You can use other events as well
Private Sub qryTable_BeforeRefresh(Cancel As Boolean)
MsgBox "Refresh is about to start!", vbInformation
End Sub
Next, you need to initialize a variable of this class. You can declare a Public variable inside a standard module and the use Workbook_Open event to instantiate it. Code in a standard module:
Option Explicit
Public objQryTable As clsQryTableEvents
Code in ThisWorkbook:
Option Explicit
Private Sub Workbook_Open()
Set objQryTable = New clsQryTableEvents
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
'Free memory
Set objQryTable = Nothing
End Sub
All done! Next time you open the workbook, the objQryTable will be initialised and will start listening to refresh events.

Excel VBA: call sub when change to another worksheet

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

Resources