I have the following global variable:
Option Explicit
Public locationCode As String 'Access the locationCode on the form anywhere on the project
Public Sub Settings()
'Declaration to access the data entered in the
'locationCode from anywhere on the project
locationCode = frmEnterLocation.txtLocationCode.Value
End Sub
But when I try to use my variable on another part of the project for example here:
Private Sub cmdOKButton_Click()
frmEnterLocation.txtLocationCode.SetFocus
If locationCode = "" Then
MsgBox "You have not entered a Location Code", vbCritical, "Please Enter a Location Code"
frmEnterLocation.txtLocationCode.SetFocus
Else
Unload Me
End Sub
The variable is not storing the value from the text box. How can I properly call this property on my Sub?
Assign value from text box via text box Change Event in Form code module
You have to assign the text box value after each change in text box txtLocationCode from within the user form to get it stored:
Private Sub txtLocationCode_Change()
' assign new value to global variable after each change in text box txtLocationCode
locationCode = Me.txtLocationCode.Value
End Sub
Calling the Userform from a Standard code module
To make your settings you just show an instance of the userform after global declaration of your locationCode and a variable that restores the old value after user abortion via red [x] (see the last section below Sub UserForm_QueryClose).
Option Explicit ' declaration head of a standard code module
' Access the locationCode on the form anywhere on the project
Public locationCode As String
Public locationCodeOld As String
Sub Settings()
With New frmEnterLocation
.Show vbModeless
End With
End Sub
Note: The With New .. statement allows you to unload (destroy) the called userform instance properly.
Complete Userform code module (without UserForm_QueryClose -> see below)
Option Explicit
Private Sub txtLocationCode_Change() ' << as discussed above
' assign new value to global variable after each change in text box txtLocationCode
locationCode = Me.txtLocationCode.Value
End Sub
Private Sub cmdOKButton_Click()
' SetFocus isn't executed after MsgBox, so use a Label1 info
If locationCode = "" Then
Me.Caption = "No Location Code entry yet"
Me.Label1.Caption = "Please Enter a Location Code"
Me.txtLocationCode.SetFocus
Else
Me.Caption = "Location code is " & locationCode
Me.Label1.Caption = "Location Code"
Me.Hide
End If
End Sub
Private Sub UserForm_Activate()
' remember old setting of locationCode
locationCodeOld = locationCode
' display current setting in text box and headers
Me.txtLocationCode.Value = locationCode
Me.txtLocationCode.SetFocus
Me.Caption = "Location code is " & IIf(Len(locationCode) = 0, " not yet entered", locationCode)
Me.Label1.Caption = IIf(Len(locationCode) = 0, "Please enter ", "") & "Location Code"
End Sub
Recommended Addition to userform code module
This allows you to restore the old value after user abortion via red [x]:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
' Reset old locationcode if form is aborted by user via [x}
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
locationCode = locationCodeOld
locationCodeOld = ""
Me.Hide
End If
End Sub
Put Public locationCode As String in the Declarations area (i.e. at the top) of a standard public module code sheet, not a private worksheet code sheet.
Related
I'm trying to reduce repetition in my Userform Code. I've tried writing a sub that sets a SpinButton and Textbox values equal to a defined default value. How do I pass the Spinbutton/Textbox as parameters in a private sub?
Referring to them directly brings up a type mismatch error.
Here's the code that doesn't work:
Private Sub UserForm_Initialize()
Call Default_Setter(TextBox_1, SpinButton_1, 0)
End Sub
Private Sub Default_Setter(InputTextBox As TextBox, InputSpinButton As SpinButton, InputDefaultValue As Integer)
InputTextBox.Locked = True
InputSpinButton.Value = InputDefaultValue
InputTextBox.Text = InputSpinButton.Value
InputTextBox.ControlTipText = "Value between " & InputSpinButton.Min & " and " & InputSpinButton.Max
End Sub
I have a ComboBox control on a custom CommandBar. I want to detect when a change has been made to the ComboBox and run some code.
This works fine when the user changes the value in the ComboxBox, but if some other VBA code changes it, the Event is not fired.
I have taken the code from here: https://learn.microsoft.com/en-us/office/vba/api/office.commandbarcombobox.change
and modified it slightly to delete a CommandBar with the same name so I can run it a number of times. I have then added another function to change the value of the ComboBox programmatically. When I change the value programmatically it can be seen to change on the Excel GUI, but the event code does not fire.
I have also tried the easier OnAction method, rather than hooking events, both seem to give the same result.
In a ClassModule called ComboBoxHandler I have the following code:
Private WithEvents ComboBoxEvent As Office.CommandBarComboBox
Public Sub SyncBox(box As Office.CommandBarComboBox)
Set ComboBoxEvent = box
If Not box Is Nothing Then
MsgBox "Synced " & box.Caption & " ComboBox events."
End If
End Sub
Private Sub Class_Terminate()
Set ComboBoxEvent = Nothing
End Sub
Private Sub ComboBoxEvent_Change(ByVal Ctrl As Office.CommandBarComboBox)
Dim stComboText As String
stComboText = Ctrl.Text
Select Case stComboText
Case "First Class"
FirstClass
Case "Business Class"
BusinessClass
Case "Coach Class"
CoachClass
Case "Standby"
Standby
End Select
End Sub
Private Sub FirstClass()
MsgBox "You selected First Class reservations"
End Sub
Private Sub BusinessClass()
MsgBox "You selected Business Class reservations"
End Sub
Private Sub CoachClass()
MsgBox "You selected Coach Class reservations"
End Sub
Private Sub Standby()
MsgBox "You chose to fly standby"
End Sub
In a module I have the following:
Private ctlComboBoxHandler As New ComboBoxHandler
Sub AddComboBox()
Set HostApp = Application
On Error Resume Next
CommandBars("Test CommandBar").Delete
Dim newBar As Office.CommandBar
Set newBar = HostApp.CommandBars.Add(Name:="Test CommandBar", Temporary:=True)
Dim newCombo As Office.CommandBarComboBox
Set newCombo = newBar.Controls.Add(msoControlComboBox)
With newCombo
.AddItem "First Class", 1
.AddItem "Business Class", 2
.AddItem "Coach Class", 3
.AddItem "Standby", 4
.DropDownLines = 5
.DropDownWidth = 75
.ListHeaderCount = 0
End With
ctlComboBoxHandler.SyncBox newCombo
newBar.Visible = True
End Sub
Sub test()
Dim newBar As Office.CommandBar
Set newBar = Application.CommandBars("Test CommandBar")
Dim cmbox As Office.CommandBarComboBox
Set cmbox = newBar.Controls(1)
cmbox.Text = "Business Class" ''<< I was hoping this would fire an event, but it does not! Same is true if I
End Sub
First I run AddComboBox and the events work fine if I manually change the ComboBox.
Then I run test() and the value displayed inside the ComboBox changes, but the event does not fire.
I declared projname globally at the top of the module 1. It is assigned in the userform, and is successfully accessed in the createWB sub. However, when I go to access it in the addWindow sub also in module 1, it becomes empty (""). I'm unsure of why this is happening because I thought that since the variable was globally declared I should be able to access it in any sub.
Module 1
Option Explicit
Public outputWorkbook As Workbook
Public globalcounter As Integer
Public projname As String
Public projnum As String
createWB()
Dim uf2 As New UserForm2
uf2.Show
Set outputWorkbook = Workbooks.Add(xlWBATWorksheet)
outputWorkbook.SaveAs Filename:=Environ("userprofile") & "\Desktop\" &
Replace(projname, " ", "") & ".xlsx"
outputWorkbook.Activate
Range("B3") = projname
Range("B4") = projnum
End Sub
addWindow()
Workbooks(Replace(projname, " ", "") + ".xlsx").Activate
End Sub
Userform Code
Public Sub CommandButton1_Click()
projname = Me.TextBox1.Text
projnum = Me.TextBox2.Text
Me.Hide
End Sub
Cells B3 and B4 are assigned the correct value, but the addWindow() line causes a subscript out of range error. When I test it with Debug.Print, I see that projname = "". I also simply tried outputWorkbook.Activate, which did not work either.
Avoid Global Pollution
Unless there is a really good reason to use them, try to avoid global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that.
Instead, try passing your parameters through your various methods as they are needed. This helps prevent errors, makes your code easier to follow, and utilizes composition.
Using your userform to store and expose your properties
Try to instantiate your userform using a With statement so that you have a captured instance of it where you have access to its various properties that you expose. In your case ProjectName and ProjectNumber.
Additionally, there should be a property to check if the userform was canceled or the X button was pressed.
You userform would look something like this:
Option Explicit
Private cancelled As Boolean
Public Property Get ProjectName() As String
ProjectName = TextBox1.Value
End Property
Public Property Get ProjectNumber() As Long
ProjectNumber = TextBox2.Value
End Property
Public Property Get IsCancelled() As Boolean
IsCancelled = cancelled
End Property
Private Sub CommandButton1_Click()
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
OnCancel
End If
End Sub
Private Sub OnCancel()
cancelled = True
Hide
End Sub
Instantiating the userform
Here is the example of now calling your userform (P.S. Change the name from Userform2). Notice we are capturing our instance of your userform using the With block. Within this block, we have access to the properties we exposed: ProjectName, ProjectNumber, IsCancelled.
Private Sub createWB()
With New UserForm2
.Show
If Not .IsCancelled Then
' Do neccessaray steps here...
' You have access to ProjectName and Project number.
' Pass this to your addWindow method.
addWindow .ProjectName
End If
End With
End Sub
The ProjectName now can be accessed from your userform and passed as a parameter to you addWindow method.
Private Sub addWindow(ByVal projName As String)
Workbooks(Replace(projName, " ", "") + ".xlsx").Activate
End Sub
For more information on using userforms in this way see this helpful Rubberduck Blog Post.
could you try using Module1 as prefix? , jus like in this code
Public Sub CommandButton1_Click()
Module1.projname = Me.TextBox1.Text
Module1.projnum = Me.TextBox2.Text
Me.Hide
End Sub
I've created a userform named UIAutotestHeader and textbox named pypath. And on button click I'm trying to pass a value to a variable but getting runtime error 424. Any help please.
Sub LoopThroughFiles()
Dim Path As String
UIAutotestHeader.Show
Path = pypath.Value
If pypath.Value = "" Then
MsgBox "Please add a path having .py files."
End If
End sub
Button click code:
Private Sub CommandButton1_Click()
UIAutotestHeader.Hide
End Sub
First, see this helpful RubberDuck Blog on working with UserForms, very helpful and applicable. This is what I'm basing my answer on.
Try to instantiate your userform using a With statement so that you have a captured instance of it where you have access to its various properties that you expose.
Note, in this case, you don't have to store your variables, as you still have access to them in your instance of your userform. Here is an example below.
Sub LoopThroughFiles()
With New UIAutotestHeader
.Show
If Not .IsCancelled Then
If .PyPath = "" Then
MsgBox "Please add a path having .py files."
End If
End If
End With
End Sub
In your Userform, you can expose the properties that you want to have access to. I also added the IsCancelled method to make sure the user didn't press cancel.
Option Explicit
Private cancelled As Boolean
Public Property Get PyPath() As String
PyPath = pypath.Value
End Property
Public Property Get IsCancelled() As Boolean
IsCancelled = cancelled
End Property
Private Sub CommandButton1_Click()
Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
OnCancel
End If
End Sub
Private Sub OnCancel()
cancelled = True
Hide
End Sub
Try this code
'In Standard Module
'------------------
Public sPath As String
Sub LoopThroughFiles()
Load UIAutotestHeader
sPath = UIAutotestHeader.pypath.Value
UIAutotestHeader.Show
End Sub
'In UserForm Module
Private Sub pypath_AfterUpdate()
If sPath = "" Then
MsgBox "Please add a path having .py files."
End If
End Sub
Private Sub CommandButton1_Click()
If sPath <> "" Then MsgBox sPath
sPath = ""
Unload UIAutotestHeader
End Sub
I have a userform, lets say when I click the button name in the userform it will request me to enter a name and it is always stored in
private sub button_click()
name = inputbox("Please enter your name:")
end sub
The thing I want is, when I start the macro first user form will appear then after user enters the necessary information, the variables values' will last until the end of the main macro.
I am searching for last two days couldn't find a solution but who knows maybe I couldn't find it. Therefore, i am writing here. Thanks in advance!
`
another question related:
lets say I have
Public plant As Variant
Public checking As Variant
Public MeanCov1 As Variant
Public MeanCov2 As Variant
Public MeanCov3 As Variant
Public WeekCov1 As Variant
Public WeekCov2 As Variant
Public WeekCov3 As Variant
Public RolLow As Variant
Public RolHigh As Variant
Public ServiceLevel As Variant
Public TrendMultiplier As Variant
Public WeekCov11 As Variant
Public WeekCov22 As Variant
Public WeekCov33 As Variant
Sub initialize()
MeanCov1 = 0.3
MeanCov2 = 0.5
MeanCov3 = 0.7
WeekCov1 = 18
WeekCov2 = 13
WeekCov3 = 8
WeekCov11 = -14 + WeekCov1
WeekCov22 = -14 + WeekCov2
WeekCov33 = -14 + WeekCov3
RolLow = 0.3
RolHigh = 0.7
TrendMultiplier = 4
ROL_Analysis.Show
Application.Run ("ROL_Analysis_Macro")
End Sub
I can not initialize the public variables, for example in user form it says show variable values but when I click it is completely empty
Private Sub ROLparameter_Click()
Line1: RolLow = InputBox("Please enter the lower bound percentage for ROL calculation between 0 and 100 (initially " & RolLow & "%):")
If Not 0 <= RolLow <= 100 Then GoTo Line1
Line2: RolHigh = InputBox("Please enter the upper bound percentage for ROL calculation between 0 and 100 (initially " & RolHigh & "%):")
End Sub
To access a variable in a different sub, you define it globally
Public Name As String
Private Sub button_click()
Name = InputBox("Please enter your name:")
End Sub
Sub Foo()
MsgBox Name
End Sub
and for your second question, if you are clicking on the buttons, then for the below code you will get a alert if you have clicked the button which corresponds to the name you typed in the InputBox
Public name As String
Sub button_click()
name = InputBox("Please enter your name:")
End Sub
Private Sub button1_click()
If name = "john" Then
MsgBox name
End If
End Sub
Private Sub button2_click()
If name = "james" Then
MsgBox name
End If
End Sub
Private Sub button3_click()
If name = "david" Then
MsgBox name
End If
End Sub
As was said, define a variable globally to access it in different subs and different modules. I have a very simple example here for you. I created a module called Module1. Here is all its code:
Option Explicit
Public name As String
Sub Test()
name = "David"
UserForm1.Show
MsgBox "The userform has closed"
End Sub
I also created a userform called UserForm1. Here is all the code and a screenshot of it:
Option Explicit
Private Sub CommandButton1_Click()
MsgBox Module1.name
End Sub
How it works:
If I launch Module1, the public variable name gets set to "David". In your case you could set it to whatever you want with your inputbox. After that, the userform is launched with .Show and the Module1 stops reading code until you're done with UserForm1.
While Userform1 is active, clicking the button will open a MsgBox saying "David", because I access the public variable Module1.name. I always specify which module the public variable comes from. When I close the userform, Module1 gets activated again and I get a msgbox saying "The userform has closed".
Does this answer all your questions?
Clicking the button:
Closing the form: