2011-04-25 93 views
3

好的,所以我只是想弄清楚爲什麼我的代碼不能像我想的那樣工作。Tkinter中的小部件如何更新?

我正在構建一個GUI,我想用文本變量在Label上顯示文本。當函數被調用時,我已經創建了一個更新Label的函數,但這當然不是我的問題。

我的問題源於我試圖實現「一次打印一個字母」類型的標籤。當它以我想要的方式打印到終端時,標籤小部件僅在整個功能完成後才更新(在視覺上它與僅打印整個字符串相同,而不是一次打印一個字母)。

那麼我錯過了什麼,我不明白什麼?你們能幫我嗎?讓我發佈一些代碼,以便你們可以看到我的錯誤在哪裏。

我嘗試了這兩個獨立的,他們都玩我相同的結果,這不是我想要的。

def feeder(phrase): 
    """Takes a string and displays the content like video game dialog.""" 
    message = "" 
    for letter in phrase:  
     time.sleep(.15) 
     message += letter 
     information.set(message) 
     #print message 

def feeder2(phrase): 
    """Same as feeder, but trying out recursion""" 
    current.index += 1 
    if current.index <= len(phrase): 
     information.set(phrase[:current.index]) 
     time.sleep(.1) 
     feeder2(current.status()) 

我還不能肯定,如果我需要發佈更多的代碼,所以你們可以更好地理解,但如果多數民衆贊成的情況下,我將這樣做。

這2個功能在此功能

def get_info(): 
    """This function sets the textvariable information.""" 
    #information.set(current) 
    feeder2(current.status()) 

該消息又在這個函數

def validate(): 
    """ This function checks our guess and keeps track of our statistics for us. This is the function run when we press the enter button. """ 
    current.turn += 1 
    if entry.get() == current.name: 
     if entry.get() == "clearing": 
       print "Not quite, but lets try again." 
       current.guesses -= 1 
     if entry.get() != "clearing": 
      print "Great Guess!" 
      current.points += 1 

    else: 
     print "Not quite, but lets try again." 
     current.guesses -= 1 
    print current 
    get_info() 
    entry.delete(0, END) 
    current.name = "clearing" 

回答

5

使用UI將更新每次進入事件循環時使用。這是因爲繪畫是通過事件完成的(也稱爲「空閒任務」,因爲它們在UI空閒時完成)。

你的問題是這樣的:當你編寫一個循環並且執行time.sleep時,在循環運行時不會進入事件循環,所以不會發生重繪。

您可以至少以幾種不同的方式解決您的問題。首先,你可以撥打update_idletasks這將刷新屏幕。這將解決重新繪製問題,但是因爲你正在睡覺,所以在你的循環中UI將不響應(因爲按鈕和按鍵不是「空閒任務」)。

另一種解決方案是編寫一個函數,它接受一個字符串,從字符串中拉出一個字符並將其添加到小部件。然後它通過事件循環安排自己再次被調用。例如:

import Tkinter as tk 

class App(tk.Tk): 
    def __init__(self,*args, **kwargs): 
     tk.Tk.__init__(self, *args, **kwargs) 
     self.label = tk.Label(self, text="", width=20, anchor="w") 
     self.label.pack(side="top",fill="both",expand=True) 
     self.print_label_slowly("Hello, world!") 

    def print_label_slowly(self, message): 
     '''Print a label one character at a time using the event loop''' 
     t = self.label.cget("text") 
     t += message[0] 
     self.label.config(text=t) 
     if len(message) > 1: 
      self.after(500, self.print_label_slowly, message[1:]) 

app = App() 
app.mainloop() 

這種類型的解決方案保證您的UI保持響應,同時仍然在循環中運行您的代碼。只是,不是使用顯式循環,而是將工作添加到已經運行的事件循環中。