autocomplete - Python Tkinter: different behavior when opening the same window from another window -
i used tkinter create window custom auto-complete entry.
when running directly window auto-complete entry (with "direct" command-line argument), entry works fine , when typing underscore entry suggests 4 hard-coded string.
when running window after double-click event window (with "indirect" command-line argument), auto-complete entry doesn't work. update: more precisely, autocomplete shows options on first window (instead of window autocomplete entry).
what causing inconsistency? how can make work in both cases?
see mwe attached:
from tkinter import * 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) 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 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) 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()
the problem creating more 1 root window , running more 1 event loop (though, 1 running @ time). tkinter designed run 1 instance of tk, mainloop() called once. if need additional windows should create instances of toplevel.
another part of problem don't give listbox explicit parent, appear in root window. need give listbox explicit parent. specifically, should same parent entry widget.
assuming first element of *args parent (which bad assumption, seems hold in specific case), quick fix this:
class autocompleteentry(entry): def __init__(self, contacts, maincomposemailwindow, *args, **kwargs): self.parent = args[0] ... def changed(...): ... self.lb = listbox(self.parent) a better (read: more clear) fix explicitly declare parent keyword argument __init__, don't rely on specific ordering of arguments.
Comments
Post a Comment