我有一个小模块,当Toplevel
小部件获得焦点时会弹出Entry
小部件。 Toplevel窗口是一个键盘,因此它需要按钮单击触发一个方法,该方法将该按钮单击插入Entry小部件。应该在两个条件下销毁Toplevel:1)用户按下实际键盘上的键,2)移动或调整Entry小部件的父级。
除了一个错误之外,一切正常:如果用户点击Toplevel,它就会变为活动状态,如果发生其中一个破坏事件,我会得到意想不到的结果(比如当条目再次获得焦点时弹回窗口)。
我的想法是,如果我可以让Entry在整个过程中保持专注,一切都会奏效,但我还没有办法让这种情况发生。
这是一个例子,它就像我可以在保留模块结构的同时一样被剥离。注意:Python 2.7
from Tkinter import *
class Top(Toplevel):
def __init__(self, attach):
Toplevel.__init__(self)
self.attach = attach
Button(self, text='Button A', command=self.callback).pack()
self.bind('<Key>', self.destroyPopup)
def callback(self):
self.attach.insert(END, 'A')
def destroyPopup(self, event):
self.destroy()
class EntryBox(Frame):
def __init__(self, parent, *args, **kwargs):
Frame.__init__(self, parent)
self.parent = parent
self.entry = Entry(self, *args, **kwargs)
self.entry.pack()
self.entry.bind('<FocusIn>', self.createPopup)
self.entry.bind('<Key>', self.destroyPopup)
self.parent.bind('<Configure>', self.destroyPopup)
def createPopup(self, event):
self.top = Top(self.entry)
def destroyPopup(self, event):
try:
self.top.destroy()
except AttributeError:
pass
root = Tk()
e1 = EntryBox(root).pack()
root.mainloop()
那么,是否有某种never_get_focus()
方法我没有发现我可以应用于Toplevel小部件,或者我是从错误的方式处理这个问题,还是什么?任何帮助表示赞赏。
编辑:我发现了一种似乎有效的创可贴型解决方案,但我觉得还有一种更好的办法来解决这个问题,我还没有找到。
这是我在Frame子类弹出方法中添加的内容:
def createPopup(self, event):
try: #When focus moves in to the entry widget,
self.top.destroy() #try to destroy the Toplevel
del self.top #and remove the reference to it
except AttributeError: #unless it doesn't exist,
self.top = Top(self.entry) #then, create it
def destroyPopup(self, event):
try:
self.top.destroy()
del self.top
except AttributeError:
pass
我正在添加赏金,因为我想看看是否有另一种更清洁的方法。我想要的步骤是:
答案 0 :(得分:2)
您可以使用状态机来处理您描述的行为。 State machines在图形用户界面中实现行为非常常见。这是一个简短的例子,让您了解它的外观。
首先设计fsm,这是一个简单的,几乎可以执行你想要的东西(为了简洁起见,跳过配置部分)。
对于实现,您可以选择现有的库,构建自己的框架,或者在时使用旧的嵌套。遵循我的快速和肮脏的实施。
调整订阅以创建状态并将事件重定向到fsm:
self.state = "idle"
self.entry.bind('<FocusIn>', lambda e:self.fsm("focus_entry"))
self.entry.bind('<FocusOut>', lambda e:self.fsm("focus_out_entry"))
self.entry.bind('<Key>', lambda e:self.fsm("key_entry"))
self.parent.bind('<Configure>', lambda e:self.fsm("configure_parent"))
选择要解决的状态/事件组合并执行适当的操作。您可能会发现您陷入某种状态并相应地调整您的FSM。
def fsm(self, event):
old_state = self.state #only for logging
if self.state == "idle":
if event == "focus_entry":
self.createPopup()
self.state = "virtualkeyboard"
elif self.state == "virtualkeyboard":
if event == "focus_entry":
self.destroyPopup()
self.state = "typing"
if event == "focus_out_entry":
self.destroyPopup()
self.state = "idle"
elif event == "key_entry":
self.destroyPopup()
self.state = "typing"
elif self.state == "typing":
if event == "focus_out_entry":
self.state = "idle"
print "{} --{}--> {}".format(old_state, event, self.state)
答案 1 :(得分:0)
这可能有助于您:Making a tkinter widget take focus
如果您决定改变焦点,那么您可以将其写入以实现这一目标。
我可能不完全理解你正在做的事情的范围,我相信它可能是奇怪的行为的原因是由于你对顶级的约束。
def destroyPopup(self, event):
self.destroy()
使用:
self.entry.bind('<FocusIn>', self.createPopup)
不确定这是否有帮助,但可能会考虑添加一些:
print "____ is triggered"
在每个方法中查看切换焦点时究竟发生了什么,可能有助于确定发生了什么。