automatically close excel userform when change sheet - vba

I have a userform that automatically appears when a new sheet is created from a pivot table drilldown. I am trying to figure out how to have this userform automically close if the user navigates to any other sheet in the workbook.

You can use the SheetActivate event of the Workbook object to check the name of the worksheet that is active and take action accordingly. For example:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
If Sh.Name = "Sheet1" And UserForm1.Visible Then
Unload UserForm1
End If
End Sub
This event is available in the ThisWorkbook module of your Excel Workbook. I believe your UserForm will need to be Modeless for users to be able to change sheets while the form is visible.
You can read about the Workbook.SheetActivate Event here.

Related

How to close a userform and open another in VBA

I have one userform in the workbook "main.xlsm" that opens upon opening the workbook, on this userform i have one button that opens another workbook "test1.xlsm". In the "test1.xlsm" workbook i have a userform that opens upon opening the workbook, on this userform i have one button that closes this workbook and saves it. The idea was that after closing the userform from "test1.xlsm" i should get back to the userfom from "main.xlsm", but on the line Workbooks("test1.xlsm").Close it closes all the opened userforms
this is the code for the button from the userform in "main.xlsm" :
Private Sub CommandButton1_Click()
Workbooks.Open ("D:\test1.xlsm")
End Sub
this is the code for the button from the userform in "main.xlsm" :
Private Sub SaveButton1_Click()
Workbooks("D:\test1.xlsm").Close SaveChanges:=True
End Sub
After asking this question on an excel forum i got the suggestion to change the ShowModal property for each form to ShowModal FALSE. So i added the this argument to my code in ThisWorkbook:
UserForm1.Show vbModeless
in both userforms and it worked.

Command button to return user back to source workbook

We have a userform that pops-up and remains on top of all applications.
Since users are always working on multiple workbooks and applications, I want a button on the userform. On clicking this button the users should be returned to the workbook from where the userform is activated.
Let's say the userform is activated from Book1. On clicking the button, users should be returned to book1.
I'm just an excel beginner. Any help will be appreciated
Something like this should work in the code for the userform:
Public wbSource As Workbook
Private Sub CommandButton1_Click()
wbSource.Activate
End Sub
Private Sub UserForm_Initialize()
Set wbSource = ThisWorkbook
End Sub

How can I tell which workbook triggered an event?

I have a BeforeClose event in a workbook, however if the user closes the workbook when it is not the active workbook, e.g. from the taskbar, the script executes on the wrong workbook.
Is there a way to tell which workbook triggered the event and reference that workbook rather than ActiveWorkbook?
Private Sub Workbook_BeforeClose(Cancel As Boolean)
' Replaces default Save message box with custom one
' that includes request stats, warnings, and errors.
If Not ActiveWorkbook.Saved Then
UF_Stats.Show
If Not GlobalVariables.bAllowClose Then Cancel = True
End If
End Sub
Use ThisWorkbook instead of ActiveWorkbook – Vincent G

how to prompt sheet selection in excel vba

When a workbook has many sheets such as 100, you can activate the sheet quickly by right-clicking the arrows on the bottom left and then a prompts shows up by lets you choose which sheet you want to select. However, I want to be able to reach this prompt without clicking and using just the keyboard. So I want to create a simple macro where I can quickly pull up this prompt by assigning to something like ctrl+g. However, I do not know how to do this in vba.
Build your replica Activate form: Insert a userform into your project. Set its caption to "Activate". Add a label to it that says "Activate:". Add a Listbox and two buttons. Label one button Ok and the other Cancel.
In the UserForm_Initialize sub of the userform, Loop through the names of your sheets and add them to the listbox....something like:
Private Sub UserForm_Initialize()
Dim oSheet As Worksheet
For Each oSheet In Worksheets
ListBox1.AddItem oSheet.Name
Next
End Sub
Private Sub CommandButton1_Click()
Sheets(ListBox1.Text).Activate
Unload Me
End Sub
Private Sub CommandButton2_Click()
Unload Me
End Sub
Now in the ThisWorkbook section of the VBA Project, add a sub to show your userform:
Private Sub ShowActivateForm()
UserForm1.Show
End Sub
Go back to Excel and click the Macros button on the developer tab. You should see a macro named ShowActivateForm. Select it and click Options to assign it your desired hotkey.

Prevent user from deleting a particular sheet

