I'm learning VBA using a combination of VBA For Dummies and the above mentioned book. The latter, presents a simple challenge (Challenge 2, Chapter 2) that I'd like to ask some for some feedback about.
The challenge is as follows:
Place a Command Button control on a worksheet and write a program in the Click()
event procedure that increments a variable by 5 with every click of the mouse.
Output the value of this variable in a message box.
I've put together the following the code snippet in response:
Sub CommandButton1_Click()
Dim AddClick As Integer
AddClick = Range("A1").Value
AddClick = AddClick + 5
Range("A1").Value = AddClick
MsgBox AddClick
End Sub
Although the code works, I'm pretty sure there's a way to eliminate the use of 'Range("A1").Value' to base the 'AddClick' variable on. How would I go about doing this?
*Update: Thanks to Cody Gray's suggestion (http://articles.techrepublic.com.com/5100-10878_11-5854605.html), I've revised the code to the following - which now works just fine (edited for further simplication):*
Sub CommandButton1_Click()
Static AddClick As Integer
AddClick = AddClick + 5
MsgBox AddClick
End Sub
Simples. Thanks again Cody.
Both previous samples are wrong I think. The correct version is below:
Sub CommandButton1_Click()
Static AddClick As Integer
AddClick = AddClick + 5
MsgBox AddClick
End Sub
Define the variable at module level.
Doing this will increase the scope of the variable from procedure to the module.
Replace the existing code with this one.
Option Explicit
Dim AddClick As Integer
Sub CommandButton1_Click()
AddClick = 0
AddClick = AddClick + 5
MsgBox (AddClick)
End Sub
Note: Defining the variable at procedure level will limit its life.
i.e. the variable won't be accessible outside the scope of the procedure.
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
I'm having problems with shapes, frames and option buttons... I'm a total newbie, I've never used them. I just put several option buttons on an Excel sheet (Using the FORM toolbox).
I'm trying to check whether my optionbutton is filled or not. So far, I've done the following :
Sub SX_EXTERNE()
Dim Ws As Worksheet
Dim ConBut As Shape
Dim Answer As String
Set Ws = ThisWorkbook.Sheets("Externe")
For Each ConBut In Ws.Shapes
If ConBut.Type = msoFormControl Then
If ConBut.FormControlType = xlOptionButton Then
If ConBut.ControlFormat.Value = xlOn Then
Answer = ConBut.Name
End If
End If
End If
Next ConBut
MsgBox Answer
End Sub
My problem is I do not know how to check only in a selected frame (i.e. "Conges_generaux" for my example):
Could you please give me a hint? I've seen many subjects about that but many of them treat of ActiveXControls... I don't even know the difference.
Thanks
Here is a quick way
Sub Sample()
Dim optBtn As OptionButton
For Each optBtn In ActiveSheet.OptionButtons
If optBtn.Value = 1 Then
Debug.Print optBtn.Name
Debug.Print optBtn.GroupBox.Name
End If
Next
End Sub
So in your code change Dim ConBut As Shape to Dim ConBut As OptionButton. Feel free to put relevant checks and store it in the relevant answer variable :)
So I'm using excel 2010, and right now, I'm trying to use calculate the value of a variable in one sub, and want it to be used in multiple subs, except I can't figure out how to do this. Here is an example of what I'm using in its most basic form
Public Sub Calc()
Dim i As Integer
i = 10 - 5
End Sub
'Other sub that will use the value for i calculated in the Calc sub
Sub Macro()
y = i +5
End Sub
How am I suppose to be able to use/pass this value for "i" in/into the sub macro?
Move the Dim above the subs:
Public i As Integer
Public Sub Calc()
i = 10 - 5
End Sub
Sub Macro()
y = i + 5
MsgBox y
End Sub
Sub MAIN()
Call Calc
Call Macro
End Sub
Try running MAIN()
Insert new module and define i as:
Public i As Integer
Then you'll be able to use it whenever you want.
For further information, please see: Scope of variables in Visual Basic for Applications
I would like to use Function instead of Sub.
Sub Main()
Msgbox Macro(calc)
end Sub
Function Calc() as Integer
Dim i As Integer
i = 10 - 5
Calc = i
End Function
Function Macro(i as Integer) as Integer
Macro = i + 5
End Function
I´m trying to use a sub to determine a dynamic range which serves as the input to a number of functions. The simplest version of what I´m trying to do looks like this
This approach gives me errors. Putting the subs and functions in different modules doesn´t help. What´s the mistake I´m making?
Global Info As Range
Sub InfoSetter()
Worksheets("Example").Activate
ActiveSheet.UsedRange.Select
Set Info = Selection
End Sub
Function Test() As Variant
Test = Info.Address
End Function
Try the below. This calls the sub from the function that sets the value of info. This means that your info will always be the current UsedRange when the function calculates. Also, using .Activate and .Select is generally considered bad practice. The below code does the same without using either.
Global Info As Range
Sub InfoSetter()
Set Info = Worksheets("Example").UsedRange
End Sub
Function Test() As Variant
Application.Volatile 'Added so function updates automatically when sheet calculates
Call InfoSetter
Test = Info.Address
End Function
Edit: Adding Application.Volatile at the beginning of your function will make it so this updates every time the worksheet calculates.
As per the comment from omegastripes, your error is likely to be because your range is empty. Given Test is a variant suggest you test for an empty range as below
Global Info As Range
Sub TryMe()
MsgBox Test
End Sub
your code
Sub InfoSetter()
Set Info = Worksheets("Example").UsedRange
End Sub
Function Test() As Variant
If Info Is Nothing Then
Test = "Ï'm empty"
Else
Test = Info.Address
End If
End Function
Usually the Excel VBA editor auto-capitalizes keywords and property names for you, but now it is un-capitalizing them. Like this:
Private Sub CommandButton1_Click()
Range("A1").Value = "test"
End Sub
changes to:
Private Sub CommandButton1_Click()
Range("A1").value = "test"
End Sub
And then the code doesn't run properly. Any ideas what could cause this behavior? Thanks.
Possible reasons
You have named one of the modules as value
You have a variable called value in one of your procedures/functions
You have a procedure/function with that name
Example for point 1
Example for point 2
Sub Sample()
Range("A1").value = "Sid"
End Sub
Sub Blah()
Dim value As Long
value = 1
End Sub
Example for point 3
Sub Sample()
Range("A1").value = "Sid"
End Sub
Sub value()
'
'
'
End Sub