Passing variable from Form to Module in VBA - excel

I have the following button on a Form:
Private Sub CommandButton1_Click()
Dim pass As String
pass = UserForm1.TextBox1
Unload UserForm1
End Sub
I then have a Module called Module1:
Public Sub Login()
...
UserForm1.Show
driver.findElementByName("PASSWORD").SendKeys pass
...
End Sub
The idea is whatever password the users enters into the input box will be assigned to the variable pass. What I'm having trouble doing however is passing pass from UserForm1 into Module1's Login sub.
I would of thought adding something like Module1.Login (pass) to my form before I unload it would work, however that doesn't seem to pass anything. Any help would be much appreciated. Thanks.

Don't declare the variable in the userform. Declare it as Public in the module.
Public pass As String
In the Userform
Private Sub CommandButton1_Click()
pass = UserForm1.TextBox1
Unload UserForm1
End Sub
In the Module
Public pass As String
Public Sub Login()
'
'~~> Rest of the code
'
UserForm1.Show
driver.findElementByName("PASSWORD").SendKeys pass
'
'~~> Rest of the code
'
End Sub
You might want to also add an additional check just before calling the driver.find... line?
If Len(Trim(pass)) <> 0 Then
This will ensure that a blank string is not passed.

Siddharth's answer is nice, but relies on globally-scoped variables. There's a better, more OOP-friendly way.
A UserForm is a class module like any other - the only difference is that it has a hidden VB_PredeclaredId attribute set to True, which makes VB create a global-scope object variable named after the class - that's how you can write UserForm1.Show without creating a new instance of the class.
Step away from this, and treat your form as an object instead - expose Property Get members and abstract away the form's controls - the calling code doesn't care about controls anyway:
Option Explicit
Private cancelling As Boolean
Public Property Get UserId() As String
UserId = txtUserId.Text
End Property
Public Property Get Password() As String
Password = txtPassword.Text
End Property
Public Property Get IsCancelled() As Boolean
IsCancelled = cancelling
End Property
Private Sub OkButton_Click()
Me.Hide
End Sub
Private Sub CancelButton_Click()
cancelling = True
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
cancelling = True
Cancel = True
Me.Hide
End If
End Sub
Now the calling code can do this (assuming the UserForm was named LoginPrompt):
With New LoginPrompt
.Show vbModal
If .IsCancelled Then Exit Sub
DoSomething .UserId, .Password
End With
Where DoSomething would be some procedure that requires the two string parameters:
Private Sub DoSomething(ByVal uid As String, ByVal pwd As String)
'work with the parameter values, regardless of where they came from
End Sub

Related

Passing text box text from a userform to a sheet using MVP pattern

Ok... So I am trying to wrap my head around properties. I have done a ton of googling but really need to try myself to fully understand. I have 3 components:
I have a UserForm: "frmView1"
I have a class module: "clsPresenter1"
I have a regular module: "modModel1"
My UserForm has a txtbox "TextBox1" and here is the userform code:
Option Explicit
'View (The V in MVP)
Public Event OnTxtBoxChange()
Public Property Get TxtBoxInfo() As String
TxtBoxInfo = TextBox1.Text
End Property
Private Sub TextBox1_Change()
RaiseEvent OnTxtBoxChange
End Sub
My Class module:
Option Explicit
'Presenter Class (The P in MVP)
'Implements Business Logic
Private WithEvents objUserForm As frmView1
Private Sub Class_Initialize()
Set objUserForm = New frmView1
End Sub
Public Sub TxtBoxContent()
objUserForm.TxtBoxInfo
End Sub
Private Sub objUserForm_OnTxtBoxChange()
DoSomething
End Sub
My regular module:
Option Explicit
'Model Module (The M in MVP)
'Business Logic
Private objPresenter As clsPresenter1
Public Sub DoSomething()
Sheet1.Cells.Clear
Sheet1.Cells(3, 3) = objPresenter.TxtBoxContent
End Sub
So this is a shortened version to simplify my question. In reality I have code to show the form and close the form and a few other things that are working fine. But my question is... How do I pass whatever the user types in the txt box to the worksheet? I keep getting:
Compile error: Expected Function or variable
Ok... So I may have figured it out... I changed:
Public Sub TxtBoxContent()
objUserForm.TxtBoxInfo
End Sub
To:
Public Function TxtBoxContent() As String
TxtBoxContent = objUserForm.TxtBoxInfo
End Function
This seems to work... Please let me know if this is not the correct way...
Maybe this is actually the correct way? Again changing:
Public Sub TxtBoxContent()
objUserForm.TxtBoxInfo
End Sub
To:
Public Property Get TxtBoxContent() As String
TxtBoxContent = objUserForm.TxtBoxInfo
End Property
Again this seems to work... But why would I ever use a function in my class module ("presenter") if I could always use a property instead?