Protecting workbook structure will prevent a user from deleting sheets. But how could I (using VBA) prevent a user from deleting a particular sheet I designate? I've seen examples where an active sheet is prevented from deletion by
Set mymenubar = CommandBars.ActiveMenuBar
mymenubar.Controls("Edit").Controls("Delete sheet").Visible = False
in its Worksheet_Activate event but that of course only works if the sheet is activated.
Is there a way to prevent a sheet from being deleted whether active or no?
For clarity: I'm fine with the user deleting some sheets, just not a couple of particular sheets.
So protecting workbook structure won't work.
As far as I can tell, it isn't possible to natively tag a single sheet as non-deletable; and there isn't an event that can be used to detect when a sheet is about to be deleted so the workbook can be protected preventively.
However, here is one potential workaround:
Protect workbook structure: this will, as you indicate, prevent all sheets from being deleted.
Create a "Controls" sheet. On this sheet, maintain a list of all sheet names (except those you don't want to be deletable).
If users want to delete a sheet, they will have to select its name on the Controls sheet (e.g. in a data validation drop-down menu) and press a "Delete" button. This button will call a macro that temporarily unprotects the workbook, deletes the selected sheet, and then reprotects the workbook.
Of course, the users will have to get used to this way of deleting sheets (as opposed to just right-click > Delete on the sheet's tab). Still, this isn't crazy complicated.
As for how to achieve #2 i.e. maintaining that list of sheet names, I suppose you could make use of a UDF like this one (must be called as an array formula):
Function DeletableSheetNames() As String()
Application.Volatile
Dim i As Long
Dim sn() As String
With ThisWorkbook
ReDim sn(1 To .Sheets.Count)
For i = 1 To .Sheets.Count
With .Sheets(i)
If .Name = "DataEntry1" Or .Name = "DataEntry2" Then
'Don't include it in the list.
Else
sn(i) = .Name
End If
End With
Next i
End With
DeletableSheetNames = sn
End Function
You cannot stop users to delete a particular sheet but you could use the Workbook_BeforeSave() event to prevent the workbook from being saved if a particular sheet is missing. The documentation on this event precisely shows how to allow saving a workbook only when certain conditions are met. See http://msdn.microsoft.com/en-us/library/office/ff840057(v=office.14).aspx
I can prevent a sheet from being deleted via the Worksheet_BeforeDelete Event as follows:
Private Sub Worksheet_BeforeDelete()
Call ThisWorkbook.Protect("password")
Call MsgBox("This sheet cannot be deleted.", vbExclamation)
End Sub
This protects all sheets from being deleted, however if you add some event code on the ThisWorkbook module like the following :
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Call ThisWorkbook.Unprotect("password")
End Sub
I will then be able to delete any other sheet as soon as it is selected.
Bear in mind, you will lose copy and paste functionality between pages due to the page unlocking when it is selected.
"there isn't an event that can be used to detect when a sheet is about to be deleted"
Since Office 2013, it is possible with the SheetBeforeDelete event.
I found this solution, similar to Dan's, on ExtendOffice.com. Put this code on the Worksheet's module:
Private Sub Worksheet_Activate()
ThisWorkbook.Protect "yourpassword"
End Sub
Private Sub Worksheet_Deactivate()
ThisWorkbook.Unprotect "yourpassword"
End Sub
When you activate the sheet in question, the whole workbook is protected, and the "Delete" option is grayed out. When you switch to any other sheet, the workbook is free again. It's subtle because you only notice the change when you go to the "safe" sheet.
Answer is by adding the following code to each of the protected sheets:
Private Sub Worksheet_Deactivate()
ThisWorkbook.Protect , True
Application.OnTime Now, "UnprotectBook"
End Sub
And the following to a Module:
Sub UnprotectBook()
ThisWorkbook.Unprotect
End Sub
Check https://www.top-password.com/blog/prevent-excel-sheet-from-being-deleted/ for credits accordingly.
The following disables the menu when you right click on tab. This stops the delete option being available.
Sub tab_rclick_off()
Application.CommandBars("Ply").Enabled = False
End Sub
The following turns the menu back on.
Sub tab_rclick_on()
Application.CommandBars("Ply").Enabled = True
End Sub
This option is simple, concise, prevents any issues with data entry/editing with protected sheets and can be called from anywhere in code, ie in conjunction with log on permissions can be given to some and not others etc. foremost yourself.
Maybe you could try to protect the structure of the workbook in SheetBeforeDelete.
See my example:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
ThisWorkbook.Protect Structure:=False
End Sub
Private Sub Workbook_SheetBeforeDelete(ByVal Sh As Object)
If Sh.Name = "Example" Then
ThisWorkbook.Protect Structure:=True
End If
End Sub
Here is another answer from mine base on the idea of #Jean-François Corbett
You can use 'Protect WB Structure' and Event 'Workbook_SheetBeforeDelete' to achieve this.
The result is that an dialog will pop up said "Workbook is protected and cannot be changed."
Private Sub zPreventWShDel(WSh As Worksheet, Protection As Boolean)
Dim zPassword As String: zPassword = ""
Dim zWB As Workbook
Set zWB = WSh.Parent
If Protection Then
zWB.Protect zPassword, Protection
Else
zWB.Protect zPassword, Protection
End If
'Stop
End Sub
Private Sub Workbook_SheetBeforeDelete(ByVal Sh As Object)
Call zPreventWShDel(Sh, True)
End Sub
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Call zPreventWShDel(Sh, False)
End Sub
Do not Call the code on Sheet Deactivation like below. Because it will deactivate it. Sequence of running is Event_SheetBeforeDelete -> Event_SheetDeactivate.
Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
Call zPreventWShDel(Sh, False)
End Sub
I created a different approach to this.
On the sheet(s) you want protected, add this code:
Private Sub Worksheet_BeforeDelete()
ThisWorkbook.Worksheets("Unprotect Workbook").Visible = True
ThisWorkbook.Worksheets("Unprotect Workbook").Activate
ThisWorkbook.Protect
End Sub
Create the ("Unprotect Workbook") sheet and make the visibility: xlSheetVeryHidden
on the "Unprotect Workbook" sheet add a button or shape that you can assign a macro to.
on the "Unprotect Workbook" sheet, add this code:
Sub unprotectThisWorkbook()
ThisWorkbook.unprotect
ActiveSheet.Visible = xlSheetVeryHidden
End Sub
Assign the sub you added, "Sub unprotectThisWorkbook()", to the button on the "Unprotect Worksheet" sheet
When you delete the sheet you protected, the workbook is protected and it takes you to the unprotect worksheet as a notice to the user and as a way to unprotect the workbook. Once the button is clicked, the workbook is unprotected and the "unprotect sheet" is hidden again.
This will work for any sheet you want to protect.