Почему после события EVT_KILL_FOCUS мигающий курсор в TextCtrl исчезает?

У меня есть TextCtrl, у которого есть событие EVT_KILL_FOCUS, которое я использую для проверки содержимого поля, оповещая пользователя о неправильном значении. После открытия MessageBox я очищаю поле и устанавливаю фокус на поле, которое я оставил проверить снова. Проблема в том, что исчезает мигающий курсор текста, который должен появиться внутри поля, и я не знаю, почему или как это исправить. Это приводит к тому, что пользователь не знает, в каком поле находится фокус.

У кого-нибудь есть какие-либо идеи?

    ...
    self.txtCode = wx.TextCtrl(self, value='')
    self.txtCode.Bind(wx.EVT_KILL_FOCUS, self.__onTxtCodeKillFocus)
    self.txtCode.Bind(wx.EVT_CHAR_HOOK, self.__onTxtCodeTabKey)

def __validateTxtCodeContent(self):
    if self.txtCode.GetValue() == "":
        self.MessageBox(self, "Error Text", _("Warning"))
        return False
    return True

def __onTxtCodeKillFocus(self, event):
    event.Skip()
    if self.__validateTxtCodeContent() == False:
        self.txtCode.SetValue("")
        self.txtCode.SetFocus()

def __onTxtCodeTabKey(self, event):
    key = event.GetKeyCode()
    shift = event.ShiftDown()

    # 9 = TAB, 13 = ENTER
    if key != 9 and key != 13:
        event.Skip()
        return
    elif key == 9:
        if self.__validateTxtCodeContent():
            if shift:
                self.btnSave.SetFocus()
            else:
                self.txtDescription.SetFocus()
        else:
            self.txtCode.SetValue("")
            self.txtCode.SetFocus()
    else:
        return False

Моя проверка не только для пустого поля, но, например, может быть только пустое поле.

Важное замечание: В событии EVT_CHAR_HOOK такое поведение также происходит.

Я пытался использовать это тоже:

self.txtCode.SetValue("")
self.txtCode.SetFocus()
self.txtCode.SetInsertionPointEnd() 
self.txtCode.Refresh()

Но это не сработало.

2 ответа

Решение

Ты не можешь позвонить SetFocus() от KILL_FOCUS обработчик. Самый прямой обходной путь заключается в использовании CallAfter() называть его чуть позже, но даже если это "сработает", это очень плохая идея, потому что вы не должны мешать пользователю покинуть окно - и нет никакого способа полностью предотвратить это.

Просто пометьте код как недействительный (например, измените его фон), но не пытайтесь сохранять фокус, когда вы его теряете.

PS звоню MessageBox() от обработчика событий фокуса может быть плохой идеей во многих случаях, лучше использовать wxLogWarning() или же CallAfter() отложить показ окна сообщения до следующей итерации цикла событий.

В дополнение к тому, что Вадим уже сказал:

  • Вы можете выполнить проверку нажатием кнопки "ОК" или когда диалоговое окно / панель закрывается.

  • Вы можете использовать wxValidator для проверки ввода пользователя в зависимости от вашей задачи.

Другие вопросы по тегам