Сообщение проверки ввода текстового поля на немодальной форме прерывает выбор текста - PullRequest
0 голосов
/ 20 ноября 2018

Привет. Я пытаюсь использовать этот код в своей пользовательской форме, чтобы проверить, являются ли данные, введенные в textbox1, числом, и если пользователь не отображает msgbox, и выбрать текст в textbox1, но код ниже не выделяет текст.в textbox1 когда пользовательская форма 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

есть какое-либо решение?

Ответы [ 3 ]

0 голосов
/ 27 ноября 2018

Корень проблемы не в выборе, так как он существует и работает как положено:

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

Я думаю, что фундаментальная проблема здесь в том, что MSForms элементы управления не являются реальными окнами, но«безоконный» объект без дескриптора окна (конечно, есть исключения, такие как listbox, tabstrip, multipage), который легко проверить с помощью скрытого метода:

'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]

С другой стороны, существует модель передачи сообщений Window, в которойкаждый элемент управления - это окно (отсюда и ОС Windows) с соответствующим дескриптором окна и способностью отправлять и получать сообщения, такие как WM_SETFOCUS / WM_KILLFOCUS и действовать соответствующим образом.И обратно к MSForms - UserForm управляет всем взаимодействием между внешним миром и дочерними элементами управления внутри.

Давайте начнем с объявления функции WIN API GetFocus :

Public Declare Function GetFocus Lib "user32.dll" () As Long

И давайте добавим несколько Debug.Print, чтобы увидеть, что происходит:

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

Что дает следующую последовательность:

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

Как вы можете видеть - SetFocus не имеет никакого эффекта, потому что пользовательская форма не имеет представления о том, что фокус потерян (следовательно, нет события Exitили).Чтобы преодолеть эту проблему, вы должны явно потерять фокус, передав фокус другому дочернему элементу управления или переключив свойство Enabled (или даже Visible):

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

, что дает желаемый вид и правильную последовательность:

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

В заключение, причина в том, что внутренние и внешние состояния фокуса вышли из синхронизации, что вытекает из немного другой модели управления между MSForms и WinForms / WinAPI плюс не-модальный режим работы, который смешивает их обоих, давая возможность потерять фокус на чем-то не MSForms.

0 голосов
/ 01 декабря 2018

Я голосую за usmanhaq и CommonSense!

просто кое-что добавлю: я попытался внедрить аналогичную вещь в одном из моих проектов, в итоге я избегаю всплывающего окна.Просто используйте ярлык для предупреждения.

И после этого я нахожу это более удобным для пользователя!

Надеюсь, это поможет!

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

эта функция финансируется в режиме онлайн, что поможет выделить, начиная с первого не номера

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
0 голосов
/ 26 ноября 2018

В моей версии Excel msgbox всегда vbModal, он не может быть vbModeless, вы можете установить только его свойство Modal scope в качестве уровня приложения или уровня системы

  • На уровне приложения он останавливаетсяприложение, пока оно не отвечает
  • На уровне системы оно приостанавливает все приложения до тех пор, пока пользователь не ответит на него

Для того, чтобы делать то, что вы собираетесь делать;Я создал немодальную пользовательскую форму и использую ее как окно сообщения

Код становится

Private Sub TextBox1_Change()

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

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

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

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

    End If

End Sub

enter image description here

Снимок экрана толькотест, вы можете сделать форматирование и т. д. в соответствии с вашим приложением.

...