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

Excel 无模式表单上文本框条目的验证消息会中断文本选择,excel,vba,userform,Excel,Vba,Userform,您好,我在我的Userform中尝试此代码,以检查textbox1中输入的数据是否是数字,如果不是,则向用户显示msgbox并选择textbox1中的文本,但当Userform为vBModeless时,下面的代码不会选择textbox1中的文本 专用子文本框1_更改 如果不是IsNumericTextBox1,则 仅MsgBox编号 TextBox1.SetFocus TextBox1.SelStart=0 TextBox1.SelLength=LenTextBox1.Text 如果结束 端接头

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

专用子文本框1_更改 如果不是IsNumericTextBox1,则 仅MsgBox编号 TextBox1.SetFocus TextBox1.SelStart=0 TextBox1.SelLength=LenTextBox1.Text 如果结束 端接头
有解决方案吗?

在我的Excel版本中,msgbox始终是VBMODEL,它不能是无VBMODEL的,您只能将其Modal scope属性设置为应用程序级或系统级

在应用程序级别,它停止应用程序,直到响应为止 在系统级,它暂停所有应用程序,直到用户响应 对它 为了做你想做的事;我创建了一个无模式用户表单,并将其用作消息框

代码变为

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

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

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

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
我认为这里的根本问题是,MSForms控件不是真正的窗口,而是没有窗口句柄的无窗口实体。当然,也有例外情况,如listbox、tabstrip、multipage,可以通过隐藏方法轻松测试:

'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]
另一方面,还有窗口的消息传递模型,其中每个控件都是一个窗口,因此Windows操作系统具有适当的窗口句柄,能够发送和接收诸如WM_SETFOCUS/WM_KILLFOCUS之类的消息,并采取适当的行动。 回到MSForms——用户表单管理外部世界和内部子控件之间的所有交互

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

让我们添加一些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
这就产生了这个序列:

--
 <userform hwnd>
 <outer hwnd>
 <outer hwnd>
--
--
 <userform hwnd>
 <outer hwnd>
 <userform hwnd>
--
产生理想的外观和正确的顺序:

--
 <userform hwnd>
 <outer hwnd>
 <outer hwnd>
--
--
 <userform hwnd>
 <outer hwnd>
 <userform hwnd>
--

总之,原因是内部和外部焦点状态不同步,这源于MSForms和WinForms/WinAPI之间的管理模式稍有不同,再加上非模态工作模式,两者混合在一起,给了非MSForms失去焦点的机会。

我投票支持usmanhaq和CommonSense

需要补充的是:我曾尝试在我的一个项目上实现类似的东西,但最终我避免了弹出另一个窗口。只需使用标签提醒即可

在我实现了这一点之后,我发现这更方便用户

希望这有帮助

用户表单:

Private Sub TextBox1_Change()
If Not IsNumeric(TextBox1.Value) Then
    Label1.Caption = "NUMBER ONLY!"
    UserForm1.TextBox1.SetFocus
    UserForm1.TextBox1.SelStart = FirstNonDigit(TextBox1.Value) - 1
    UserForm1.TextBox1.SelLength = Len(TextBox1.Text)
Else
     Label1.Caption = ""
End If
End Sub
该功能由在线资助,有助于从第一个非数字开始突出显示

Public Function FirstNonDigit(xStr As String) As Long
    Dim xChar As Integer
    Dim xPos As Integer
    Dim I As Integer
    Application.Volatile
    For I = 1 To Len(xStr)
        xChar = Asc(Mid(xStr, I, 1))
        If xChar <= 47 Or _
           xChar >= 58 Then
            xPos = I
            Exit For
        End If
    Next
    FirstNonDigit = xPos
End Function

当你说代码不起作用时,它到底是怎么起作用的?它是否产生错误,MsgBox是否未显示,或其他内容?@MartinParkin你说得对,我应该提供更多详细信息,代码有效,MsgBox显示但文本框中的文本未选中。你是否尝试验证文本框1_Exit sub中的输入而不是更改中的输入?您还应该能够将“取消”设置为“真”,以防止它们在输入有效之前离开。另一个选项是使用“向下键”事件,或者可能是按键?要检查unicode是否为数字,如果不是,请取消按键。我仍然鼓励任何有效的方法,在MsgBox执行后实际包括文本选择,尽管OP已经被Avax接受。我同意@Mistella的观点,解决方案的关键应该在控件的事件链中找到。我的简单希望是在实际执行MsgBox语句VBA.Interaction类元素后选择验证文本的解决方案。但我很欣赏你的方法来取代造成的障碍;msgbox是一个模式对话框,它停止应用程序的执行。例如,如果放置两条msgbox语句,它们将永远不会同时显示,则必须先关闭一条语句才能恢复程序,然后再显示第二条语句。也许唯一的方法是以某种方式进行系统调用,将vbModal行为更改为VBMODEL无模式。如果可能的话,它可能会工作。@usmanhaq,谢谢你的帮助,我在我的项目中修改了你的代码,它工作得很好;您可能对一些指向无模式用户表单的放大链接感兴趣:;参考结论性步骤、指导性描述、简单解决方案-示例性答案。。。或者甚至有两个答案:1切换.Enabled属性,2通过任何其他接受焦点的控件失去焦点BTW今天早上也发现了第二种方法。希望有很多人支持我:-我喜欢你得到解决方案的启发性和决定性的方式,我很高兴把这笔奖金奖励给你。我确实从你的回答中学到了:-@常识