Workbook event not working in new workbooks - excel

I'm totally new to Excel_vba, I'm trying to make kind of simple macros in excel.
I'm intending to make a macro: If active sheet is the first sheet in the workbook, move to last activated sheet. Else if, move to the first sheet in the workbook.
I googled and I added the code below to 'thisworkbook' module in addin (.xlam).
Private Sub Workbook_SheetdeActivate(ByVal Sh As Object)
Set LstSht = Sh
End Sub
In next, I create general module in addin(.xlam), added the code below.
Global LstSht As Worksheet
Sub GoToLast()
LstSht.Activate
End Sub
Private Sub Sht_tab()
If ActiveSheet.Index = 1 Then
Call GoToLast
ElseIf ActiveSheet.Index <> 1 Then
ActiveWorkbook.Sheets(1).Activate
End If
End Sub
The problem is, even though I move to any other sheet in workbook, sheetdeactivate event is not working, so LstSht object is not defined.
The event: sheetdeactivate only works in specific workbook? I want to assign a shorcut to this macro and use it in other workbooks, but I can't make it run.
Thank you for all in advance.

Related

How do I amend this VBA so it runs when a specific worksheet is selected?

I have this VBA written. Essentially what it does is; I've used 'Define Range' ("Test") on a few cells in a worksheet. The VBA makes sure that whenever the workbook is opened, it automatically zooms in to fit that range. Right now, I think it only triggers when the workbook is opened, and it gives an error message if that worksheet is not selected when the workbook is opened. Now, I would like it to run only if the specific worksheet is selected. I've literally copied it from someone else so don't really know how I would amend this...
Thanks in advance!
Private Sub Workbook_Open()
Range("Test").Select
ActiveWindow.Zoom = True
Cells(1, 1).Select
End Sub
Zoom & Scroll To Cell When Worksheet Is Activated...
... and if the worksheet is active when the workbook is opened.
It is assumed that the range is of Workbook scope.
ThisWorkbook Module
Option Explicit
Private Sub Workbook_Open()
Const WorksheetName As String = "Sheet1"
If ActiveSheet.Name = WorksheetName Then SelectMyRange
End Sub
Sheet Module, e.g. Sheet1...
... where Sheet1 is the code name i.e. the name not in parentheses, e.g. Sheet1(Data), seen in the VBE Project Explorer window.
Option Explicit
Private Sub Worksheet_Activate()
SelectMyRange
End Sub
Standard Module, e.g. Module1...
... created by using Insert Module.
Option Explicit
Sub SelectMyRange()
Const RangeName As String = "Test"
With Range(RangeName)
.Select
ActiveWindow.Zoom = True
Application.Goto .Cells(1), True
End With
End Sub

Create Excel sheet with worksheet_change code [duplicate]

