October 19, 2010
Python Tkinter Hints

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, что будет приводить к удалению дополнительного символа.