Tkinter中的小部件如何更新?

问题描述:

好的,所以我只是想弄清楚为什么我的代码不能像我想的那样工作。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" 

使用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保持响应,同时仍然在循环中运行您的代码。只是,不是使用显式循环,而是将工作添加到已经运行的事件循环中。