This question already has an answer here:
Excel vba add code to sheet module programmatically
(1 answer)
Closed last year.
I have code that creates a worksheet and the worksheet contains a table.
I then programmatically add an advanced filter to the table in the created worksheet.
This works fine, but the advanced filter does not refresh on change of the worksheet: A known issue.
The standard solution is to put code behind the worksheet_change event so the filter is refreshed when the worksheet changes. This also works fine when I add this code manually.
But when I create a sheet I want to automatically create the code for the new sheets worksheet_change event. I don't know how to programmatically specify code for my new sheet in the worksheet_change event.
Is this possible? Or is there another way to accomplish this?
Maybe look at using this instead. It'll fire for all sheet changes and allows your code to work centrally ...
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
End Sub
You can create a class module with the event and hook that to your worksheets. So you can add a hidden sheet with all workbook names that you want to add that event to.
So if you programmatically add a new sheet you just need to add its name to that list.
So first add a sheet named MyClassSheets (you can make it hidden so no user sees it). And add some sheet names there:
So this means we want to run your worksheet_change event in Sheet2 and Sheet3 only.
Then we add a class module MyWsClass:
Option Explicit
Public WithEvents Ws As Worksheet
Private Sub Ws_Change(ByVal Target As Range)
MsgBox Target.Address(False, False) & " changed."
End Sub
This is the event we want to run. It just shows a message box which cell was changed. You need to adjust that to your wishes.
Finally we need to hook those events to the worksheets. So we add a normal module (non-class module) HookWsEvents:
Option Explicit
Dim MyWorksheets() As New MyWsClass
Public Sub HookEvents()
' get list of worksheets we want to add the class
With ThisWorkbook.Worksheets("MyClassSheets")
Dim MyClassSheets() As Variant
MyClassSheets = .Range("A1", .Cells(.Rows.Count, "A").End(xlUp)).Value
End With
ReDim MyWorksheets(UBound(MyClassSheets) - 1)
Dim i As Long
' add class to those worksheets
Dim Ws As Variant
For Each Ws In MyClassSheets
Set MyWorksheets(i).Ws = ThisWorkbook.Worksheets(CStr(Ws))
i = i + 1
Next Ws
End Sub
So now we just need to make sure that the procedure HookEvents is called everytime the workbook opens. So we add the following into ThisWorkbook:
Option Explicit
Private Sub Workbook_Open()
HookEvents
End Sub
After running HookEvents the event runs in every sheet that is listed in MyClassSheets.
If you now add a new worksheet that you want to add the event to, you just need to add it to the list in MyClassSheets and run HookEvents again. Therefore we can add a small helper procedure to our HookWsEvents module:
Public Sub AddWsToList(Ws As Worksheet)
With ThisWorkbook.Worksheets("MyClassSheets")
' add the worksheet name of Ws to the list in MyClassSheets
.Cells(.Rows.Count, "A").End(xlUp).Offset(RowOffset:=1).Value = Ws.Name
End With
End Sub
So now we can use the following code
' add a new worksheet as last worksheet
Dim NewWs As Worksheet
Set NewWs = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
' give it a name
NewWs.Name = "Sheet5"
' add it to the list of MyClassSheets
AddWsToList NewWs
' hook events to all sheets
HookEvents
to add a new worksheet and add the event to it.
You may want to add some error checking if a worksheet in the list of MyClassSheets does not exist anymore (was deleted) so your code does not thorw an unhandled exception in this case. I left this out to have the above explanation more clear.
If all your sheets have someting common in their name you don't need to maintain that MyClassSheets list. So for example if all the sheets you want to add the event to start with XYZ_ you just need to loop over all sheets in the HookEvents procedure and check if they start with XYZ_ to add them to the MyWorksheets array then. Resizing that array may be a bit more complicated then.

How to copy the code used in one sheet/tab in a workbook to create a report in another sheet/tab within the same workbook

Let's say, there is a report that has already been created in a sheet in a work book using macros. I want to create another report within the same workbook in another sheet(tab) with the exact same code in VBA which was used to create the report that has already been created. How do i copy and make those codes work in a different sheet to create a similar report?
Any code in the Worksheet itself should use Me to refer to itself - this way, it will work when copied/duplicated
Any other code should take the Worksheet to act on as a Argument, or as Module Level Object:
Option Explicit
Sub CreateReport(TargetSheet As Worksheet)
TargetSheet.Cells(1,1).Value = "Hello"
End Sub
or
Option Explicit
Public TargetSheet AS Worksheet
Sub CreateReport()
If TargetSheet Is Nothing Then Exit Sub 'In case the object has not been set
TargetSheet.Cells(1,1).Value = "Hello"
End Sub
Then you can duplicate a "master" template sheet, and run the macros to target it

Prevent user duplicating or adding new sheets to Excel manually

I am new in using Excel VBA. I have an Excel VBA code that will duplicate a certain sheet for n times. I want to prevent user from changing the workbook structure manually (such as adding new sheet, duplicating sheet, or moving sheet), but I still want the VBA to be able to run.
How should I do it?
I was hoping you could use UserInterfaceOnly but that appears to be only worksheet level and not workbook level - it locks the worksheet for users, but allows VBA code to make updates.
The only other way I can think of is to lock and unlock the workbook as needed:
Sub Test()
Dim wrkSht As Worksheet
UnlockWorkbook
Set wrkSht = ThisWorkbook.Worksheets.Add
LockWorkbook
End Sub
Sub LockWorkbook()
ThisWorkbook.Protect Password:="aaa", Structure:=True
End Sub
Sub UnlockWorkbook()
ThisWorkbook.Unprotect Password:="aaa"
End Sub

Calling Value From another macro

I have a userform which opens one of a list of worksheets. I want to create a macro that recognises the last sheet opened by the userform and then runs data validation based on data types in the sheet.
How can I reference the sheet opened so that it can be called later my the validation macro?
All help gratefully accepted!
You need to "remember" it in a Public variable.
In a Standard Module, near the top of that module, include:
Public LastSheet As Worksheet
and in the UserForm, code like:
Sub WithinUserForm()
Dim x As String
x = Application.InputBox(Prompt:="pick a worksheet", Type:=2)
Sheets(x).Select
Set LastSheet = ActiveSheet
End Sub
Finally within the DV macro:
Sub MacroForDV()
LastSheet.Select
End Sub

Resources