【问题标题】:VBA How to force a function to Return when a Form Button is pressedVBA如何在按下表单按钮时强制函数返回
【发布时间】:2012-05-06 23:48:01
【问题描述】:

我认为这很简单,但事实证明这很困难。任何建议或想法都将不胜感激。

我在 Excel 中有一个表单,如果按下某个按钮,我需要用户在该按钮的代码运行之前输入密码。

我可以只使用输入框,但这将允许其他人在输入密码时看到密码。所以我想使用带有文本框的第二个表单并将其 PasswordChar 参数设置为 *

这就是问题所在。我想使用这样的代码

if checkPassword("Please enter your password") = False then exit sub

checkPassword 是一个将字符串作为参数的函数。此函数打开一个表单并将消息放入标签中。用户应输入密码并单击确定。

btnOK_Click()应该检查密码是否正确,然后如果密码正确则强制打开表单的函数返回True,否则密码不正确。

我只是不知道如何强制函数返回。当用户单击确定然后卸载表单时,我尝试将全局变量设置为 True 或 False。这会使函数返回,但它也会重置表单设置的所有全局变量。

这是我调用表单的函数

Function checkPassword(message As String) As Boolean

  frmPassword.Show
  frmPassword.passwordMsg.Caption = message

  'passwordStatus is a global variable
  If passwordStatus = True Then checkPassword = True Else  checkPassword = False

End Function

这里是链接到表单确定按钮的子:

Private Sub passwordok_Click()

  If Me.passwordtext.Text = "password" Then
      passwordStatus = True
  Else
      passwordStatus = False
  End If
  Unload Me

End Sub

【问题讨论】:

    标签: vba excel


    【解决方案1】:

    我可以只使用输入框,但这将允许其他人在输入密码时看到密码。所以我想使用带有文本框的第二个表单并将其 PasswordChar 参数设置为 *

    这是我数据库中的一些内容。

    免责声明:我没有写这个,我不记得是谁写的

    用法

    Private Sub passwordok_Click()
        Dim Prompt, password As String
        Prompt = "Please enter your password."
        password = InputBoxDK(Prompt)
    
        MsgBox password '<~~ Do whatever you want to do with this
    End Sub
    

    在一个模块中

    Option Explicit
    
    Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
    ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
    
    Private Declare Function GetModuleHandle Lib "kernel32" Alias _
    "GetModuleHandleA" (ByVal lpModuleName As String) As Long
    
    Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" _
    (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, _
    ByVal dwThreadId As Long) As Long
    
    Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
    
    Private Declare Function SendDlgItemMessage Lib "user32" Alias "SendDlgItemMessageA" _
    (ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal wMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
    
    Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
    (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    
    Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
    
    'Constants to be used in our API functions
    Private Const EM_SETPASSWORDCHAR = &HCC
    Private Const WH_CBT = 5
    Private Const HCBT_ACTIVATE = 5
    Private Const HC_ACTION = 0
    
    Private hHook As Long
    
    Public Function NewProc(ByVal lngCode As Long, ByVal wParam As Long, _
    ByVal lParam As Long) As Long
        Dim RetVal
        Dim strClassName As String, lngBuffer As Long
    
        If lngCode < HC_ACTION Then
            NewProc = CallNextHookEx(hHook, lngCode, wParam, lParam)
            Exit Function
        End If
    
        strClassName = String$(256, " ")
        lngBuffer = 255
    
        'A window has been activated
        If lngCode = HCBT_ACTIVATE Then
            RetVal = GetClassName(wParam, strClassName, lngBuffer)
            'Class name of the Inputbox
            If Left$(strClassName, RetVal) = "#32770" Then
                'This changes the edit control so that it display the password character *.
                'You can change the Asc("*") as you please.
                SendDlgItemMessage wParam, &H1324, EM_SETPASSWORDCHAR, Asc("*"), &H0
            End If
        End If
    
        'This line will ensure that any other hooks that may be in place are
        'called correctly.
        CallNextHookEx hHook, lngCode, wParam, lParam
    
    End Function
    
    Public Function InputBoxDK(Prompt, Optional Title, Optional Default, Optional XPos, _
    Optional YPos, Optional HelpFile, Optional Context) As String
        Dim lngModHwnd As Long, lngThreadID As Long
        lngThreadID = GetCurrentThreadId
        lngModHwnd = GetModuleHandle(vbNullString)
        hHook = SetWindowsHookEx(WH_CBT, AddressOf NewProc, lngModHwnd, lngThreadID)
        InputBoxDK = InputBox(Prompt, Title, Default, XPos, YPos, HelpFile, Context)
        UnhookWindowsHookEx hHook
    End Function
    

    快照

    【讨论】:

    • 不客气。我真的希望我可以引用原作者的链接,而不是粘贴上面的代码。如果我找到它,我会回来编辑这篇文章。 :)
    【解决方案2】:

    从对话框中返回一个值是一项常见的任务,而且非常简单。

    最简单的模式是将函数放在对话框表单本身中,并让该函数以模态方式显示其宿主表单。

    Private passwordStatus As Boolean
    
    Function checkPassword(message As String) As Boolean
      '//setup the form
      Me.passwordMsg.Caption = message
    
      '//show the form modally, this will not return until the form is unloaded 
      '//i.e. when the button is clicked; so values in private variable are still valid
      Me.Show vbModal
    
      '//form is unloaded (via unload me or a close) return the value;
      checkPassword = passwordStatus
    End Function
    
    Private Sub passwordok_Click()
      passwordStatus = Me.passwordtext.Text = "password"
      Unload Me
    End Sub
    

    用作

    passworkOk = frmPassword.checkPassword("enter your blabla")
    

    【讨论】:

    • 嗨,Alex,感谢您提供此解决方案。我尝试了 Siddharth 的解决方案,效果很好(再次感谢 Siddharth),但您的解决方案更接近我最初想做的。我试过了,效果很好,更简单,负载更小。谢谢
    • 我用过这个,效果很好,除了我必须将passwordStatus = Me.passwordtext.Text = "password" 放在unload me 之后,因为卸载会重置该变量,这会导致问题吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    相关资源
    最近更新 更多