В этой статье я расскажу, как обнаружить особые нажатия горячих клавиш и почему это может быть полезным. В самом деле, обнаруживать такие клавиши достаточно просто, но иногда удивляет то, что один виджет ведёт себя совершенно отлично от другого. Самое сложное наступает, когда нужно захватить EVT_CHAR.
Примечание: примеры, которые я рассматриваю в данной статье, не работают на Mac OSX El Capitan.
Сначала я расскажу о событиях, вызываемых горячими клавишами, wx.EVT_KEY_DOWN и wx.EVT_KEY_UP, а потом уже погружусь в сложности wx.EVT_CHAR.
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Обнаружение событий, связанных с горячими клавишами
Обнаружение событий в wxPython, связанных с горячими клавишами, в wxPython – процесс достаточно простой. Всё, что нужно, это выяснить код какой клавиши вы хотите обнаружить в документации wxPython, или обнаружить все клавиши и запомнить (читай, записать) все коды, которые срабатывают при нажатии горячих клавиш. Давайте посмотрим:
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 |
import wx class MyForm(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, title="Key Press Tutorial") panel = wx.Panel(self, wx.ID_ANY) btn = wx.Button(panel, label="OK") btn.Bind(wx.EVT_KEY_DOWN, self.onKeyPress) def onKeyPress(self, event): keycode = event.GetKeyCode() print(keycode) if keycode == wx.WXK_SPACE: print("you pressed the spacebar!") event.Skip() if __name__ == "__main__": app = wx.App(True) frame = MyForm() frame.Show() app.MainLoop() |
Вы заметите, что в данном фрагменте кода виджетами последствий являются только панель и кнопка. Я привязываю клавишу к EVT_KEY_DOWN и проверяю в хэндлере, нажимал ли пользователь пробел. Событие запускается только если клавиша была нажата. Вы также заметите, что я вызывал event.Skip в конце. Если вы не вызовете event.Skip, то клавиша будет поглощена и не будет запущено соответствующее событие горячей клавиши. Это не повлияет на кнопку, но в командной строке события горячих клавиш подходят для обнаружения верхнего и нижнего регистров, ударений, умляутов и им подобных.
Я использовал подобный метод для отслеживания нажатий клавиш-стрелок в моём приложении, которое являлось таблицей. Я хотел быть способным обнаруживать данные клавиши во время редактирования ячейки, чтобы нажатие стрелки делало активно другую ячейку. Это не поведение по умолчанию. В сетке, каждая ячейка имеет собственный редактор, а нажатие клавиш-стрелок перемещало курсор внутри ячейки.
Когда вы запускаете код, написанный выше, и нажимаете пробел, то должны увидеть что-то похожее на этот скриншот:
Просто эксперимента ради, я создал пример, похожий на тот, что вы видите выше, только теперь я привязал события, связанные с нажатием клавиш вверх и вниз к двум разным виджетам. Для этого понадобиться следующий код:
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 32 33 34 35 36 37 38 39 40 41 42 43 |
import wx class MyForm(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, title="Key Press Tutorial 2") panel = wx.Panel(self, wx.ID_ANY) sizer = wx.BoxSizer(wx.VERTICAL) btn = self.onWidgetSetup(wx.Button(panel, label="OK"), wx.EVT_KEY_UP, self.onButtonKeyEvent, sizer) txt = self.onWidgetSetup(wx.TextCtrl(panel, value=""), wx.EVT_KEY_DOWN, self.onTextKeyEvent, sizer) panel.SetSizer(sizer) def onWidgetSetup(self, widget, event, handler, sizer): widget.Bind(event, handler) sizer.Add(widget, 0, wx.ALL, 5) return widget def onButtonKeyEvent(self, event): keycode = event.GetKeyCode() print(keycode) if keycode == wx.WXK_SPACE: print("you pressed the spacebar!") event.Skip() def onTextKeyEvent(self, event): keycode = event.GetKeyCode() print(keycode) if keycode == wx.WXK_DELETE: print("you pressed the delete key!") event.Skip() if __name__ == "__main__": app = wx.App(True) frame = MyForm() frame.Show() app.MainLoop() |
Когда запустите код, написанный выше, попробуйте нажать на кнопку и затем на пробел. Затем переместите фокус с текстового поля и нажмите клавишу «Delete». Когда вы закончите, то должны увидеть что-то вроде этого скриншота:
Попробуйте нажать другие клавиши, и вы увидите, что коды горячих клавиш распечатались для каждой клавиши.
Соглашусь, этот код скорее для иллюстрации. Главное, что вам нужно знать это то, что вы действительно не используете EVT_KEY_UP до тех пор, пока вам не понадобится отслеживать несколько комбинаций из двух-трёх клавиш вроде CTRL+K+Y, или что-то подобное (в качестве дополнительного замечания: ознакомитесь с возможностями wx.AcceleratorTable). Так как я не делаю этого в своём примере, стоит отметить, что если вы проверяете клавишу CTRL, то лучше будет использовать event.CmdDown(), чем event.ControlDown. Причина в том, что CmdDown является эквивалентом для ControlDown на Windows и Linux, но в Mac он симулирует клавишу Command. Таким образом, CmdDown лучший кроссплатформенный способ проверки нажатия клавиши CTRL.
И это, пожалуй, всё, что вам нужно знать о событиях, связанных с горячими клавишами. Теперь давайте разберёмся с char-событиями.
Обнаружение с char-событий
Обнаружение с char-событий немного сложнее, но не слишком. Давайте взглянем на пример, чтобы понять какие существуют отличия.
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 32 |
import wx class MyForm(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, title="Char Event Tutorial") # Add a panel so it looks the correct on all platforms panel = wx.Panel(self, wx.ID_ANY) btn = wx.TextCtrl(panel, value="") btn.Bind(wx.EVT_CHAR, self.onCharEvent) def onCharEvent(self, event): keycode = event.GetKeyCode() controlDown = event.CmdDown() altDown = event.AltDown() shiftDown = event.ShiftDown() print(keycode) if keycode == wx.WXK_SPACE: print("you pressed the spacebar!") elif controlDown and altDown: print(keycode) event.Skip() if __name__ == "__main__": app = wx.App(True) frame = MyForm() frame.Show() app.MainLoop() |
Я думаю, что главное отличие в том, что вы захотите проверять ударения или международные знаки. Таким образом, у вас будут сложные условия, которые проверяют были ли нажаты определённые клавиши и в каком порядке. Робин Данн (создатель wxPython) сказал, что wxSTC проверять и события, связанные с горячими клавишами, и char-события. Если в ваши планы входит поддержка пользователей за пределами англоязычных стран, вы, скорее всего, захотите узнать, как это работает.
Цитата Робина Дана: «Если вы хотите, чтобы события, связанные с горячими клавишами, выполняли «команды» внутри приложения, используйте сырые значения в хэндлере EVT_KEY_DOWN. Как бы то ни было, если в перечень возможностей приложения входит ввод текста, тогда оно должно использовать готовые значения в хэндлере события EVT_CHAR, чтобы нормально обрабатывать не английскую раскладку клавиатуры и другие редакторы методов ввода. (Примечание: события keydown/keyup считаются сырыми, в то время как char-события считаются готовыми).
Как мне объяснил Робин Дан, во всех раскладках клавиатуры, кроме английской, заготовка клавиш для char-событий является мэппингом физических клавиш к национальной раскладке клавиатуры, чтобы появлялись символы с ударениями, умляутами и прочие.
Когда вы будете тестировать мою демо-версию, вы заметите, что в нём коды, привязанные к горячим клавишам, активируются, когда вы их нажимаете. Если вы хотите увидеть коды для особых комбинаций клавиш, попробуйте нажать CTRL или SHIFT одновременно с другой клавишей. Вам также нужно иметь возможность обнаруживать ALT, но я заметил, что эта опция не работает ни на моём компьютере с Windows 7, ни на моём макбуке.
Итоги
Теперь вы можете написать своё собственное приложение, использующее захват клавиш и char-события. Вам также может пригодится другая статья на похожую тему, которая называется AcceleratorTable. Этот класс позволяет разработчикам захватывать комбинации клавиш, которые пользователь нажимает в то время, как использует программу. Так что прочтите её, когда будет возможность.
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»