Initializing cells and variables in worksheet when file is opened - excel

Is it possible to initialize worksheet variables and cells on opening file? I have some cells which needs to be initiated and some variables also in my code.
I have found a way to initialize cells using the workbook_open sub. But initializing variables (defined in sheet1) is not possible. Is there an equivalent of Userform_Initialize for worksheets? I don't want to use worksheet_activate as I need this to perform only once. Is there a work around for this?

Public variable
If you declare a public variable in sheet1
Public strA As String
then you can set a value in Workbook_Open() with
Worksheets("Sheet1").strA = "init"
Sheet1.strA = "init" 'Alternative … If you prefer the VBA name of the sheet
Private variable
If it is a private variable then you need a init sub within sheet1 which you call from Workbook_Open()
sheet1
Private strA As String
Sub MyInit()
strA = "init"
End Sub
workbook
Private Sub Workbook_Open()
Worksheets("Sheet1").MyInit
Sheet1.MyInit 'Alternative … If you prefer the VBA name of the sheet
End Sub

Related

VBA EXCEL: Apply sub to another worksheet from module

Trying to get a sub from a module to run within another worksheet. In a sense to stop using redundant ranges and keep it streamlined.
i.e.
-Module object-
Public sub method1()
{
Range("B4:B23") = ""
Range("C4:C23") = ""
'Empties these ranges...
}
-worksheet(s)-
sub project)
{
with sheet1 (or on any sheet 2,3,4,5... etc.)
Call module1.method1
'but this method only works on the module object, not in the context of the 'specified worksheet where it is needed
End with
Ideally to clear the data in ranges by using method1 in ANY worksheet. Every reference I tried just runs the module1 method without any effect or makes a useless reference to the method or worksheet. Just trying to save on code space by not writing direct references to every sheet which is formatted identical.
You can do this with a sub (ClearCells) that accepts a variable number of arguments via the ParamArray keyword. Then you can simply call the ClearCells sub and pass it the worksheet objects you want to clear the same ranges in, as in the DoClear sub. You can add more ranges as needed to the Union function in the GetRanges function.
Sub DoClear()
ClearCells Sheet1, Sheet3
End Sub
Sub ClearCells(ParamArray wkshts() As Variant)
Dim vWs As Variant
Dim ws As Worksheet
For Each vWs In wkshts
Set ws = vWs
GetRanges(ws).Clear
Next vWs
End Sub
Function GetRanges(ws As Worksheet) As Range
With ws
Set GetRanges = Union(.Range("B4:B23"), _
.Range("C4:C23"))
End With
End Function
Or assuming you are calling the method from the sheet you want to clear, you can just use ActiveSheet:
Public Sub Method1()
ActiveSheet.Range("B4:B23").Clear
ActiveSheet.Range("C4:C23").Clear
End Sub

automatically declare object class variable when creating new sheet in EXCEL

How do I declare a - private - class variable, when a new sheet is created using the tab. It has to be done automatically. I presume it is a good idea to declare it by using the
Private Sub Workbook_NewSheet(ByVal Sh As Object) -event from the Wookbook object
Sub Workbook_NewSheet(ByVal Sh As Object)
Dim sh.privateVariableOfSheet As Integer
Declare New sh.privateVariableOfSheet2 As Integer
End Sub
Both above 'declarations' fails of course!
And for the completeness, how to refer to this variable from an ordinary module.
Another method is to use the CustomProperties collection of the Worksheet. For example:
Option Explicit
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Sh.CustomProperties.Add Name:=Sh.Name, Value:=99
End Sub
You can then use it later in a sub-routine:
Option Explicit
Sub Test()
Dim var As Variant
var = ThisWorkbook.Worksheets("Sheet13").CustomProperties(1)
MsgBox var
End Sub
Let take some class - clsFoo - which has a single property of type Range with a getter and setter:
Private m_rngSomewhere As Range
Public Property Get SomeRange() As Range
Set SomeRange = m_rngSomewhere
End Property
Public Property Set SomeRange(rng As Range)
Set m_rngSomewhere = rng
End Property
Now, in the Workbook code module you have:
a Public variable which we will set as a Dictionary
a Sub to instantiate the Dictionary - could be called from Workbook_Open or something
an event handler for Workbook_NewSheet
The event handler creates a new instance of clsFoo and sets its property as a Range from the new Worksheet, and then adds that to the dictionary (and checks if it was already there for some new reason).
Code in Workbook module:
Option Explicit
Public SheetFooDic As Object
Public Sub InitialiseSheetFooDic()
Set SheetFooDic = CreateObject("Scripting.Dictionary")
End Sub
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Dim rng As Range
Dim cls As clsFoo
If Not SheetFooDic.Exists(Sh) Then
Set rng = Sh.Range("A1")
Set cls = New clsFoo
Set cls.SomeRange = rng
SheetFooDic.Add Sh, cls
End If
End Sub
This leaves you needing to simply use some Worksheet object as a key into the Dictionary in order to retrieve the Range you stored when the Worksheet was created. You can refer to the public Dictionary like this:
ThisWorkbook.SheetFooDic(ThisWorkbook.Worksheets("Sheet2")).SomeRange.Address
And get:
$A$1
You can store the address of the last selected cell as a string. So, asking for an object variable might be misleading. Either way, the easiest way is to declare a public variable (for example PrevCell As String, or As Range if you prefer or need the value) in each of your worksheets' code and set that variable in each sheet's Selection_Change event procedure.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
PrevCell = Target.Cells(1) ' or .Address
End Sub
Since you may find it useful to avoid recording selections of multiple cells my above procedure just records the address of the first cell which avoid errors that often crop up when a copy/paste action was performed on a sheet.
Now, when you insert a new sheet, don't use the Add method. Instead copy an existing sheet and clean it up the way you want. In this way the new sheet will already have the variable and the code that sets it.
I can't imagine your having need of the previous cell in any circumstance other than when the sheet is activated, but if my imagination is insufficient in this case, you might declare a global array with an element for each sheet, using the sheets' CodeName property for identification. This array would be set by the Selection_Change event procedure as demonstrated above, but when a sheet which isn't known to the array tries to register its latest selection it must be a new sheet and the array is extended to include it. The code to do so is inherited from other sheets by the same method described above.

How Do I populate a list box on a user from a range of cells in another workbook?

I currently am building a userform In excel vba and I want to populate one of my list boxes. I can't get it to populate from a range of cells in another workbook? The workbook reference and sheet name are correct, I copied and tested it from a working code. I tried setting the private sub to public but I get the same results
Private Sub UserForm_Initialize()
Shop_UserForm_ClockIn_Listbox_EmployeeName.List = Workbooks("hub.xlsb").Sheets("EmployeeNames").Range("f2").value
End Sub
This is the error message
Run-time error '381',
Could not set the List property. Invalid property array index
Your code is crashing because you are trying to assign a single value to the List.
This would work:
Private Sub UserForm_Initialize()
Shop_UserForm_ClockIn_Listbox_EmployeeName.List = Workbooks("hub.xlsb").Sheets("EmployeeNames").Range("f2:f3").value
End Sub
because it is assigning an array of values.
If you really just want to set the List to a single value, you could do either of the following:
Private Sub UserForm_Initialize()
Shop_UserForm_ClockIn_Listbox_EmployeeName.List = Array(Workbooks("hub.xlsb").Sheets("EmployeeNames").Range("f2").value)
End Sub
or
Private Sub UserForm_Initialize()
Shop_UserForm_ClockIn_Listbox_EmployeeName.AddItem Workbooks("hub.xlsb").Sheets("EmployeeNames").Range("f2").value
End Sub

Having a public variable available in userform / sheet objects

I've spent the last hour reading pages about variable scope in various flavours of excel vba, and could not find a definite documentation reference addressing my scope problem... even though i'm convinced it is such a classic. Oh well, here goes.
I've got a workbook that contains just one sheet and one userform. I have a list of students sitting in column 1 on my sheet. I would like to :
load this list up into some global Collection variable named students_list (i do this using a Workbook-Open() procedure in the ThisWorkbook object)
use the contents of students_list to initialize a listbox in my userform
remove elements from students_list when a button on my userform is clicked on
All i need is a variable that is seen from within my userform's procedures, as well as from inside the ThisWorkbook object.
I tried declaring it as public, global, in the sheet's code, in the userform, in ThisWorkbook, in a separate module dedicated to globals... I just can't seem to find the right way to have the students_list variable visible from everywhere.
What am I missing ? My apologies for this question that should be so basic and yet beats me :-/
Place the declaration of your Public variables inside a Module (use Insert / Module from the menu to create one, if you don't already have one). The scope will then extend to your whole project.
So in a Module (e.g. Module1) have:
Public foo As Integer
And in the worksheet (e.g. Sheet1) code have:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
foo = 4
MsgBox "foo set to 4"
End Sub
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
MsgBox "foo = " & foo
End Sub
If you were to place the declaration in the code for ThisWorkbook you would need to reference it as Thisworkbook.foo because, although it is accessible from any part of the code, it is a variable specific to that ThisWorkbook object.
So, in the code for ThisWorkbook have:
Public foo As Integer
And in the worksheet (e.g. Sheet1) code have:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
ThisWorkbook.foo = 4
MsgBox "foo set to 4"
End Sub
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
MsgBox "foo = " & ThisWorkbook.foo
End Sub

How can I get a reference to the worksheet an event was generated in?

In a worksheet I can attach code to an event like so:
Private Sub Worksheet_Calculate()
' .. code here
End Sub
How can I get a reference to the worksheet the event was generated in?
I want to have a 100% secure way, so I don't have to worry about code breaking when the name worksheet changes etc.
ActiveSheet is not correct because it is not guaranteed that any sheet is active upon (re)calculate.
You can use caller:
Application.Caller.Worksheet.Name
You can use the Codename property:
Private Sub Worksheet_Calculate()
Debug.Print Me.CodeName
End Sub
By default it's the same name as the worksheet, but you can change it in the Properties Window of the VBE - it's the Name property. The user can't change it. (Copying a sheet adds a number to the name, e.g., Sheet1 becomes Sheet11.
You can also use it in the workbook-level event:
Private Sub Workbook_SheetCalculate(ByVal Sh As Object)
If Sh.CodeName = "TheSheetICareAbout" Then
Debug.Print Sh.Name
End If
End Sub
It's hard to be more helpful as you don't say how you'll use the reference.
Some more information on code names:
http://www.ozgrid.com/VBA/excel-vba-sheet-names.htm

Resources