Validation message of text box entry on modeless form interrupts text selection
up vote
4
down vote
favorite
Hi I try this code in my Userform to check if Data entered in textbox1
is a number and if is not show a msgbox
to user and select text in textbox1
, but below code doesn't select text in textbox1
when Userform is 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
is any solution?
excel vba excel-vba userform
|
show 1 more comment
up vote
4
down vote
favorite
Hi I try this code in my Userform to check if Data entered in textbox1
is a number and if is not show a msgbox
to user and select text in textbox1
, but below code doesn't select text in textbox1
when Userform is 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
is any solution?
excel vba excel-vba userform
3
When you say code doesn't work, how does it not work exactly? Does it produce an error, does the MsgBox not show, or something else?
– Martin Parkin
Nov 20 at 12:27
1
@MartinParkin you right I should give more details, Code works, msgbox shows but text in textbox not selected.
– Avax
Nov 21 at 5:26
Have you tried verifying the input in theTextBox1_Exit()
sub instead of in theChange
? You should also be able to setCancel
to true to prevent them leaving until the input's valid.
– Mistella
Nov 26 at 20:04
Another option would be using theKey_Down
event (or maybeKey_Press
?) to check if the unicode is for a number, and if not, "cancel" the keypress.
– Mistella
Nov 26 at 20:08
I still encourage any valid approach that actually includes text selection afterMsgBox
execution, though OP has been accepted already by Avax. I agree with @Mistella that the key to a solution should be found in the control's chain of events.
– T.M.
Nov 27 at 7:53
|
show 1 more comment
up vote
4
down vote
favorite
up vote
4
down vote
favorite
Hi I try this code in my Userform to check if Data entered in textbox1
is a number and if is not show a msgbox
to user and select text in textbox1
, but below code doesn't select text in textbox1
when Userform is 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
is any solution?
excel vba excel-vba userform
Hi I try this code in my Userform to check if Data entered in textbox1
is a number and if is not show a msgbox
to user and select text in textbox1
, but below code doesn't select text in textbox1
when Userform is 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
is any solution?
excel vba excel-vba userform
excel vba excel-vba userform
edited Nov 25 at 18:10
Paul
3,26111739
3,26111739
asked Nov 20 at 12:24
Avax
337
337
3
When you say code doesn't work, how does it not work exactly? Does it produce an error, does the MsgBox not show, or something else?
– Martin Parkin
Nov 20 at 12:27
1
@MartinParkin you right I should give more details, Code works, msgbox shows but text in textbox not selected.
– Avax
Nov 21 at 5:26
Have you tried verifying the input in theTextBox1_Exit()
sub instead of in theChange
? You should also be able to setCancel
to true to prevent them leaving until the input's valid.
– Mistella
Nov 26 at 20:04
Another option would be using theKey_Down
event (or maybeKey_Press
?) to check if the unicode is for a number, and if not, "cancel" the keypress.
– Mistella
Nov 26 at 20:08
I still encourage any valid approach that actually includes text selection afterMsgBox
execution, though OP has been accepted already by Avax. I agree with @Mistella that the key to a solution should be found in the control's chain of events.
– T.M.
Nov 27 at 7:53
|
show 1 more comment
3
When you say code doesn't work, how does it not work exactly? Does it produce an error, does the MsgBox not show, or something else?
– Martin Parkin
Nov 20 at 12:27
1
@MartinParkin you right I should give more details, Code works, msgbox shows but text in textbox not selected.
– Avax
Nov 21 at 5:26
Have you tried verifying the input in theTextBox1_Exit()
sub instead of in theChange
? You should also be able to setCancel
to true to prevent them leaving until the input's valid.
– Mistella
Nov 26 at 20:04
Another option would be using theKey_Down
event (or maybeKey_Press
?) to check if the unicode is for a number, and if not, "cancel" the keypress.
– Mistella
Nov 26 at 20:08
I still encourage any valid approach that actually includes text selection afterMsgBox
execution, though OP has been accepted already by Avax. I agree with @Mistella that the key to a solution should be found in the control's chain of events.
– T.M.
Nov 27 at 7:53
3
3
When you say code doesn't work, how does it not work exactly? Does it produce an error, does the MsgBox not show, or something else?
– Martin Parkin
Nov 20 at 12:27
When you say code doesn't work, how does it not work exactly? Does it produce an error, does the MsgBox not show, or something else?
– Martin Parkin
Nov 20 at 12:27
1
1
@MartinParkin you right I should give more details, Code works, msgbox shows but text in textbox not selected.
– Avax
Nov 21 at 5:26
@MartinParkin you right I should give more details, Code works, msgbox shows but text in textbox not selected.
– Avax
Nov 21 at 5:26
Have you tried verifying the input in the
TextBox1_Exit()
sub instead of in the Change
? You should also be able to set Cancel
to true to prevent them leaving until the input's valid.– Mistella
Nov 26 at 20:04
Have you tried verifying the input in the
TextBox1_Exit()
sub instead of in the Change
? You should also be able to set Cancel
to true to prevent them leaving until the input's valid.– Mistella
Nov 26 at 20:04
Another option would be using the
Key_Down
event (or maybe Key_Press
?) to check if the unicode is for a number, and if not, "cancel" the keypress.– Mistella
Nov 26 at 20:08
Another option would be using the
Key_Down
event (or maybe Key_Press
?) to check if the unicode is for a number, and if not, "cancel" the keypress.– Mistella
Nov 26 at 20:08
I still encourage any valid approach that actually includes text selection after
MsgBox
execution, though OP has been accepted already by Avax. I agree with @Mistella that the key to a solution should be found in the control's chain of events.– T.M.
Nov 27 at 7:53
I still encourage any valid approach that actually includes text selection after
MsgBox
execution, though OP has been accepted already by Avax. I agree with @Mistella that the key to a solution should be found in the control's chain of events.– T.M.
Nov 27 at 7:53
|
show 1 more comment
3 Answers
3
active
oldest
votes
up vote
6
down vote
accepted
In my version of Excel A msgbox is always vbModal, it cannot be vbModeless, you can only set its Modal scope property to be as application level or system level
- At Application level, it stops the application until it is responded
- At system level it suspends all applications until the user responds
to it
In order to do what you intend to do; I have created a Modeless UserForm and use it as a message box
The code becomes
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
The screenshot is only a test, you can do the formatting etc according to your application.
My simple hope is a solution that selects the validated text after actually executing aMsgBox
statement (VBA.Interaction class element). But I appreciate your approach to replace the causing obstacle.
– T.M.
Nov 26 at 18:04
What I have tested on my PC is; the msgbox is a Modal dialog, it stops execution of the application. For an example, if you put two msgbox statements they will never show up at once, you have to close first to resume the program and the second one will show up. Maybe the only way could be to make a system call somehow to change the vbModal behavior to vbModeless. Maybe if it is possible it can work.
– usmanhaq
Nov 27 at 0:33
@usmanhaq, Thank you for your help I modified your code in my project and its working perfectly ;)
– Avax
Nov 27 at 5:32
You might be interested in some amplifying links to (modeless) UserForms: Destroy a modeless Userform instance properly, The perfect UserForm in VBA; cf. also Apply logic for UserForm dialog
– T.M.
Nov 29 at 19:47
add a comment |
up vote
7
down vote
The root of the problem isn't a selection, since it there and works as expected:
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
I think the fundamental problem here is that MSForms
controls aren't real windows, but "windowless" entity without window handle (of course, there's exceptions like listbox, tabstrip, multipage), which easily can be tested via hidden method:
'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]
In other hand there's the Window's message-passing model where each control is a window (hence Windows OS) with a proper window handle and with ability to send and recive messages like WM_SETFOCUS
/WM_KILLFOCUS
and act appropriately.
And back to MSForms - the UserForm
manages all the interaction between outer world and child controls internally.
Let's start by declaring WIN API function GetFocus:
Public Declare Function GetFocus Lib "user32.dll" () As Long
And let's add some of Debug.Print
's to see what is happening:
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
Which yields this sequence:
--
<userform hwnd>
<outer hwnd>
<outer hwnd>
--
As you can see - the SetFocus
has no effect, because the Userform has no idea that focus is lost (hence there's no Exit
event either). To overcome this problem you should explicitly lose your focus by transferring focus to another child control or by switching Enabled
(or even Visible
) property:
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
Which yields a desired appearance and a proper sequence:
--
<userform hwnd>
<outer hwnd>
<userform hwnd>
--
As a conclusion, the cause is internal and external focus states got out of sync, which stems from a slightly different managment model between MSForms
and WinForms
/WinAPI
plus a non-modal regime of work, that mixes them both, giving an opportunity to lose focus to something non-MSForms
.
Conclusive steps, instructive description, simple solution - an exemplary answer ... or even two answers: 1) switching the.Enabled
property, 2) losing focus via any other control accepting focus (BTW found this 2nd approach this morning, too). Hopefully for many upvotes :-)
– T.M.
Nov 27 at 10:38
I loved the instructive and conclusive way you got to a solution and am happy to award this bounty to you. I did learn from your answer :-) @CommonSense
– T.M.
Dec 1 at 20:00
add a comment |
up vote
1
down vote
I vote for usmanhaq and CommonSense!
just something to add: I've tried to implement similiar thing on one of my projects, I end up avoiding pop up another window. Just use a label to alert.
And after i implement this i find this more userfriendly!
Hope this helps!
userform:
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
this function is funded online that would help highlight starting from the first non number
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
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53392937%2fvalidation-message-of-text-box-entry-on-modeless-form-interrupts-text-selection%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
6
down vote
accepted
In my version of Excel A msgbox is always vbModal, it cannot be vbModeless, you can only set its Modal scope property to be as application level or system level
- At Application level, it stops the application until it is responded
- At system level it suspends all applications until the user responds
to it
In order to do what you intend to do; I have created a Modeless UserForm and use it as a message box
The code becomes
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
The screenshot is only a test, you can do the formatting etc according to your application.
My simple hope is a solution that selects the validated text after actually executing aMsgBox
statement (VBA.Interaction class element). But I appreciate your approach to replace the causing obstacle.
– T.M.
Nov 26 at 18:04
What I have tested on my PC is; the msgbox is a Modal dialog, it stops execution of the application. For an example, if you put two msgbox statements they will never show up at once, you have to close first to resume the program and the second one will show up. Maybe the only way could be to make a system call somehow to change the vbModal behavior to vbModeless. Maybe if it is possible it can work.
– usmanhaq
Nov 27 at 0:33
@usmanhaq, Thank you for your help I modified your code in my project and its working perfectly ;)
– Avax
Nov 27 at 5:32
You might be interested in some amplifying links to (modeless) UserForms: Destroy a modeless Userform instance properly, The perfect UserForm in VBA; cf. also Apply logic for UserForm dialog
– T.M.
Nov 29 at 19:47
add a comment |
up vote
6
down vote
accepted
In my version of Excel A msgbox is always vbModal, it cannot be vbModeless, you can only set its Modal scope property to be as application level or system level
- At Application level, it stops the application until it is responded
- At system level it suspends all applications until the user responds
to it
In order to do what you intend to do; I have created a Modeless UserForm and use it as a message box
The code becomes
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
The screenshot is only a test, you can do the formatting etc according to your application.
My simple hope is a solution that selects the validated text after actually executing aMsgBox
statement (VBA.Interaction class element). But I appreciate your approach to replace the causing obstacle.
– T.M.
Nov 26 at 18:04
What I have tested on my PC is; the msgbox is a Modal dialog, it stops execution of the application. For an example, if you put two msgbox statements they will never show up at once, you have to close first to resume the program and the second one will show up. Maybe the only way could be to make a system call somehow to change the vbModal behavior to vbModeless. Maybe if it is possible it can work.
– usmanhaq
Nov 27 at 0:33
@usmanhaq, Thank you for your help I modified your code in my project and its working perfectly ;)
– Avax
Nov 27 at 5:32
You might be interested in some amplifying links to (modeless) UserForms: Destroy a modeless Userform instance properly, The perfect UserForm in VBA; cf. also Apply logic for UserForm dialog
– T.M.
Nov 29 at 19:47
add a comment |
up vote
6
down vote
accepted
up vote
6
down vote
accepted
In my version of Excel A msgbox is always vbModal, it cannot be vbModeless, you can only set its Modal scope property to be as application level or system level
- At Application level, it stops the application until it is responded
- At system level it suspends all applications until the user responds
to it
In order to do what you intend to do; I have created a Modeless UserForm and use it as a message box
The code becomes
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
The screenshot is only a test, you can do the formatting etc according to your application.
In my version of Excel A msgbox is always vbModal, it cannot be vbModeless, you can only set its Modal scope property to be as application level or system level
- At Application level, it stops the application until it is responded
- At system level it suspends all applications until the user responds
to it
In order to do what you intend to do; I have created a Modeless UserForm and use it as a message box
The code becomes
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
The screenshot is only a test, you can do the formatting etc according to your application.
answered Nov 26 at 12:25
usmanhaq
1,108128
1,108128
My simple hope is a solution that selects the validated text after actually executing aMsgBox
statement (VBA.Interaction class element). But I appreciate your approach to replace the causing obstacle.
– T.M.
Nov 26 at 18:04
What I have tested on my PC is; the msgbox is a Modal dialog, it stops execution of the application. For an example, if you put two msgbox statements they will never show up at once, you have to close first to resume the program and the second one will show up. Maybe the only way could be to make a system call somehow to change the vbModal behavior to vbModeless. Maybe if it is possible it can work.
– usmanhaq
Nov 27 at 0:33
@usmanhaq, Thank you for your help I modified your code in my project and its working perfectly ;)
– Avax
Nov 27 at 5:32
You might be interested in some amplifying links to (modeless) UserForms: Destroy a modeless Userform instance properly, The perfect UserForm in VBA; cf. also Apply logic for UserForm dialog
– T.M.
Nov 29 at 19:47
add a comment |
My simple hope is a solution that selects the validated text after actually executing aMsgBox
statement (VBA.Interaction class element). But I appreciate your approach to replace the causing obstacle.
– T.M.
Nov 26 at 18:04
What I have tested on my PC is; the msgbox is a Modal dialog, it stops execution of the application. For an example, if you put two msgbox statements they will never show up at once, you have to close first to resume the program and the second one will show up. Maybe the only way could be to make a system call somehow to change the vbModal behavior to vbModeless. Maybe if it is possible it can work.
– usmanhaq
Nov 27 at 0:33
@usmanhaq, Thank you for your help I modified your code in my project and its working perfectly ;)
– Avax
Nov 27 at 5:32
You might be interested in some amplifying links to (modeless) UserForms: Destroy a modeless Userform instance properly, The perfect UserForm in VBA; cf. also Apply logic for UserForm dialog
– T.M.
Nov 29 at 19:47
My simple hope is a solution that selects the validated text after actually executing a
MsgBox
statement (VBA.Interaction class element). But I appreciate your approach to replace the causing obstacle.– T.M.
Nov 26 at 18:04
My simple hope is a solution that selects the validated text after actually executing a
MsgBox
statement (VBA.Interaction class element). But I appreciate your approach to replace the causing obstacle.– T.M.
Nov 26 at 18:04
What I have tested on my PC is; the msgbox is a Modal dialog, it stops execution of the application. For an example, if you put two msgbox statements they will never show up at once, you have to close first to resume the program and the second one will show up. Maybe the only way could be to make a system call somehow to change the vbModal behavior to vbModeless. Maybe if it is possible it can work.
– usmanhaq
Nov 27 at 0:33
What I have tested on my PC is; the msgbox is a Modal dialog, it stops execution of the application. For an example, if you put two msgbox statements they will never show up at once, you have to close first to resume the program and the second one will show up. Maybe the only way could be to make a system call somehow to change the vbModal behavior to vbModeless. Maybe if it is possible it can work.
– usmanhaq
Nov 27 at 0:33
@usmanhaq, Thank you for your help I modified your code in my project and its working perfectly ;)
– Avax
Nov 27 at 5:32
@usmanhaq, Thank you for your help I modified your code in my project and its working perfectly ;)
– Avax
Nov 27 at 5:32
You might be interested in some amplifying links to (modeless) UserForms: Destroy a modeless Userform instance properly, The perfect UserForm in VBA; cf. also Apply logic for UserForm dialog
– T.M.
Nov 29 at 19:47
You might be interested in some amplifying links to (modeless) UserForms: Destroy a modeless Userform instance properly, The perfect UserForm in VBA; cf. also Apply logic for UserForm dialog
– T.M.
Nov 29 at 19:47
add a comment |
up vote
7
down vote
The root of the problem isn't a selection, since it there and works as expected:
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
I think the fundamental problem here is that MSForms
controls aren't real windows, but "windowless" entity without window handle (of course, there's exceptions like listbox, tabstrip, multipage), which easily can be tested via hidden method:
'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]
In other hand there's the Window's message-passing model where each control is a window (hence Windows OS) with a proper window handle and with ability to send and recive messages like WM_SETFOCUS
/WM_KILLFOCUS
and act appropriately.
And back to MSForms - the UserForm
manages all the interaction between outer world and child controls internally.
Let's start by declaring WIN API function GetFocus:
Public Declare Function GetFocus Lib "user32.dll" () As Long
And let's add some of Debug.Print
's to see what is happening:
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
Which yields this sequence:
--
<userform hwnd>
<outer hwnd>
<outer hwnd>
--
As you can see - the SetFocus
has no effect, because the Userform has no idea that focus is lost (hence there's no Exit
event either). To overcome this problem you should explicitly lose your focus by transferring focus to another child control or by switching Enabled
(or even Visible
) property:
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
Which yields a desired appearance and a proper sequence:
--
<userform hwnd>
<outer hwnd>
<userform hwnd>
--
As a conclusion, the cause is internal and external focus states got out of sync, which stems from a slightly different managment model between MSForms
and WinForms
/WinAPI
plus a non-modal regime of work, that mixes them both, giving an opportunity to lose focus to something non-MSForms
.
Conclusive steps, instructive description, simple solution - an exemplary answer ... or even two answers: 1) switching the.Enabled
property, 2) losing focus via any other control accepting focus (BTW found this 2nd approach this morning, too). Hopefully for many upvotes :-)
– T.M.
Nov 27 at 10:38
I loved the instructive and conclusive way you got to a solution and am happy to award this bounty to you. I did learn from your answer :-) @CommonSense
– T.M.
Dec 1 at 20:00
add a comment |
up vote
7
down vote
The root of the problem isn't a selection, since it there and works as expected:
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
I think the fundamental problem here is that MSForms
controls aren't real windows, but "windowless" entity without window handle (of course, there's exceptions like listbox, tabstrip, multipage), which easily can be tested via hidden method:
'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]
In other hand there's the Window's message-passing model where each control is a window (hence Windows OS) with a proper window handle and with ability to send and recive messages like WM_SETFOCUS
/WM_KILLFOCUS
and act appropriately.
And back to MSForms - the UserForm
manages all the interaction between outer world and child controls internally.
Let's start by declaring WIN API function GetFocus:
Public Declare Function GetFocus Lib "user32.dll" () As Long
And let's add some of Debug.Print
's to see what is happening:
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
Which yields this sequence:
--
<userform hwnd>
<outer hwnd>
<outer hwnd>
--
As you can see - the SetFocus
has no effect, because the Userform has no idea that focus is lost (hence there's no Exit
event either). To overcome this problem you should explicitly lose your focus by transferring focus to another child control or by switching Enabled
(or even Visible
) property:
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
Which yields a desired appearance and a proper sequence:
--
<userform hwnd>
<outer hwnd>
<userform hwnd>
--
As a conclusion, the cause is internal and external focus states got out of sync, which stems from a slightly different managment model between MSForms
and WinForms
/WinAPI
plus a non-modal regime of work, that mixes them both, giving an opportunity to lose focus to something non-MSForms
.
Conclusive steps, instructive description, simple solution - an exemplary answer ... or even two answers: 1) switching the.Enabled
property, 2) losing focus via any other control accepting focus (BTW found this 2nd approach this morning, too). Hopefully for many upvotes :-)
– T.M.
Nov 27 at 10:38
I loved the instructive and conclusive way you got to a solution and am happy to award this bounty to you. I did learn from your answer :-) @CommonSense
– T.M.
Dec 1 at 20:00
add a comment |
up vote
7
down vote
up vote
7
down vote
The root of the problem isn't a selection, since it there and works as expected:
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
I think the fundamental problem here is that MSForms
controls aren't real windows, but "windowless" entity without window handle (of course, there's exceptions like listbox, tabstrip, multipage), which easily can be tested via hidden method:
'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]
In other hand there's the Window's message-passing model where each control is a window (hence Windows OS) with a proper window handle and with ability to send and recive messages like WM_SETFOCUS
/WM_KILLFOCUS
and act appropriately.
And back to MSForms - the UserForm
manages all the interaction between outer world and child controls internally.
Let's start by declaring WIN API function GetFocus:
Public Declare Function GetFocus Lib "user32.dll" () As Long
And let's add some of Debug.Print
's to see what is happening:
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
Which yields this sequence:
--
<userform hwnd>
<outer hwnd>
<outer hwnd>
--
As you can see - the SetFocus
has no effect, because the Userform has no idea that focus is lost (hence there's no Exit
event either). To overcome this problem you should explicitly lose your focus by transferring focus to another child control or by switching Enabled
(or even Visible
) property:
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
Which yields a desired appearance and a proper sequence:
--
<userform hwnd>
<outer hwnd>
<userform hwnd>
--
As a conclusion, the cause is internal and external focus states got out of sync, which stems from a slightly different managment model between MSForms
and WinForms
/WinAPI
plus a non-modal regime of work, that mixes them both, giving an opportunity to lose focus to something non-MSForms
.
The root of the problem isn't a selection, since it there and works as expected:
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
I think the fundamental problem here is that MSForms
controls aren't real windows, but "windowless" entity without window handle (of course, there's exceptions like listbox, tabstrip, multipage), which easily can be tested via hidden method:
'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]
In other hand there's the Window's message-passing model where each control is a window (hence Windows OS) with a proper window handle and with ability to send and recive messages like WM_SETFOCUS
/WM_KILLFOCUS
and act appropriately.
And back to MSForms - the UserForm
manages all the interaction between outer world and child controls internally.
Let's start by declaring WIN API function GetFocus:
Public Declare Function GetFocus Lib "user32.dll" () As Long
And let's add some of Debug.Print
's to see what is happening:
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
Which yields this sequence:
--
<userform hwnd>
<outer hwnd>
<outer hwnd>
--
As you can see - the SetFocus
has no effect, because the Userform has no idea that focus is lost (hence there's no Exit
event either). To overcome this problem you should explicitly lose your focus by transferring focus to another child control or by switching Enabled
(or even Visible
) property:
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
Which yields a desired appearance and a proper sequence:
--
<userform hwnd>
<outer hwnd>
<userform hwnd>
--
As a conclusion, the cause is internal and external focus states got out of sync, which stems from a slightly different managment model between MSForms
and WinForms
/WinAPI
plus a non-modal regime of work, that mixes them both, giving an opportunity to lose focus to something non-MSForms
.
edited Nov 27 at 11:34
answered Nov 27 at 9:44
CommonSense
2,8252525
2,8252525
Conclusive steps, instructive description, simple solution - an exemplary answer ... or even two answers: 1) switching the.Enabled
property, 2) losing focus via any other control accepting focus (BTW found this 2nd approach this morning, too). Hopefully for many upvotes :-)
– T.M.
Nov 27 at 10:38
I loved the instructive and conclusive way you got to a solution and am happy to award this bounty to you. I did learn from your answer :-) @CommonSense
– T.M.
Dec 1 at 20:00
add a comment |
Conclusive steps, instructive description, simple solution - an exemplary answer ... or even two answers: 1) switching the.Enabled
property, 2) losing focus via any other control accepting focus (BTW found this 2nd approach this morning, too). Hopefully for many upvotes :-)
– T.M.
Nov 27 at 10:38
I loved the instructive and conclusive way you got to a solution and am happy to award this bounty to you. I did learn from your answer :-) @CommonSense
– T.M.
Dec 1 at 20:00
Conclusive steps, instructive description, simple solution - an exemplary answer ... or even two answers: 1) switching the
.Enabled
property, 2) losing focus via any other control accepting focus (BTW found this 2nd approach this morning, too). Hopefully for many upvotes :-)– T.M.
Nov 27 at 10:38
Conclusive steps, instructive description, simple solution - an exemplary answer ... or even two answers: 1) switching the
.Enabled
property, 2) losing focus via any other control accepting focus (BTW found this 2nd approach this morning, too). Hopefully for many upvotes :-)– T.M.
Nov 27 at 10:38
I loved the instructive and conclusive way you got to a solution and am happy to award this bounty to you. I did learn from your answer :-) @CommonSense
– T.M.
Dec 1 at 20:00
I loved the instructive and conclusive way you got to a solution and am happy to award this bounty to you. I did learn from your answer :-) @CommonSense
– T.M.
Dec 1 at 20:00
add a comment |
up vote
1
down vote
I vote for usmanhaq and CommonSense!
just something to add: I've tried to implement similiar thing on one of my projects, I end up avoiding pop up another window. Just use a label to alert.
And after i implement this i find this more userfriendly!
Hope this helps!
userform:
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
this function is funded online that would help highlight starting from the first non number
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
add a comment |
up vote
1
down vote
I vote for usmanhaq and CommonSense!
just something to add: I've tried to implement similiar thing on one of my projects, I end up avoiding pop up another window. Just use a label to alert.
And after i implement this i find this more userfriendly!
Hope this helps!
userform:
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
this function is funded online that would help highlight starting from the first non number
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
add a comment |
up vote
1
down vote
up vote
1
down vote
I vote for usmanhaq and CommonSense!
just something to add: I've tried to implement similiar thing on one of my projects, I end up avoiding pop up another window. Just use a label to alert.
And after i implement this i find this more userfriendly!
Hope this helps!
userform:
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
this function is funded online that would help highlight starting from the first non number
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
I vote for usmanhaq and CommonSense!
just something to add: I've tried to implement similiar thing on one of my projects, I end up avoiding pop up another window. Just use a label to alert.
And after i implement this i find this more userfriendly!
Hope this helps!
userform:
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
this function is funded online that would help highlight starting from the first non number
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
answered Dec 1 at 3:26
li rachel
1544
1544
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53392937%2fvalidation-message-of-text-box-entry-on-modeless-form-interrupts-text-selection%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
When you say code doesn't work, how does it not work exactly? Does it produce an error, does the MsgBox not show, or something else?
– Martin Parkin
Nov 20 at 12:27
1
@MartinParkin you right I should give more details, Code works, msgbox shows but text in textbox not selected.
– Avax
Nov 21 at 5:26
Have you tried verifying the input in the
TextBox1_Exit()
sub instead of in theChange
? You should also be able to setCancel
to true to prevent them leaving until the input's valid.– Mistella
Nov 26 at 20:04
Another option would be using the
Key_Down
event (or maybeKey_Press
?) to check if the unicode is for a number, and if not, "cancel" the keypress.– Mistella
Nov 26 at 20:08
I still encourage any valid approach that actually includes text selection after
MsgBox
execution, though OP has been accepted already by Avax. I agree with @Mistella that the key to a solution should be found in the control's chain of events.– T.M.
Nov 27 at 7:53