【问题标题】:Assigning a variable directly from a userform直接从用户窗体分配变量
【发布时间】:2025-12-20 15:50:10
【问题描述】:

我正在尝试添加一些代码来弹出一个用户表单,允许最终用户输入他们特定网站的登录名/密码。这段代码Passing variable from Form to Module in VBA 让我更接近我的目标,但我不确定如何让它按我需要的方式工作。这是我的用户表单的代码。

Private Sub CommandButton1_Click()
UPass = UserForm1.UserID
Unload UserForm1
End Sub

Private Sub CommandButton1_Click()
UID = UserForm1.WavePassword
Unload UserForm1
End Sub

我正在使用以下代码登录网站。

    Public Sub Connect_To_Wave()
    Dim Dasboard As Worksheet
        Set Dashboard = ActiveWorkbook.Worksheets("Dashboard")
    Dim UID As String
        UID = driver.findElementByName("PASSWORD").SendKeys UID
    Dim UPass As String
        UPass = driver.findElementByName("PASSWORD").SendKeys Upass




Set ie = CreateObject("InternetExplorer.Application")
my_url = "url of website - not a variable"

With ie
    .Visible = True
    .Navigate my_url
    .Top = 100
    .Left = 530
    .Height = 700
    .Width = 400

Do Until Not ie.Busy And ie.readyState = 4
    DoEvents
Loop

End With

ie.Document.getElementById("txtLoginUsername").Value = ""
ie.Document.getElementById("txtLoginPassword").Value = ""
ie.Document.getElementById("txtLoginUsername").Value = UID
ie.Document.getElementById("txtLoginPassword").Value = UPass
ie.Document.getElementById("btnLogin").Click

Do Until Not ie.Busy And ie.readyState = 4
    DoEvents
Loop
End Sub

我遇到的问题是我在 uid/upass 变量上收到“预期语句结束”错误。如何正确让用户表单将输入直接传递给变量,以便变量可用于登录网站?如果有更好的方法,我完全愿意改变方法。

【问题讨论】:

  • 我什至还没到运行任何一组代码的地步。当我完成输入 UID = / UPass = 行时,它们都变成了红色并标记了错误。
  • 过程CommandButton1_Click 定义了两次。那无法编译。 Connect_To_Wave() 也应该是 ConnectToWave(ByVal uid As String, ByVal pwd As String) - 你没有显示表单的实例化位置,但它分配全局变量和卸载表单的全局/默认实例并不是可靠代码的标志。
  • 我按照建议进行了这些更改。我不知道如何从这里测试它。我按 F8 运行用户表单,我认为它按预期运行,但我不确定如何同时测试登录代码。当我现在尝试 F8 登录代码时,它只是叮当,但没有提供错误消息。
  • @TonyP 如果代码现在可以运行,那么您可以将其提交给Code Review
  • @MacroMan 我不确定它是否有效。由于某种原因它不允许我运行它?

标签: vba excel


【解决方案1】:

这不可能编译:

Private Sub CommandButton1_Click()
UPass = UserForm1.UserID
Unload UserForm1
End Sub

Private Sub CommandButton1_Click()
UID = UserForm1.WavePassword
Unload UserForm1
End Sub

一个过程不能存在两次。重命名您的按钮OkButton,添加一些CancelButton 并重写表单的代码隐藏,如下所示:

Option Explicit
Private cancelling As Boolean

Public Property Get UID() As String
    UID = UserID.Text
End Property

Public Property Get PWD() As String
    PWD = WavePassword.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
        Me.Hide
    End If
End Sub

注意OkButtonCancelButtonQueryClose 处理程序只隐藏表单,因此调用代码仍然可以读取IsCancelledUIDPWD 属性价值观。

调用代码可以做到这一点——假设用户窗体被重命名为LoginPrompt

Public Sub DownloadStuff()
    With New LoginPrompt
        .Show vbModal
        If .IsCancelled Then Exit Sub
        ConnectToWave .UID, .PWD
    End With
End Sub

最后,ConnectToWave 过程,接受用户的输入:

Private Sub ConnectToWave(ByVal userID As String, ByVal password As String)
    ' there, you got your values from the form - now use them!
End Sub

【讨论】:

  • 这是一个基本问题,但是我应该将 Public Sub Downloadstuff() 放在带有 ConnecttoWave 还是用户表单的模块中?
  • 这将在标准模块中,并且可以作为附加到工作表上的按钮的宏公开,例如 - 我会将它放在 ConnectToWave 过程旁边。
  • 这是有道理的。谢谢!
  • FWIW 我为您链接的问题添加了答案。
【解决方案2】:

我不确定driver 是什么,但这个说法是错误的

UID = driver.findElementByName("PASSWORD").SendKeys UID as Sendkeys 是一种方法,因此在尝试分配返回值时需要使用括号。

试试这个:

UID = driver.findElementByName("PASSWORD").SendKeys(UID)

【讨论】:

  • 驱动程序是链接帖子中使用的一些对象/ findElementByName 是 ArcObjects 库的一部分的方法。鉴于 OP 不知道如何声明全局变量,我高度怀疑他使用的是 ArcObjects。
【解决方案3】:

这个:

Dim UID As String
    UID = driver.findElementByName("PASSWORD").SendKeys UID
Dim UPass As String
    UPass = driver.findElementByName("PASSWORD").SendKeys Upass

应该是:

Dim UID As String
    UID = driver.findElementByName("PASSWORD").SendKeys(UID)
Dim UPass As String
    UPass = driver.findElementByName("PASSWORD").SendKeys(Upass)

如果您调用的函数没有将任何内容分配回一个值,那么您不需要使用括号,但如果它正在为变量分配内容,那么您需要使用上述语法。

Foo() 是一个函数,Bar 是一个变量

'// Not assigning a value
Foo Bar

'// Assigning a value
someVar = Foo(Bar)

【讨论】:

    【解决方案4】:

    要完成您想要的,您必须在模块顶部创建一个全局变量。我怀疑你正在使用 ArcObjects,所以废弃整个 driver.findElementByName 的东西。此外,您已经正确设置了用户名和密码字段的值(此位:ie.Document.getElementById("txtLoginUsername").Value = UID),因此不需要任何SendKeys 方法。

    你需要的是在你的代码模块的最顶部这样的东西:

    Option Explicit
    Public UID as String
    Public UPass as String
    

    【讨论】:

    • 我应该提到我确实有公众在顶部。
    • @Tim 错误消息是由不正确的语法引起的,而不是变量范围。