2015-07-11 114 views
0

我使用Tkinter創建一個帶自定義自動完成條目的窗口。Python Tkinter:從另一個窗口打開同一窗口時的不同行爲

當運行直接與自動完成條目(與「直接」命令行參數)的窗口,進入正常工作和打字強調當上述項目建議的4硬編碼字符串。

當從另一個窗口(使用「間接」命令行參數)雙擊事件後運行此窗口時,自動完成條目不起作用。 更新:更確切地說,自動完成在第一個窗口(而不是自動完成條目的窗口)上顯示選項。

是什麼導致了這種不一致?我怎樣才能使它在兩種情況下工作?

見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() 

回答

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__的關鍵字參數,因此您不需要依賴於參數的特定順序。

+0

我試圖將內部TK()更改爲Toplevel()並刪除內部主循環(),但第二種情況仍然不起作用。你能提供MWE嗎? – zvisofer

+0

@zvisofer:我已經更新了我的答案。 –

+0

這是正確的。將父窗口傳遞給列表框會修復它。 TNX – zvisofer

相關問題