Validation message of text box entry on modeless form interrupts text selection











up vote
4
down vote

favorite
3












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?










share|improve this question




















  • 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 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










  • 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















up vote
4
down vote

favorite
3












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?










share|improve this question




















  • 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 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










  • 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













up vote
4
down vote

favorite
3









up vote
4
down vote

favorite
3






3





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?










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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










  • 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














  • 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 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










  • 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








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












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


enter image description here



The screenshot is only a test, you can do the formatting etc according to your application.






share|improve this answer





















  • 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












  • @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


















up vote
7
down vote



+100










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.






share|improve this answer























  • 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


















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


enter image description here



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





share|improve this answer





















    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
    });


    }
    });














    draft saved

    draft discarded


















    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


    enter image description here



    The screenshot is only a test, you can do the formatting etc according to your application.






    share|improve this answer





















    • 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












    • @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















    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


    enter image description here



    The screenshot is only a test, you can do the formatting etc according to your application.






    share|improve this answer





















    • 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












    • @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













    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


    enter image description here



    The screenshot is only a test, you can do the formatting etc according to your application.






    share|improve this answer












    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


    enter image description here



    The screenshot is only a test, you can do the formatting etc according to your application.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    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 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












    • @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










    • 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












    up vote
    7
    down vote



    +100










    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.






    share|improve this answer























    • 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















    up vote
    7
    down vote



    +100










    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.






    share|improve this answer























    • 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













    up vote
    7
    down vote



    +100







    up vote
    7
    down vote



    +100




    +100




    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.






    share|improve this answer














    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.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    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


















    • 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










    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


    enter image description here



    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





    share|improve this answer

























      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


      enter image description here



      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





      share|improve this answer























        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


        enter image description here



        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





        share|improve this answer












        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


        enter image description here



        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






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Dec 1 at 3:26









        li rachel

        1544




        1544






























            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            404 Error Contact Form 7 ajax form submitting

            How to know if a Active Directory user can login interactively

            TypeError: fit_transform() missing 1 required positional argument: 'X'