I have spent quite a bit of time work ing on a project under the assumstion that each sheet in an excell book would use an instance of the module I was writing. I have multiple sheets that are all the same template but the sheets are specific to the type of data being stored. In the module I have setters and getters however, I was expecting the getters on a given sheet to only access the varibles set by the setters on that same sheet (an instance of the module). As it turns out all of the sheets are using the same instance of the module and the setters are over-riding each other, so that only one sheet has acurate results calculated by the module. I don't want to get into TMI but the setters provide data that is used to format the raw data provided by the getters. Is there a way to make each sheet have an instance of the module with out having to code each and every sheet. What I mean by that is, when the operator has new set of relults to be stored and processed they just copy the sheet in excell and put the data on that new sheet. I don't want the operator to need to modify the code. I have tried to explain this but I am not sure I did a good job explaining it properly. Is there a way to make separate instances of the module?
You can do this with a class module instead of just a module. One difference is that you'll need to create an object on each worksheet as the same type as the class, but intantiate a separate instance of the object each time.
Depending on how you scope this class (using Dim) will determine where it is availabe.
This is a pretty good reference: http://www.cpearson.com/excel/classes.aspx
If you have multiple worksheets of the same "type" (same kind of data and layout etc), then a good approach (as suggested by others here) is to place the code which "manages" the sheet into a class module, and have a property in that class which can hold a reference to a specific worksheet (which could be the activesheet, or the sheet you're currently working with).
Eg: a simple class clsSheet with a single "Title" property which maps to a specific cell:
Option Explicit
Private m_sht As Worksheet
Public Sub Init(sht As Worksheet)
Set m_sht = sht
End Sub
Public Property Let Title(t As String)
m_sht.Range("A1").Value = t
End Property
Public Property Get Title() As String
Title = m_sht.Range("A1").Value
End Property
Usage:
Dim shtObj as New clsSheet
shtObj.Init ActiveSheet
shtObj.Title = "my title"
msgbox shtObj.Title
Your existing code should likely map over fairly easily into the new class module: you just need to make sure to reference m_sht instead of (eg) ActiveSheet when working with Ranges etc.
Related
I try to access public variables in other Excel files (which are referenced) without hard coding the excel file/VBA project and need help in achieving this. I need the qualification as multiple files with similar variables can be open.
Assume you have a VBA project Test(Test.xlsb) which defined a public variable myVar.
In another VBA project (which has a reference to Test) I can access this variable , e.g.
debug.print Test.myVar
However I have been unable to achieve the same without using the qualifier Test. I tried to use aworkBook, VBProject and Reference as qualifier but none of these options works out. I also cannot assign the object addressed by the code name to a variable. The code set myObj = Test throws a compiler error, while set mySheet = Test.Sheet1 does work.
Any help appreciated.
It appears that you need to define the public variable outside of the module, so to be placed in the worksheet object, outside of any functions.
A similar question is asked here Using Excel VBA variable for multiple workbooks
So, if you place Public myVar as String (assumng the type is string) in the external workbooks' ThisWorkbook and set your object to the workbook as you have been doing, you can then achieve this:
Dim wb As Workbook
Set wb = Workbooks("Test.xlsb")
MsgBox wb.myVar
So there are a few ways to set a worksheet in Excel.
set WS = Sheets("Name Here!")
set WS = WB.Sheets("Name Here!")
set WS = shNameOfTheSheetObject
However, there doesn't seem to be a way to do:
set WS = WB.shNameOfTheSheetObject
I'd like to know how, if it's possible, I can get this type of reference to work. I like being very, very explicit with my code (Perhaps too much so), and it'd be useful to know if I have multiple workbooks open that I'm handling.
I think there is a slight confusion on how the access via the code name works. When you get a worksheet via ThisWorkbook.Worksheets("SheetName") you query a collection on the workbook; when you use the code name, you get the corresponding component of the VBA project containing your project, which implements the Worksheet interface.
Both are the same object, but the resolution of the identifier takes a different path: a workbook does not know about the VBA components. Consequently, as #Comintern mentioned in the comments, you can only use the project name of the containing VBA project as further qualifier. That name is whatever you set it to via the project properties dialog. If you do not change it, it will always be VBAProject in Excel, which is not very helpful.
Let's say we have two workbooks identical with respect to the VBA functionality; however, the data-sets will be different. The VBA code stores some data on a collection variable to facilitate calculations. This variable is called via different modules inside the same workbook. As this variable also exists on the other workbook and these two workbooks should not share the same collection values, how can we make sure the call for collection will only pull the variable from its own workbook?
Will the declaration "Option Private Module" be adequate when declaring the collection variable? Such as:
Option Private Module
Public DataCol As New Collection
Thanks.
Yes.
Declaring the module as Option Private Module will restrict the scope of "Public" variables declared in that module to that specific project. This is similar to Friend scope in classes, and analogous to internal static in .NET.
Unlikely to be an issue...
Let's say you have two identical workbooks:
Book1.xlsm, and,
Book2.xlsm
...and both have a Public Variable setup identically, named X.
Unless you have explicitly set a Reference from Book1 to Book2, then Book1 cannot "see" X or other variables/constants/etc that exist within Book2.
For example, one way of setting a the reference would be if in Book1 you went Tools > References > Browse and selected workbook Book2.xlsm.
Even if you did set a reference between the workbooks, and both have a variable named X, Book1 will always look for an X in within itself before looking elsewhere. You would have to qualify the variable like:
Applications.Workbooks("Books2.xlsm").X
This applies to all references; If you have something in your workbook named the same as a "connected" reference, code running in your workbook "looks" first within the procedure, then within the module, then within the workbook, before looking externally to connected references.
Its very unlikely that VBA will refer to a variable in the wrong workbook.
If you often have two identical workbooks open, it's much more likely that you will accidentally write or execute code in the wrong workbook, (I've done it, it's annoying - especially when you close & delete the "garbage workbook", that you actually accidentally just wrote a bunch of code in!)
There should not be very many situations where you have two identical workbooks open; if this is regular practice there is probably a better way to organize your data storage process.
Ranges
Note that the same does not apply when referring to worksheet ranges, etc., with unqualified references.
For example, Range("A1") refers to whatever worksheet is "on top" (ie., the last workbook that was clicked, selected, or otherwise activated.
This is why it's important to qualify range references. One example of a fully qualified range reference is:
ThisWorkbook.Sheets("Sheet1").Range("A1")
Scope
This discussion falls into the category of Scope.
Read more about what scope is and how to use it to your benefit (and prevent problems) in these links:
Chip Pearson : Understanding Scope of Variables and Procedures in VBA
MS Office Support : Scope of variables in Visual Basic for Applications
analysistabs.com : Scope of Variables in Excel VBA
Truly Global Variables
Incidentally, there's also a way to create truly Global Variables, that can be referenced by other (non-Office) applications, and even after your application has closed and/or re-opened.
It takes some fairly advanced coding since it involves Windows API's, but Chip Pearson has the steps and sample code available here.
I am trying to create custom properties in a worksheet that the user can’t see. My reasons are the following:
avoid the CustomProperties collection (no direct access),
avoid using global variables (get dropped randomly on workbook save), or
using specific named cells on the worksheet as retrieving and inserting the values seem slow.
The code below seems to work, and I can work with all needed worksheet properties and methods of the created sht object. The downside is the loss of intellisense, which is not a problem for me.
Although this seems to work, my code now appears to randomly go unstable, and I can’t find any direct cause, other than the fact that I may have violated something.
I currently have 7 custom properties each in 5 worksheets.
Here is a code sample in the worksheet (at top):
Private pPassword As String
Public Property Get Password() As String
Password = pPassword
End Property
Public Property Let Password(Value As String)
pPassword = Value
End Property
And here is a code sample in a module:
Sub doSomething(currentSheetName as string)
Dim Password as String
Dim sht as object
Set sht = ThisWorkbook.Worksheets(currentSheetName)
Blahblahblah code
Password = sht.password
Blahblahblah code
End sub
Based on the suggestion from iled, I decided to create a blank worksheet, rename it to shtProperties, and add custom properties and methods to it. I can now use intellisense and change/retrieve properities from anywhere in the project. (example: shtProperties.Password = myPassword). When each sheet is activated, I simply clear out the custom properties of shtProperties, and reset to new properties of the activesheet. No more crashes. Thanks iled for the suggestion.
here's my goal: I need to declare a table that I would like to use first in a workbook and then in a different module. The table would always contain the same values and would be filled at the opening of the excel document, and I need to use it in a different module afterwards.
Now I have searched the proper way to implement this, and what I have found tells me to put a "public" in front of the variable in order to be able to use it in a different module. However I have to declare the table in the workbook of my project (not in a module), fill it with the values, and only then can I launch the module that will use that table.
Is it because I declare the table in the workbook that the "public" does not do the trick? Or is it simply impossible to do such things with vba?
Thank you for your time and your answers
-Declaration of the Table :
you can declare in any module using the keyword GLOBAL
GLOBAL table() as variant
-filling the table :
write your code inside the event Workbook_open() in thisWorkbook