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.
Related
Normally when using the VBA editor, code autosuggests from available methods.properties for whatever object being referenced.
I'm trying to pull data from an Excel sheet into a Word document using a macro on the Word document. Whenever I try to use worksheets.activate, no autosuggestion for activate comes up, leading me to think it's not activating. Neither can I use it from a VBA script in Excel.
My script is still in it's beginning stages:
Sub Populate()
Dim doc As Document
Set doc = ActiveDocument
Dim appXL As excel.Application
Set appXL = CreateObject("excel.Application")
Dim partnerNames As excel.Workbook
Dim ihmNames As excel.Workbook
Set partnerNames = appXL.Workbooks.Open("D:/Database/Imports and Exports/Funder Credit Lists/2022-01 Partners.csv")
Set ihmNames = appXL.Workbooks.Open("D:\Database\Imports and Exports\Funder Credit Lists\2022-01 IHM.csv")
appXL.Worksheets(Left(partnerNames.Name, Len(partnerNames.Name) - 4)).Activate
Dim lastRow As Long
lastRow = appXL.Cells.Find(What:="*", After:=Range("C1"), SearchOrder:=xlByRows, searchDirection:=xlPrevios).Row
appXL.Range("A1").Resize(lastRow, 3).Select
'Insert Hero Names
Dim hero As Range
Set hero = doc.Range(Start:=doc.Bookmarks("Hero").Start, End:=doc.Bookmarks("Hero").End)
hero.InsertAfter ("IT WORKS!!!")
End Sub
The lastRow = appXL.Cells..... is causing a type mismatch, which I believe is being caused by the fact that appXL.Cells refers to the active sheet, and the ActiveDocument is a Word document.
That leads me to activating the sheet, but trying to do so causes the error "Subscript out of range," even if I explicitly type the sheet name.
appXL is an excel.Application object. Worksheets property belongs to Workbook class. You can use just Worksheets.(...) to refer the active workbook sheets. Same to property .Cells
Or you can define a new Workbook variable and handle it:
Dim wbXL as Workbook
set wbXL = ActiveWorkbook
wbXL.Worksheets(...).Activate
It seems you just need to add an Excel COM reference in Word VBA to be able to get auto-suggestions. From the Tools menu, choose References to display the References dialog box. The References dialog box shows all object libraries registered with the operating system. Scroll through the list for the application whose object library you want to reference. References whose check boxes are selected are used by your project; those that aren't selected are not used, but can be added. Select the object library reference in the Available References box in the References dialog box and choose OK. Your Visual Basic project now has a reference to the application's object library. If you open the Object Browser (press F2) and select the application's library, it displays the objects provided by the selected object library, as well as each object's methods and properties. In the Object Browser, you can select a class in the Classes box and select a method or property in the Members box.
So the problem was specifically the "After:=Range" portion in the appXL.Cells.Find function. I forgot that, since I'm working from a word doc and not an excel, I needed to specify appXL.Range instead of just Range. Oh the joy of finding out my weeklong problem was just a simple missed class specification.
That said, thanks to #Eugene for informing me of the Object Browser window. That was useful.
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.
Is it possible to have a new Excel sheet created and then VB code automatically put in that sheet?
Here is what I have done so far. A sheet called Template has the input for all of the information that users need to input. I have various checks to make sure that all fields are filled out and are filled out correctly before anything else will execute. When they click on a certain cell to execute the script it will open a Word document and import all required information in it. Then a new sheet in Excel is created. A name is given to the new sheet, based on what was selected in the ComboBox (cboSites) from the Template sheet. I also have a check in place to make sure there already isn't a sheet with the same name. I have all of this working without any issues.
From here what I would like to do and can't think of how to do it, is when the new sheet is created I want VBA code automatically dumped in this new sheet. I know the code that I want to use, but I just have no idea how to get it so it will automatically put that code with that sheet.
Is this possible to do or can only a new sheet be created and formatted, without being able to import any code into it?
Here is a sample code which will insert
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
MsgBox "Hello World"
End Sub
in a new sheet in a new workbook.
Sub Sample()
Dim wb As Workbook, ws As Worksheet
Dim VBP As Object, VBC As Object, CM As Object
Dim strProcName As String
Set wb = Workbooks.Add
Set ws = wb.Sheets(1)
Set VBP = wb.VBProject
Set VBC = VBP.VBComponents(ws.Name)
Set CM = VBC.CodeModule
strProcName = "Worksheet_SelectionChange"
With wb.VBProject.VBComponents( _
wb.Worksheets(ws.Name).CodeName).CodeModule
.InsertLines Line:=.CreateEventProc("SelectionChange", "Worksheet") + 1, _
String:=vbCrLf & _
" Msgbox ""Hello World"""
End With
End Sub
Please amend it to suit your needs.
You need to ensure that Trust access to Visual Basic Project is selected. To select it, follow the steps mentioned in THIS LINK
I am not aware of an easy way to put code in an Excel file.
Someone might think about changing the XML structure directly (xlsx files are basically a zipped directory of xml and code files).
But did you consider using XLAM (Excel addin) files, that can contain code and be imported for all users, who ever need to use it. And would open up with Excel, when the users start it. Depending on your setup, this could help you?
Look into the VBProject property of the workbook you are generating. You should be able to manipulate it, adding new VBComponents items containing the code you want.
http://msdn.microsoft.com/en-us/library/office/ff194737.aspx
This will require the appropriate security settings to do.
Here's a thread on another site related to this topic:
http://www.mrexcel.com/forum/excel-questions/663848-access-vbulletin-project-not-trusted.html
I haven't tried it myself, so I can't give much more detail.
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.