无模式窗体上文本框条目的验证消息中断文本选择
Validation message of text box entry on modeless form interrupts text selection
您好,我在我的用户表单中尝试使用此代码来检查 textbox1
中输入的数据是否为数字,如果不是,则向用户显示 msgbox
并在 [= 中显示 select 文本11=],但当用户表单为 vBModeless
时,下面的代码不会 select 在 textbox1
中显示文本
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
有什么解决办法吗?
在我的版本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
截图只是测试,您可以根据自己的应用进行格式化等。
问题的根源不是选择,因为它在那里并且按预期工作:
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
控件不是真正的 windows,而是没有 window 句柄的 "windowless" 实体(当然,也有例外,例如列表框、标签条、多页),可以通过隐藏方法轻松测试:
'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]
另一方面,有 Window 的消息传递模型,其中每个控件都是 window(因此 Windows OS),具有适当的 window 处理并能够发送和接收消息,例如 WM_SETFOCUS
/WM_KILLFOCUS
并采取适当的行动。
回到 MSForms - UserForm
在内部管理外部世界和子控件之间的所有交互。
让我们从声明 WIN API 函数开始 GetFocus:
Public Declare Function GetFocus Lib "user32.dll" () As Long
让我们添加一些 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>
--
如您所见 - SetFocus
无效,因为用户窗体不知道焦点丢失(因此也没有 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
这会产生所需的外观和正确的顺序:
--
<userform hwnd>
<outer hwnd>
<userform hwnd>
--
总而言之,原因是内部和外部焦点状态不同步,这源于 MSForms
和 WinForms
/WinAPI
之间略有不同的管理模型加上非模态工作制度,将两者混合在一起,让我们有机会失去对非MSForms
.
事物的关注
我投票给 usmanhaq 和 CommonSense!
只是要补充一点:我已经尝试在我的一个项目中实现类似的东西,我最终避免弹出另一个 window。只需使用标签来提醒。
在我实现这个之后,我发现它更加用户友好!
希望对您有所帮助!
用户表单:
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
您好,我在我的用户表单中尝试使用此代码来检查 textbox1
中输入的数据是否为数字,如果不是,则向用户显示 msgbox
并在 [= 中显示 select 文本11=],但当用户表单为 vBModeless
textbox1
中显示文本
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
有什么解决办法吗?
在我的版本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
截图只是测试,您可以根据自己的应用进行格式化等。
问题的根源不是选择,因为它在那里并且按预期工作:
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
控件不是真正的 windows,而是没有 window 句柄的 "windowless" 实体(当然,也有例外,例如列表框、标签条、多页),可以通过隐藏方法轻松测试:
'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]
另一方面,有 Window 的消息传递模型,其中每个控件都是 window(因此 Windows OS),具有适当的 window 处理并能够发送和接收消息,例如 WM_SETFOCUS
/WM_KILLFOCUS
并采取适当的行动。
回到 MSForms - UserForm
在内部管理外部世界和子控件之间的所有交互。
让我们从声明 WIN API 函数开始 GetFocus:
Public Declare Function GetFocus Lib "user32.dll" () As Long
让我们添加一些 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>
--
如您所见 - SetFocus
无效,因为用户窗体不知道焦点丢失(因此也没有 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
这会产生所需的外观和正确的顺序:
--
<userform hwnd>
<outer hwnd>
<userform hwnd>
--
总而言之,原因是内部和外部焦点状态不同步,这源于 MSForms
和 WinForms
/WinAPI
之间略有不同的管理模型加上非模态工作制度,将两者混合在一起,让我们有机会失去对非MSForms
.
我投票给 usmanhaq 和 CommonSense!
只是要补充一点:我已经尝试在我的一个项目中实现类似的东西,我最终避免弹出另一个 window。只需使用标签来提醒。
在我实现这个之后,我发现它更加用户友好!
希望对您有所帮助!
用户表单:
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