Существуют всего два фокус события, применение которых я видел лично: wx.EVT_SET_FOCUS и wx.EVT_KILL_FOCUS. Событие EVT_SET_FOCUS запускается, когда виджет получает фокус, например, когда вы кликаете на пустую панель или же наводите курсор на виджет TextCtrl. Когда вы кликаете за пределами виджета или переключаетесь на другое диалоговое окно, запускается процесс EVT_KILL_FOCUS.
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Приобретение (эквайринг) фокуса
Одно из нескольких «фишек», которые я заметил, листая еженедельную почтовую рассылку от wxPython, было то, что wx.Panel принимает фокус только тогда, когда у него нет дочернего виджета, который бы принял фокус вместо него. Проще будет объяснить всё это с помощью нескольких примеров.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import wx class MyForm(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, title="Focus Tutorial 1") panel = wx.Panel(self) panel.Bind(wx.EVT_SET_FOCUS, self.onFocus) def onFocus(self, event): print("panel received focus!") # Добавляем панель так, чтобы она корректно отображалась на всех платформах. if __name__ == "__main__": app = wx.App(False) frame = MyForm().Show() app.MainLoop() |
Этот код отображает пустую панель, на которой ничего нет. Вы заметите, что stdout незамедлительно получит надпись «panel received focus!», если вы используете Windows или Mac. На Linux вы получите это сообщение только если кликните на саму панель. Теперь, если вы добавите TextCtrl или кнопку, то фокус получат именно они, и хэндлер событий OnFocus не будет запущен. Попробуйте запустить код, расположенный ниже, чтобы увидеть, как это работает:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import wx class MyForm(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, title="Focus Tutorial 1a") panel = wx.Panel(self) panel.Bind(wx.EVT_SET_FOCUS, self.onFocus) txt = wx.TextCtrl(panel, wx.ID_ANY, "") def onFocus(self, event): print("panel received focus!") if __name__ == "__main__": app = wx.App(False) frame = MyForm().Show() app.MainLoop() |
Забавы ради, попробуйте вставить в эту панель StaticText вместо TextCtrl. Какой виджет по-вашему получит фокус? В зависимости от того, на какой платформе запущен следующий код, вы можете прийти к тому, что ничего не находится в фокусе. Со мной подобное произошло на Linux. На Windows 7, панель была в фокусе. В то время, когда я ещё пользовался Windows XP, фокус получил Frame. В любом случае, давайте взглянем на код:
Главное, что можно вынести из этих экспериментов, это то, что wx.Window.FindFocus() является очень полезной функцией, и она поможет вам, когда вы будете пытаться выяснить то, почему фокус находится не в том месте, в котором вы предполагали. Конечно, некоторые из вас знают что, когда курсор мыши попадает в рамку, и что информацию об этом можно получить посредством EVT_ENTER_WINDOW (которому я не буду уделять внимания в этой статье.
Потеря фокуса
Теперь давайте быстренько разберёмся с wx.EVT_KILL_FOCUS. Я создал простой пример, содержащий всего два элемента контроля. Попробуйте догадаться, что произойдёт, если вы переключитесь между ними.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import wx class MyForm(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, title="Losing Focus") # Добавляем панель так, чтобы она корректно отображалась на всех платформах. panel = wx.Panel(self, wx.ID_ANY) txt = wx.TextCtrl(panel, value="") txt.Bind(wx.EVT_SET_FOCUS, self.onFocus) txt.Bind(wx.EVT_KILL_FOCUS, self.onKillFocus) btn = wx.Button(panel, wx.ID_ANY, "Test") sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(txt, 0, wx.ALL, 5) sizer.Add(btn, 0, wx.ALL, 5) panel.SetSizer(sizer) def onFocus(self, event): print("widget received focus!") def onKillFocus(self, event): print("widget lost focus!") if __name__ == "__main__": app = wx.App(False) frame = MyForm().Show() app.MainLoop() |
Как вы могли предполагать, когда вы переключитесь между ними, TextCtrl может запустить как отмену фокуса, так и запуск фокуса. Как узнать какой из виджетов запускает эти события? Посмотрите на мои методы Бинда. Только текстовые контроли могут запускать события фокуса. В качестве упражнения попробуйте забиндить кнопку и на эти хэндлеры, а затем вывести на экран сообщение о том, какие виджеты запускают определённые события.
Последнее событие фокуса, которое я собираюсь рассматривать называется wx.EVT_CHILD_FOCUS, которым я сам, честно говоря, никогда не пользовался. Это событие используется, чтобы определить то, когда дочерний виджет получает фокус, и чтобы выяснить, производным от какого виджета он является.
По словам Робина Данна, wx.lib.scrolledpanel использует это событие. Один из моих читателей поделился со мной удобным случаем, в котором можно использовать wx.EVT_CHILD_FOCUS: «Вы можете использовать его в рамке, чтобы просто очистить панель статуса посредством нажатия на любой другой дочерний виджет. Таким образом вы не получите старое сообщение «â€oeError※ или подобный текст в панели статуса, когда вы нажмёте на другой дочерний виджет.» (hattip @devplayer)
Итоги
Теперь вы уже должны знать достаточно о том, как работает фокусировка в wxPython, так что можете использовать её в своих приложениях. Также вы узнали о том, как выявить фокус в различных обстоятельствах. Мы также написали приложение, которое может дать нам знать о том, когда оно в фокусе, а когда нет. И, наконец, мы узнали, как теряется фокус, что может быть также очень полезно в некоторых случаях.
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»