события Python GUI вышли из строя - PullRequest
1 голос
/ 16 марта 2010
from Tkinter import *
from tkMessageBox import *

class Gui:
 def __init__(self, root):
  self.container = Frame(root)
  self.container.grid()
  self.inputText = Text(self.container, width=50, height=8)
  self.outputText = Text(self.container, width=50, height=8, bg='#E0E0E0', state=DISABLED)
  self.inputText.grid(row=0, column=0)
  self.outputText.grid(row=0, column=1)

  self.inputText.bind("<Key>", self.translate)

 def translate(self, event):
  input  = self.inputText.get(0.0, END)
  output = self.outputText.get(0.0, END)

  self.outputText.config(state=NORMAL)
  self.outputText.delete(0.0, END)
  self.outputText.insert(INSERT, input)
  self.outputText.config(state=DISABLED)

  showinfo(message="Input: %s characters\nOutput: %s characters" % (len(input), len(input)))


root = Tk()   #toplevel object
app = Gui(root)  #call to the class where gui is defined
root.mainloop()  #enter event loop

Работая над графическим интерфейсом в tkinter, я немного запутался в отношении последовательности запуска обработчиков событий. Если вы запустите приведенный выше код, то, надеюсь, увидите ...

1) Редактирование текстового виджета запускает обработчик событий, но, похоже, он отключается без регистрации фактического изменения, 2) Даже когда текстовый виджет очищен (т. Е. Продолжайте нажимать BackSpace), он все еще имеет строку длиной в один символ, 3) Выходной виджет получает свое обновление только тогда, когда срабатывает СЛЕДУЮЩИЙ триггер, несмотря на то, что данные поступили в предыдущем событии.

Так работают привязки в tkinter или я что-то здесь упускаю?

Поведение, которое я хотел бы при обновлении виджета ввода: 1) Показать изменения, 2) Введите обработчик события, 3) Обновить выводной виджет, 4) Показать окно сообщения.

1 Ответ

4 голосов
/ 18 марта 2010

Так работают привязки (и это хорошо), но ваша проблема легко решается.

Привязки запускаются в порядке, указанном тегами привязки виджетов (также называемыми тегами привязки или тегами привязки). Если не указано иное, привязки происходят в следующем порядке:

  1. если на виджете есть привязка, она будет запущена перед любыми другими привязками.
  2. если есть привязка к классу виджета, он запускается следующим
  3. если на виджете верхнего уровня, который содержит виджет, имеется привязка, то он запускается следующим (примечание: корневое окно в этом контексте считается окном верхнего уровня)
  4. если есть привязка к «all», она сработает следующим.

Последовательность может быть остановлена ​​в любой момент одним из обработчиков событий, но это не относится к этому конкретному обсуждению.

В случае по умолчанию ваша привязка к <Key> происходит до привязки класса, и это привязка класса, где текст фактически вставляется в виджет. Вот почему ваша привязка всегда кажется на один символ позади.

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

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

Чтобы изменить привязки, вы можете сделать что-то вроде этого:

self.inputText.bindtags(((str(self.inputText)), "Text", "post-insert", ".", "all"))

Чтобы привязать к "post-insert", сделайте это с помощью метода bind_class:

self.inputText.bind_class("post-insert", "<Key>", self.translate)

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

Кстати, не забывайте, что если вы добавите все символы в конец текстового виджета, то в конце всегда будет дополнительная новая строка. Либо доберитесь до end-1c, либо обрежьте одну новую строку из текста.

...