Tkinter — не самая красивый, удобный и логичный GUI. Тем не менее, до сих пор этот GUI считается стандартным и входит во все основные дистрибутивы. Соответственно, программы, написанные с использованием Tkinter, будут наиболее переносимы и для их функционирования пользователю не придется устанавливать ничего дополнительно, кроме собственно Питона. Поэтому приходтся использовать эту библиотеку, когда хочешь написать что-нибудь кроссплатформенно-гуёвое. :)
Однако, при использовании Tkinter часто сталкиваешься с проблемами, отсутствующими в других библиотеках. А качество документации по Tk и Tkinter таково, что найти в инете что-нибудь сложнее тривиальных примеров почти нереально. И полного описания библиотеки нет и подавно. Например, я долго пытался понять как работает механизм обработки событий. Почему после того, как отработал мой собственный обработчик, срабатывал дефолтовый? Или, скажем, в текстовом редакторе выделить весь текст или реализовать удаление по словам (на привычные Ctrl-A и Ctrl-Backspace виджет Text никак не реагирует).
Найденные решения подобных проблем буду записывать сюда, в Тумблер. Во-первых, чтоб не потерялись, а во-вторых, мало ли — может, еще кому пригодится…
Как прервать дальнейшую обработку события?
Самым простым способом прервать цепочку обработки события является возврат строки “break” из обработчика. Например:
def ignore(event):
return "break"
text.bind("<Return>", ignore)
Пример блокирует клавишу Enter. Если убрать из кода возврат значения “break”, то в текстовом редакторе по-прежнему будут появляться новые строки при нажатии Enter.
Описано здесь: http://www.pythonware.com/library/tkinter/introduction/events-and-bindings.htm
Как в виджете Text выделить весь текст?
def select_all(self, event):
self.tag_add(SEL, '1.0', END+'-1c')
self.mark_set(INSERT, '1.0')
self.see(INSERT)
return 'break'
Далее, эту функцию надо “повесить” например на Ctrl-A:
editor.bind("<Control-Key-a>", select_all)
Эту функцию я обнаружил в книге Марка Лутца “Программирование на Python”.
Как реализовать пословное удаление текста?
Можно например так:
def on_ctrl_bs(self, event):
self.delete('%s -1 c wordstart' % INSERT, INSERT)
return 'break'
def on_ctrl_del(self, event):
self.delete(INSERT, '%s wordend' % INSERT)
return 'break'
Вешаем эти функции на соответствующие клавиши:
self.bind('<Control-Key-BackSpace>', on_ctrl_bs)
self.bind('<Control-Key-Delete>', on_ctrl_del)
Кстати, в последних примерах прерывание цепочки обработки события путем возврата строки “break” крайне важно, потому что в противном случае после удаления слова будет срабатывать штатный обработчик клавиш Backspace или Del, что будет приводить к удалению дополнительного символа.