我使用Tkinter
创建了一个带有自定义自动完成条目的窗口。
当运行直接带有自动完成条目的窗口(带有“直接”命令行参数)时,该条目正常工作,当键入下划线时,该条目表示4个硬编码字符串
在从另一个窗口双击事件(使用“indirect”命令行参数)后运行此窗口时,自动完成条目不起作用。 更新:更准确地说,自动完成显示第一个窗口上的选项(而不是带有自动完成条目的窗口)。
造成这种不一致的原因是什么?如何在两种情况下都能使它工作?
见MWE附件:
from Tkinter import *
from ttk import Frame, Label, Style
class AutocompleteEntry(Entry):
def __init__(self, contacts, mainComposeMailWindow, *args, **kwargs):
Entry.__init__(self, *args, **kwargs)
self.contacts = contacts
self.mainComposeMailWindow = mainComposeMailWindow
self.var = self["textvariable"]
if self.var == '':
self.var = self["textvariable"] = StringVar()
self.var.trace('w', self.changed)
self.bind("<Right>", self.selection)
self.bind("<Up>", self.up)
self.bind("<Down>", self.down)
self.lb_up = False
def changed(self, name, index, mode):
words = self.comparison()
if words:
if not self.lb_up:
self.lb = Listbox()
self.lb.bind("<Double-Button-1>", self.selection)
self.lb.bind("<Right>", self.selection)
self.lb.place(x=self.winfo_x(), y=self.winfo_y()+self.winfo_height())
self.lb_up = True
self.lb.delete(0, END)
for w in words:
self.lb.insert(END,w)
else:
if self.lb_up:
self.lb.destroy()
self.lb_up = False
def selection(self, event):
if self.lb_up:
self.var.set(self.lb.get(ACTIVE))
self.lb.destroy()
self.lb_up = False
self.icursor(END)
def up(self, event):
if self.lb_up:
if self.lb.curselection() == ():
index = '0'
else:
index = self.lb.curselection()[0]
if index != '0':
self.lb.selection_clear(first=index)
index = str(int(index)-1)
self.lb.selection_set(first=index)
self.lb.activate(index)
def down(self, event):
if self.lb_up:
if self.lb.curselection() == ():
index = '0'
else:
index = self.lb.curselection()[0]
if index != END:
self.lb.selection_clear(first=index)
index = str(int(index)+1)
self.lb.selection_set(first=index)
self.lb.activate(index)
def comparison(self):
return [w for w in self.contacts if w.lower().startswith(self.var.get().lower())]
def get_content(self):
return self.var.get()
class AutoCompleteWindow:
def __init__(self):
autocomplete_choices = ['_This', '_order', '_is', '_important']
self.root = Tk()
self.root.minsize(300,300)
Label(self.root, text="Enter text:").grid(row=0)
self.autocomplete_entry = AutocompleteEntry(autocomplete_choices, self, self.root, bd = 2, width=50)
self.autocomplete_entry.grid(row=0, column=1)
self.root.mainloop()
def on_open_window(event):
AutoCompleteWindow()
def makeWindow ():
global select
win = Tk()
frame3 = Frame(win)
frame3.pack()
scroll = Scrollbar(frame3, orient=VERTICAL)
select = Listbox(frame3, yscrollcommand=scroll.set, height=17, width=100)
select.bind("<Double-Button-1>" , on_open_window)
scroll.config (command=select.yview)
scroll.pack(side=RIGHT, fill=Y)
select.pack(side=LEFT, fill=BOTH, expand=1)
return win
def setSelect () :
scrollbar_choices = ["first", "second", "third"]
select.delete(0,END)
for a_choice in scrollbar_choices:
select.insert(END, a_choice)
def intro_window():
win = makeWindow()
setSelect ()
win.mainloop()
if __name__ == "__main__":
if sys.argv[1] == "indirect":
intro_window()
elif sys.argv[1] == "direct":
AutoCompleteWindow()
答案 0 :(得分:1)
问题是您正在创建多个根窗口并运行多个事件循环(但是,一次只运行一个)。 Tkinter设计为仅使用Tk
的一个实例运行,mainloop()
只调用一次。如果您需要其他窗口,则应创建Toplevel
的实例。
问题的另一部分是您没有为列表框提供显式父级,因此它将始终显示在根窗口中。您需要为列表框指定一个显式父级。具体来说,它应该与条目小部件是同一个父级。
假设*args
的第一个元素是父元素(这是一个不好的假设,但似乎在这个非常具体的情况下保持不变),一个非常快速的解决方法就是这样做:
class AutocompleteEntry(Entry):
def __init__(self, contacts, mainComposeMailWindow, *args, **kwargs):
self.parent = args[0]
...
def changed(...):
...
self.lb = Listbox(self.parent)
更好(读取:更清楚)修复将显式声明parent
作为__init__
的关键字参数,因此您不依赖于参数的特定顺序。