2011-12-30 70 views
35

我見過的每一個tkinter教程都聲稱,必須調用tkinter.mainloop來繪製要繪製的窗口和要處理的事件,並且即使在hello world程序中它們也總是調用此函數。但是,當我在交互式shell中嘗試這些時,無需調用mainloop即可正確繪製窗口。在tkinter中嵌入matplotlib圖形的This example會生成一個相對複雜的應用程序,並帶有用於在tkinter窗口中平移,縮放和調整圖形大小的按鈕,並且,如果您移除對mainloop的調用並在交互式shell中運行代碼,當然,如果我在交互式shell外運行腳本(在主循環被移除的情況下),程序結束得太快以至於看不到會發生什麼,但是如果我添加一個調用input來保持程序打開一切正常(我正在運行python 3.2.2在linux上)。什麼時候需要在Tkinter應用程序中調用mainloop?

那麼,mainloop究竟做了什麼,以及何時需要調用它?

編輯: 爲了澄清,如果我打通GNOME終端輸入而不必調用主循環

$python3 
>>> import tkinter 
>>> root = tkinter.Tk() 

一個窗口立即出現,和更復雜的Tkinter功能似乎工作以及(例如,向窗口添加按鈕)。在IDLE中,調用mainloop是必要的。我的理解是,除非主循環被調用,否則不應該繪製任何事件,也不應處理任何事件。

回答

38

你主要問題的答案是,當你準備好你的應用程序運行時,你必須調用一次mainloop一次。

mainloop比一個無限循環,看起來大致是這樣的(這些都不是這些方法的實際名稱,名稱僅僅用來說明這一點)沒有更多:

while True: 
    event=wait_for_event() 
    event.process() 
    if main_window_has_been_destroyed(): 
     break 

在這種情況下,「事件」意味着用戶交互(鼠標點擊,按鍵等)以及來自工具包或OS /窗口管理器的繪製或重新繪製小部件的請求。如果該循環未運行,則不會處理事件。如果事件沒有得到處理,屏幕上就不會顯示任何內容,並且程序可能會退出,除非您有自己的無限循環運行。

那麼,爲什麼你不需要交互調用呢?這只是一種方便,否則一旦您呼叫mainloop,將不可能輸入任何命令,因爲mainloop直到主窗口被銷燬。

7

將程序與交互式GUI進行比較,以計算第百個斐波納契數。後面的所有程序都必須按順序經過一系列步驟,從上到下。這套步驟及其排序可以事先知道,無論您運行程序多少次,它都會保持不變。

但是GUI程序是不同的:在任何特定的時刻,它必須能夠處理各種不同類型的事件和交互。這個要求通常使用稱爲事件循環的編程構造來實現。事件循環是程序的中央控制結構。它等待事件發生,然後分派適當的處理程序。

你沒有提到你正在使用哪個交互式shell,但我猜它是空閒的。 IDLE本身是一個Tkinter程序,它已經有一個事件循環。所以可能你在shell中鍵入的Tkinter代碼已經綁定到IDLE的事件循環。

+0

對不起,我應該提到:我只是用標準Python殼(未IDLE)在GNOME終端(其顯然寫入C)。就我所知,除了我自己的代碼之外,沒有什麼東西可以做任何影響tkinter的東西。 – James 2011-12-30 21:38:45

+1

我剛剛在IDLE中嘗試過同樣的事情,而且我沒有得到相同的行爲 - 直到我調用mainloop時纔會出現窗口。 – James 2011-12-30 21:46:38

-3

我已經決定,我不會直接在我的腳本的任何地方直接粘貼一個調用mainloop,我只是將它添加爲atexit的一部分 - 也就是說,當Python解釋器決定是時候開始關閉的時候,將進入Tk的主循環。這樣就可以防止它完成關停序列,直到用戶實際上告訴Tk的退出(即,在Mac上的命令-Q,或通過單擊Windows中的紅色的X)。

from Tkinter import Tk 
root = Tk() 

import atexit 
atexit.register(root.mainloop) 

似乎有無需從系統命令行調用mainloop。 Python解釋器會在沒有它的情況下繼續運行,因爲它正在等待您的進一步輸入(直到您運行exit())。

+1

_「在我看來,調用mainloop所做的唯一的事情是阻止你的應用程序自動關閉」_:這是一個不正確的評估。它管理事件隊列,這遠遠不止是阻止應用程序退出。另外,你甚至沒有按照你自己的想法做:你實際上是在調用'mainloop()',而不是在退出時調用。 – 2016-03-07 15:20:31

+1

@BryanOakley - 哎呀,我已經修復了對''mainloop()'的意外調用 - 現在它只是註冊了,因爲它應該是。無論如何,我相信你是不正確的。在你的回答中,你說你不需要在交互式交互中調用mainloop這一事實「僅僅是一種方便」。呃,什麼?如果這是一件方便的事情,那麼無論是交互式解釋器還是「Tkinter」模塊都必須包含允許這樣做的特殊代碼。我不相信代碼存在。沒有說明它的文檔。你說的負擔就是證明主循環是神奇的。 – ArtOfWarfare 2016-03-07 15:29:39

+0

我從來沒有聽說過atexit,我很高興我找到了這個答案,因爲它允許我在單元測試期間調用一個'Tk()'應用程序,而無需手動關閉應用程序。 – 2017-02-21 10:07:03

-3

如下:

from tkinter import * 

tk = Tk() 
canvas = Canvas(tk, width=500, height=500) 
canvas.pack() 
canvas.create_line(0, 0, 500, 500) 

mainloop() 
相關問題