python gui事件无序 [英] python gui events out of order

查看:128
本文介绍了python gui事件无序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自tkinter import的$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ b self.container = Frame(root)
self.container.grid()
self.inputText = Text(self.container,width = 50,height = 8)
self.outputText =文本(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 =
self.outputText.delete(0.0,END)
self.outputText.insert(INSERT,input)
self.outputText.config(state = DISABLED)

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


root = Tk() #toplevel object
app = Gui(root)#call定义为gui的类
root.mainloop()#enter事件循环

工作在tkinter的gui上,对于运行事件处理程序的顺序,我有些困惑。如果你运行上面的代码,你会希望看到...



1)编辑文本窗口小部件触发事件处理程序,但似乎将其启动而不注册实际更改,
2)即使文本窗口小部件被清除(即,继续按BackSpace),它仍然似乎有一个字符长度的字符串
3)当NEXT事件时,输出窗口小部件仅接收其更新触发器被触发,尽管数据来自上一个事件。



这只是绑定在tkinter中的工作吗?或者我在这里缺少一些东西?



我想要的行为更新输入窗口小部件是:
1)显示更改
2)输入事件处理程序
3)更新输出窗口小部件
4)显示消息框。

解决方案

这是绑定如何工作(这是一件好事),但你的问题很容易解决。



绑定按照小部件bindtags指定的顺序触发。除非另有说明,否则绑定按以下顺序进行:


  1. 如果在窗口小部件上直接绑定,将在任何其他绑定。

  2. 如果在小部件的类上有绑定,则在下一个

  3. 中触发,如果在顶部小部件上包含绑定

  4. 如果在all上有一个约束,它将被触发。

(可以通过其中一个处理程序在任何位置停止该序列,但是在此特定讨论的旁边)



在默认情况下,您在< Key> 之前的绑定发生在类绑定之前,它是类绑定,文本实际插入到窗口小部件中。这就是为什么你的绑定总是似乎是一个字符。



通常这个顺序是正确的,因为更具体的绑定有机会覆盖默认行为。如果不是这样,你总是会得到默认的行为,即使你不想要它。一个地方,这并不总是你想要的是当你想增加默认绑定而不是替换它们。



您可以交换bindtags的顺序,以便首先绑定类绑定。或者,添加一个额外的bindtag到您的文本窗口小部件,并在类绑定后的序列中添加,并绑定到该绑定。通常添加一个bindtag是更好的解决方案,但并不总是。



要更改bindtags,您可以执行以下操作:

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

要绑定到post-insert,请使用bind_class方法:

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

可能看起来很奇怪,但是bindtags是其中最强大的绑定机制之一。它们可以完全和全面地控制绑定的顺序,这与任何其他工具包相比要困难得多。



顺便说一下,不要忘记,如果你得到所有字符到文本小部件的末尾总是会有一个额外的换行符。或者到达 end-1c ,或从文本中剪掉一个换行符。


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

Working on a gui in tkinter I'm a little confused as to the sequence the event handlers are run. If you run the above code you'll hopefully see...

1) Editing the text widget triggers the event handler but it seems to fire it off without registering the actual change, 2) Even when the text widget is cleared (ie, keep pressing BackSpace) it still seems to have a one character length string, 3) The output widget only receives its update when the NEXT event trigger is fired despite the fact the data came on the previous event.

Is this just how bindings work in tkinter or am i missing something here?

The behaviour i would like when updating the input widget is: 1) Show the change, 2) Enter event handler, 3) Update output widget, 4) Show message box.

解决方案

This is how bindings work (and that's a good thing), but your problem is easily solved.

Bindings are fired in the order specified by a widgets bindtags. Unless you specify otherwise, the bindings happen in the following order:

  1. if there is a binding directly on the widget it will be fired before any other bindings.
  2. if there is a binding on the widget's class, it is fired next
  3. if there is a binding on the toplevel widget that contains the widget, it is fired next
  4. if there is a binding on "all" it will fire next.

(the sequence can be stopped at any point by one of the handlers, but that's beside the point for this specific discussion)

In the default case, your binding on <Key> happens before the class binding, and it is the class binding where the text is actually inserted into the widget. That is why your binding always seems to be one character behind.

Normally this order of things is exactly right, since more specific bindings get a chance to override the default behavior. If it wasn't this way you'd always get the default behavior even if you didn't want it. One place where this is not always what you want is when you want to augment the default bindings rather than replace them.

You can swap the order of the bindtags so that the class binding happens first. Or, add an additional bindtag to your text widget and add that in the sequence after the class binding, and bind to that. Usually adding a bindtag is the better solution, but not always.

To change the bindtags you can do something like this:

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

To bind to "post-insert", do it with the bind_class method:

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

It may seem odd, but bindtags are one of the most powerful binding mechanisms out there. They give you complete and total control over the order of bindings, which is much more difficult with any other toolkit.

By the way, don't forget that if you get all the characters to the end of the text widget there will always be an extra newline at the end. Either get to end-1c, or trim off one newline from the text.

这篇关于python gui事件无序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