Global variable not accessible in different sub?

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

VBA Pass Form Controls to Function

All,
I have been struggling with this for a while: is it possible to pass an object to a function?
Here is what I am trying to accomplish:
Get the name of which control was pressed on a form (as object?)
Send the control's name to function "MyFunction" (as reference?)
Disable that same control on "MyFunction"
Called from form1:
Private Sub button1_Click()
Dim caller As String
caller = Form1.ActiveControl.Name
MyFunction(caller)
End Sub 'I'm able to pass it as a string
button1_Click calls MyFunction and passes caller to it:
Private Sub MyFunction(caller As String)
caller.Enabled = False
End Sub
I understand this will not work as a string. How could I possibly do it as an actual object?
Thank you!
There is little problem passing an object to a sub:
Private Sub Disable(c As Control)
MsgBox c.Name
c.Enabled = False
End Sub
Private Sub CommandButton1_Click()
Disable CommandButton1
End Sub
Private Sub CommandButton2_Click()
Disable CommandButton2
End Sub
Private Sub CommandButton3_Click()
Disable CommandButton3
End Sub
In the above I created a userform with three buttons, they say who they are when clicked and are then disabled.
Note that
Disable CommandButton1
can be replaced by
Disable Me.ActiveControl
or even just
Disable ActiveControl
You can even use Variant like so (rough example):
Private Sub CommandButton1_Click()
EnableDisable ActiveControl, "disable"
End Sub
Private Sub EnableDisable(control As Variant, status As String)
If status = "enabled" Then
control.Enabled = True
Else
control.Enabled = False
End If
End Sub
John Coleman's example is better than mine, though.

VBA Excel, Returning a Variable between Forms

I need some help. I am writing VBA script for an Excel macro. I have two forms, the first has a button calling the second. On the second I want it to return a variable (tempdate, this is declared as public type Date in the main Worksheet).
Main form button code:
Private Sub SetDueButton_Click()
UserForm1.Show
DueDate.Value = tempdate 'display tempdate in the DueDate text box
End Sub
UserForm1 'ok' button:
Private Sub CommandButton53_Click()
tempdate = TextBox1.Value
Unload Me
End Sub
What am I missing to get this variable to load whatever is in TextBox1.Value?
I would use a property in the userform
Your main form code would change to look like this:
Option Explicit
Private Sub SetDueButton_Click()
Dim UF As UserForm1 'you can declare a user form as an independent object
UF.Show
DueDate.Value = UF.tempdate 'get the property
Unload UF 'now you can unload or set to Nothing
End Sub
Your UserForm1 code would be this:
Option Explicit
Public Property Get tempdate() As String
tempdate = Me.TextBox1.Value 'Me refers to the form itself
End Property
Private Sub CommandButton53_Click()
Me.Hide 'hide don't unload yet or you can't get the data.
End Sub
You need to declare the variable in a module, not the worksheet, and the declaration needs to be:
Global tempDate as Date
or
Public tempDate as Date
The variables in the worksheet are not available in the forms.
It would be possible to make a function in the worksheet and call this function, but this is a much simpler solution.

Returning a value or Cancel from Excel userform

I have a sub that calls a userform to show and would only like to proceed if the user didn't click my Cancel button. I don't want to put all my other sub calls within the userform.
Is it possible to have a userform return a value or a way to check if the user clicked a particular button?
I suppose I can use a global variable, but was wondering if I could pass things to and from a userform.
I prefer to use properties.
Inside your userForm
Private m_bCancel As Boolean
Public Property Get Cancel() As Boolean
Cancel = m_bCancel
End Property
Public Property Let Cancel(ByVal bCancel As Boolean)
m_bCancel = bCancel
End Property
Code for the cancel button
Private Sub cmdCancel_Click()
Me.Cancel=True
Me.Hide
End Sub
Call the userForm from outside like this
sub loadForm()
dim frm
set frm= new UserForm1
frm.show
if frm.Cancel then
Msgbox "Cancelled"
end if
End Sub

Resources