2013-07-05 101 views
2

下面的代碼顯示出一個問題,我不明白:在python中導致tkinter級聯菜單失敗的原因是什麼?

from Tkinter import * 
root = Tk() 

cheese_var = IntVar() 
parrot_var = IntVar(value=1) 
check_menu = Menu(tearoff=0) 
check_menu.add_checkbutton(label="Cheese", variable=cheese_var) 
check_menu.add_checkbutton(label="Parrot", variable=parrot_var) 
count = 0 

class Top(): 
    def __init__(self): 
     global count 
     count += 1 
     self.tl = Toplevel(root) 
     Label(self.tl, text="Window " + str(count)).pack() 
     self.mb = Menubutton(self.tl, text="Push Me", bg='pink') 
     self.menu = Menu(self.mb, tearoff=0) 
     self.menu.add_cascade(label="Choices", menu=check_menu) 
     self.menu.add_command(label="New Window", command=new_top) 
     self.mb.config(menu=self.menu) 
     self.mb.pack() 

def new_top(): 
    Top() 

Top() 
root.mainloop() 

通過菜單按鈕,在創建頂層窗口後顯示的菜單最初的行爲與預期。點擊New Window命令可以創建一個新的窗口,其行爲與預期相同。事實上,只要你不斷創建新的頂級窗口,一切都會繼續按預期工作。但是,一旦刪除(關閉)了其中任何一個窗口,則在隨後創建的新窗口中,新菜單上的Choices級聯不起作用。 (在關閉一個窗口之前創建的窗口仍然沒問題。)

我最初遇到這種症狀的情況要複雜得多,但我能夠簡化它,直到上面的例子出現問題。我發現我可以通過讓Top的每個實例都創建自己的check_menu作爲屬性來避免這個問題;但我不明白爲什麼這是必要的。如果沒有在多個窗口中使用級聯菜單的複製,請指出是否有人避免該問題。

回答

0

不幸的是,我不認爲有可能做你想做的事。我會盡力盡力解釋。

當你第一次運行腳本時,check_menu被創建並且對第一個窗口工作正常。當你創建更多的窗口時,check_menu只是在它們之間共享。但是,當你關閉其中的一個時,check_menu(以及它下面的所有東西)都被銷燬。所以,當你在此之後創建一個新窗口時,check_menu不再存在,並且不顯示。

但是,腳本不會拋出錯誤,因爲出於某種原因,Tkinter允許您將菜單分配給非菜單的事物。不管你信不信,下面的代碼都不是:

self.menu.add_cascade(label="Choices", menu=None) 
self.menu.add_cascade(label="Choices", menu=1) 
self.menu.add_cascade(label="Choices", menu="") 

會破壞腳本。每一行只是做了一個空的級聯「選擇」。

這基本上是發生了什麼事情。關閉一個窗口後,check_menu及其下的所有內容都將被銷燬。然而,Tkinter不會拋出錯誤,而是將菜單分配給不再是菜單的菜單(就其分配菜單而言,我相信它使用的是舊的已被銷燬的check_menu實例)。

要解決此問題,請在每次調用Top時重新創建check_menu及其下的所有內容。換句話說,將check_menu的代碼(及其選項)放在Top的__init__方法中。這樣,每次調用Top時,check_menu都會存在。

希望這有助於(並且我已經充分解釋了:) :)

+0

感謝您的迴應。我明白它不起作用;但我仍然不清楚爲什麼,我懷疑還有一點需要更多的完整解釋。我所期望的是,只要有一個對象的引用,它就會繼續存在。如果菜單按照你的說法被銷燬,它是如何繼續在破壞之前創建的窗口中運行的?如果我在關閉其中一個窗口後檢查check_menu的值,我會在<0x0000000004237F48>處獲得。 –

相關問題