Как связать собственные события в текстовом виджете Tkinter после того, как он будет связан текстовым виджетом? - PullRequest
13 голосов
/ 17 августа 2010

Я хочу связать собственные события после Text привязок класса виджета, чтобы изменить текст виджета при вызове моей функции привязки.Моя привязка, например self.text.bind("<Key>", self.callback), вызывается до изменения содержимого в текстовом виджете.

1 Ответ

25 голосов
/ 18 августа 2010

Что происходит в вашем случае, так это то, что ваша привязка для печати значения происходит до привязки класса, а именно привязка класса фактически принимает пользовательский ввод и помещает его в виджет. Есть несколько способов решить эту проблему. Вы можете привязаться к <KeyRelease> вместо <KeyPress> или использовать встроенные функции проверки ввода, чтобы ваш код вызывался при каждом нажатии клавиши. С этим решением вам будут предоставлены все необходимые данные: значение до изменения, значение после изменения, нажатая клавиша и т. Д.

Другой вариант - изменить порядок обработки событий. Поскольку в вашем вопросе конкретно спрашивалось, как изменить порядок, на это я и буду отвечать.

Несмотря на то, что привязка, по-видимому, связана с виджетом, когда вы делаете что-то вроде entry.bind(...), вы фактически назначаете привязку «тегу привязки» (или «тегу привязки»). По умолчанию каждый виджет имеет привязку, которая совпадает с именем виджета. Другие привязанные теги включают в себя класс виджета (например, «Entry»), путь к корневому окну (например, «.») И специальный тег «all». Виджетам присваивается набор привязок, которые обрабатываются по порядку при получении события. Порядок по умолчанию изменяется от наиболее специфичного к наименее конкретному: виджет, класс, верхний уровень, все.

Есть несколько способов манипулировать привязками, чтобы получить желаемый результат. Одним из вариантов является изменение порядка привязок. Перемещая связывающий тег, представляющий виджет, после того, как связывающий тег представляет класс, класс будет обрабатывать событие, прежде чем передать его конкретному виджету.

Другой вариант - добавить дополнительный привязочный тег после привязки класса, а затем поместить привязки в этот тег, а не в тег, представляющий виджет.

Зачем выбирать одно над другим? Изменяя порядок, вы будете влиять на все привязки в этом виджете. Если у вас много привязок, и некоторые из них зависят от порядка (например, это может запретить определенные нажатия клавиш), изменение порядка может привести к тому, что эти привязки перестанут работать.

Вводя новую привязку, вы можете выбрать, какие привязки будут выполняться до привязок классов, а какие - после.

В следующем коде я создаю три виджета ввода. Первый использует набор привязок по умолчанию (явно установлен в примере, хотя они идентичны стандартным). Второй меняет порядок, а третий вводит дополнительный биндаг. Запустите код, затем нажмите клавишу, пока фокус находится в каждом окне. Обратите внимание, что в первом виджете ввода привязка всегда кажется на один символ позади. Опять же, это связано с тем, что привязка виджета происходит до того, как привязка класса поместит символ в виджет.

Во втором и третьем примерах привязка происходит после привязки класса, поэтому функция видит изменения в виджетах.

import Tkinter

def OnKeyPress(event):
    value = event.widget.get()
    string="value of %s is '%s'" % (event.widget._name, value)
    status.configure(text=string)

root = Tkinter.Tk()

entry1 = Tkinter.Entry(root, name="entry1")
entry2 = Tkinter.Entry(root, name="entry2")
entry3 = Tkinter.Entry(root, name="entry3")

# Three different bindtags. The first is just the default but I'm
# including it for illustrative purposes. The second reverses the
# order of the first two tags. The third introduces a new tag after
# the class tag.
entry1.bindtags(('.entry1', 'Entry', '.', 'all'))
entry2.bindtags(('Entry', '.entry2', '.', 'all'))
entry3.bindtags(('.entry3','Entry','post-class-bindings', '.', 'all'))

btlabel1 = Tkinter.Label(text="bindtags: %s" % " ".join(entry1.bindtags()))
btlabel2 = Tkinter.Label(text="bindtags: %s" % " ".join(entry2.bindtags()))
btlabel3 = Tkinter.Label(text="bindtags: %s" % " ".join(entry3.bindtags()))
status = Tkinter.Label(anchor="w")

entry1.grid(row=0,column=0)
btlabel1.grid(row=0,column=1, padx=10, sticky="w")
entry2.grid(row=1,column=0)
btlabel2.grid(row=1,column=1, padx=10, sticky="w")
entry3.grid(row=2,column=0)
btlabel3.grid(row=2,column=1, padx=10)
status.grid(row=3, columnspan=2, sticky="w")

# normally you bind to the widget; in the third case we're binding
# to the new bindtag we've created
entry1.bind("<KeyPress>", OnKeyPress)
entry2.bind("<KeyPress>", OnKeyPress)
entry3.bind_class("post-class-bindings", "<KeyPress>", OnKeyPress)

root.mainloop()
...