I have a load of variable names in a spreadsheet column. These variables are defined and have values in the modules I have in my project.
I want to have a code that references the variable name in a spreadsheet, and returns the value that it have in the module and pastes the value in another spreadsheet i.e
Sub code()
dim variable1 as integer
variable1 = 2
End sub
sheet 1: cell A1: variable1
Sub code2()
sheet(2).range("a1").value = sheet(1).range("a1").value
end sub
sheet 2: cell A1: 2
There is no way to ask for a variable by name in VBA during runtime. During compilation all variable names are stripped away, and at runtime the variables are referenced just with memory locations. Also, if the variable is declared within a sub, it only exists while that sub is being executed. If you try to access it later, something else will be using its memory location.
The only way to do this is to declare all the variables at module level, and then have a function which explicitly maps variable names to these variables:
Private variable1 As Integer
Sub code()
variable1 = 2
End Sub
Sub code2()
Sheets(2).Range("a1").Value = VariableByName(Sheets(1).Range("a1").Value)
End Sub
Function VariableByName(VarName As String) As Variant
Select Case VarName
Case "variable1": VariableByName = variable1
End Select
End Function
Actually, your best option is to forget about using variables and use names instead:
Sub code()
Names.Add "variable1", 2, Visible:=False
End Sub
Sub code2()
Sheets(2).Range("a1").Value = Evaluate(Sheets(1).Range("a1").Value)
End Sub
But when you go that route, if you need to access the variable in VBA you can't just say variable1, you need to use code like this:
Sub code3()
Dim variable1 As Integer
variable1 = Evaluate("variable1") 'bring it into a normal variable
variable1 = variable1 * 2 'now you can use it like a normal variable
Names("variable1").RefersTo = variable1 'need to save it when you're done
End Sub
This worked in Excel 2010
variable1 = [variable1].Value
VBA treats [variable1] (with brackets) as a variant that references the named cell.
-mmh
Related
I encounter a weird problem that I believe is related to Excel behavior, rather than to my code.
I have a global variable named "numEtape", which is an integer. My code consists in several steps where the user has to type data on a sheet, then press a button which saves the data in an array and increments the "numEtape", before going to the next step.
The code (simplified) looks like this :
Dim numEtape As Integer
Sub AjoutEssai()
numEtape = 2
UFPreAjoutInfos.Show 'Unrelated Userform that asks user for more informations, but doesn't modify "numEtape" or call any other macro
Call InterfaceFiller
End Sub
Sub InterfaceFiller()
Dim rangedubtn As Range
Dim btnPrecedent As Button
Select Case numEtape
Case 2
'Change value of some cells
Case 3
'Change value of some cells
Case 4
'Change value of some cells
Case Is >= 5
'Change value of some cells
Case Else
Debug.Print "Error"
End Select
Set rangedubtn = Sheets("Interface").Range("M3")
Set btnPrecedent = Sheets("Interface").Buttons.Add(rangedubtn.Left, rangedubtn.Top,rangedubtn.Width, rangedubtn.Height)
With btnPrecedent
.OnAction = "mSuivant"
.Caption = "Suivant"
.Name = "btnSuivant"
End With
End Sub
Sub mSuivant()
numEtape = numEtape + 1
Call InterfaceFiller
End Sub
I don't think the code itself is important, what I can expect from it, since I first call AjoutEssai(), is for numEtape to always be greater than 2.
However, when during the steps the user opens and close other excel/office files (that don't have any vba code/macros in it), excel seems to empty numEtape, which makes the Select Case go to the Case Else.
When does excel remove global variables from memory, and is there a way to prevent this behavior from happening?
Public numEtape As Long
A viable option is to use the word public like public numEtape As Long.
Then the variable will be saving its value for as long as the Excel workbook is opened. In older versions of VBA the word was Global (What is the difference between Dim, Global, Public, and Private as Modular Field Access Modifiers?)
Dim numEtape As Long
For using Dim outside of Sub or Function, the variable will be emptied, after the code is over. Take this snippet only:
Dim numEtape As Long
Sub MainTest()
numEtape = 23
End Sub
Once you run it and you hit End Sub the variable would be emptied as well. Check after running the MainTest():
Sub PrintingVariable()
Debug.Print numEtape
End Sub
If you want to save the value, there are 2 basic ways that work:
Write the value in an excel cell
Write the value in a database
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
Here is the vba I currently have. I am needing it to delete all data in any worksheet that starts with "Demand". The code is running but no data is being deleted. Any help is appreciated!!
Option Explicit
Sub ClearExcelContent()
Dim DemandData As Worksheet
For Each DemandData In ActiveWorkbook.Worksheets
If LCase(Left(DemandData.Name, 6)) = "Demand" Then
DemandData.Rows("2:" & Rows.Count).ClearContents
End If
Next DemandData
MsgBox "All Demand Data has been Deleted from Consolidation Tab"
End Sub
If LCase(Left(DemandData.Name, 6)) = "Demand" Then
The above statement will not match any worksheet, because the LHS is all lowercase and the RHS has an uppercase D. Replace Demand with lowercase demand.
If LCase(Left(DemandData.Name, 6)) = "demand" Then
These are 3 basic functions for edition of strings:
LCase, UCase, and WorksheetFunction.Proper
This is what they would return:
Demand Is Diamand
demand is diamand
DEMAND IS DIAMAND
if you run them like this:
Public Sub TestMe()
Dim strText As String
strText = "demaNd is dIamand"
Debug.Print WorksheetFunction.Proper(strText)
Debug.Print LCase(strText)
Debug.Print UCase(strText)
End Sub
In order to compare the result of the functions, you should be comparing with similar string. Probably the most sure thing is to put the same string functions on both parts of the comparison. Like this:
LCase(Left(DemandData.name, 6)) = LCase("demand") Then
In general, if you want to make sure that Vit=VIT then consider adding Option Compare Text on top of the module. Then this would be true:
Option Compare Text
Sub TestMe()
Debug.Print "Vit" = "VIT"
End Sub
In VBA I need a module sub to tell an instance to set up some variables.
In Module 1 I have:
Sub Load()
ThisWorkbook.SetupVariables
ThisWorkbook.TestVariables
End Sub
In ThisWorkbook I have:
Private Variable1 As Integer
Private Variable2 As String
Private Variable3 As MyUserDefinedObjectType
Public Sub SetupVariables()
Variable1 = 5
Variable2 = "Five"
Set Variable3 = New MyUserDefinedObjectType()
End Sub
Sub TestVariables()
MsgBox Variable1 & " is spelled " & Variable2
Variable3.SomeFunction
End Sub
The call to TestVariables inside Load() yields the correct result, but subsequent calls to TestVariables fail. How can I make Variable1 and Variable2 hold their values? (In my real-world situation, these variables are objects I've defined and cannot be made public variables.)
Sequence of events:
Load is stored in Module1 and is associated with a form button on Worksheet1. This is pressed first.
Subsequently, an ActiveX control in Worksheet2 tells ThisWorkbook to call TestVariables.
It works for me as you have it. Create a Watch (View - Watch Window) for Variable1 and choose Break When Value Changes. You should be able to see when it changes to zero.
Im having trouble takign my assigned variable and offseting it. What am I doing wrong?
Public Sub SampleBox_Change()
Dim str As Integer
If (SampleBox.ListIndex > -1) Then
str = SampleBox.List(SampleBox.ListIndex)
End If
End Sub
Public Sub Samplesdel(str As Integer)
Range(Range("BA1").EntireColumn, Range("BA1").Offset(0, -str).EntireColumn).Select
End Sub
Public Sub CommandButton1_Click()
Application.Run "Samplesdel"
End Sub
So the variable (str) is a whole number. I would like to use this number to select a certain number of columns (from BA1 to "left however many columns valued as str"). so if the user selects 8 i would like to select BA1 and left 8 columns.
The combobox is in a userform where the code for the assigned variable is set.
I would like to use the assigned variable in a macro (where i used the select function).
so the variable str gets assigned from a userform combobox. I would then like to pass this variable to a macro where i use it in the offset function.
I just used your snippets of code here, I'll assume you know what you're trying to accomplish with this. As mentioned in another answer, I think it's an issue of scope; it doesn't seem like there's a good reason you can't combine your statements as follows:
Public Sub SampleBox_Change()
Dim str As Integer
If (SampleBox.ListIndex > -1) Then
Range(Range("BA1").EntireColumn, Range("BA1").Offset(0, SampleBox.ListIndex).EntireColumn).Select
End If
End Sub
To add some unsolicited feedback, naming a variable that is an integer "str" will be very confusing to anyone else that has to read your code, the name "str" implies "string", a different data type.
James, you are setting the value of str here correct?
Public Sub SampleBox_Change()
Dim str As Integer
If (SampleBox.ListIndex > -1) Then
str = SampleBox.List(SampleBox.ListIndex)
End If
End Sub
The scope for str will only be this function and it will not be able to be accessed by any other function.
What value are you passing to Samplesdel as the parameter?
Application.Run "Samplesdel"