无模式表单上的文本框条目的验证消息中断文本选择

Ava*_*vax 4 excel vba excel-vba userform

您好,我在我的Userform中尝试此代码,以检查输入的数据textbox1是否是一个数字,如果没有显示msgbox给用户并选择文本textbox1,但下面的代码不会选择文本textbox1时Userform是vBModeless

Private Sub TextBox1_Change()
    If Not IsNumeric(TextBox1) Then
        MsgBox " only number"
        TextBox1.SetFocus
        TextBox1.SelStart = 0
        TextBox1.SelLength = Len(TextBox1.Text)
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

有什么办法吗?

Com*_*nse 7

问题的根源不是选择,因为它在那里并按预期工作:

Private Sub TextBox1_Change()
    If Not IsNumeric(TextBox1) Then
        MsgBox " only number"
        TextBox1.SetFocus
        TextBox1.SelStart = 0
        TextBox1.SelLength = Len(TextBox1.Text)
        Debug.Print TextBox1.SelText
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

我认为这里的根本问题是MSForms控件不是真正的窗口,而是没有窗口句柄的"无窗口"实体(当然,有像listbox,tabstrip,multipage这样的例外),可以通过隐藏方法轻松测试:

'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]
Run Code Online (Sandbox Code Playgroud)

另一方面,还有Window的消息传递模型,其中每个控件都是一个窗口(因此是Windows操作系统),具有适当的窗口句柄,并且能够发送和接收WM_SETFOCUS/ WM_KILLFOCUS等消息并进行适当的操作.回到MSForms - 在内部UserForm管理外部世界和子控件之间的所有交互.

让我们从声明WIN API函数GetFocus开始:

Public Declare Function GetFocus Lib "user32.dll" () As Long
Run Code Online (Sandbox Code Playgroud)

让我们添加一些Debug.Print来看看发生了什么:

Private Sub TextBox1_Change()
    If Not IsNumeric(TextBox1) Then
        Debug.Print "--"
        Debug.Print GetFocus
        MsgBox " only number"
        Debug.Print GetFocus
        TextBox1.SetFocus
        Debug.Print GetFocus
        Debug.Print "--"
        TextBox1.SelStart = 0
        TextBox1.SelLength = Len(TextBox1.Text)
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

这产生了这个序列:

--
 <userform hwnd>
 <outer hwnd>
 <outer hwnd>
--
Run Code Online (Sandbox Code Playgroud)

正如你所看到的 - SetFocus没有效果,因为Userform不知道焦点丢失(因此也没有Exit事件).要解决这个问题,您应该通过将焦点转移到另一个子控件或切换Enabled(甚至Visible)属性来明确地失去焦点:

Private Sub TextBox1_Change()
    If Not IsNumeric(TextBox1) Then
        Debug.Print "--"
        Debug.Print GetFocus
        TextBox1.Enabled = False
        'or use CommandButton1.SetFocus or something
        MsgBox " only number"
        TextBox1.Enabled = True
        Debug.Print GetFocus
        TextBox1.SetFocus
        Debug.Print GetFocus
        Debug.Print "--"
        TextBox1.SelStart = 0
        TextBox1.SelLength = Len(TextBox1.Text)
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

这产生了所需的外观和正确的顺序:

--
 <userform hwnd>
 <outer hwnd>
 <userform hwnd>
--
Run Code Online (Sandbox Code Playgroud)

作为一个结论,原因是内部和外部的焦点状态不同步,这源于一种略有不同的管理模式MSFormsWinForms/ WinAPI或非模态的工作制度,将它们混合在一起,使得机会失去对某些事物的关注非MSForms.


小智 6

在我的Excel版本中,msgbox始终是vbModal,它不能是vbModeless,只能将其Modal范围属性设置为应用程序级别或系统级别

  • 在应用程序级别,它会在应用程序响应之前停止应用程序
  • 在系统级别,它会暂停所有应用程序,直到用户对其进行响应

为了做你想做的事; 我创建了一个无模型用户窗体并将其用作消息框

代码变成了

Private Sub TextBox1_Change()

    If Not IsNumeric(TextBox1) Then
        UserForm2.Label1 = "Only Number is Allowed"
        UserForm2.Show

        'At this point TextBox1 has lost focus,
        'to set the focus again you have to setfocus on something else
        'and then again set focus on textbox1 (a way to reinitialize it).
        'I have added a hidden textbox2 and will set focus on it

        TextBox2.Visible = True
        TextBox2.SetFocus
        TextBox2.Visible = False

        TextBox1.SetFocus
        TextBox1.SelStart = 0
        TextBox1.SelLength = Len(TextBox1.Text)

    End If

End Sub
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

截图只是一个测试,您可以根据您的应用程序进行格式化等.