Tkinter 中的小部件如何更新? [英] How do widgets update in Tkinter?

查看:38
本文介绍了Tkinter 中的小部件如何更新?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,所以我只是想澄清一下为什么我的代码没有像我想象的那样工作.

Okay, so I'm just trying to get some clarification on why my code is not working like I thought it would.

我正在构建一个 GUI,我想在带有文本变量的 Label 上显示文本.我已经做了一个在调用函数时更新标签的函数,但这当然不是我的问题.

I am building a GUI, and I want to display text on a Label with a text variable. I have already made a function that updates the Label when the function is called, but of course that is not my problem.

我的问题源于我试图实现一次打印一个字母"类型的标签.虽然它以我想要的方式打印到终端,但标签小部件仅在整个函数完成后更新(视觉上它与仅打印整个字符串而不是一次打印一个字母相同).

My problem stems from me trying to implement a "print one letter at a time" type of label. While it prints to the terminal in the way I want it to, the label widget only updates after the whole function has finished (visually its the same as just printing the whole string instead of printing a letter at a time).

那么我错过了什么,我不明白什么?你们能帮帮我吗?让我贴一些代码,让你们看看我的错误在哪里.

So what am I missing, what do I not understand? Can you guys help me? Let me post some code so you guys can see where my error is.

我分别尝试了这两种方法,它们都给我带来了相同的结果,这不是我想要的.

I tried both of these independently and they both game me the same result, which was not what I desired.

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

如果我需要发布更多代码,我并不肯定,以便你们可以更好地理解,但如果是这样,我会这样做.

I'm not positive if I need to post more code, so you guys can understand better, but if thats the case, I will do that.

在这个函数中用到了这两个函数

Those 2 functions are used in this function

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

在这个函数中依次使用了哪些

Which in turn is used in this function

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 空闲时完成的).

The UI will update every time the event loop is entered. This is because painting is done via events (also known as "idle tasks" because they are done when the UI is otherwise idle).

您的问题是:当您编写一个循环并执行 time.sleep 时,该循环运行时不会进入事件循环,因此不会发生重绘.

Your problem is this: when you write a loop and do time.sleep, the event loop will not be entered while that loop is running, so no redrawing will occur.

您至少可以通过几种不同的方式来解决您的问题.一方面,您可以调用 update_idletasks 来刷新屏幕.这将解决重绘问题,但因为您正在睡眠,所以在循环期间 UI 将无响应(因为按钮和按键不是空闲任务").

You can solve your problem in at least a couple different ways. For one, you can just call update_idletasks which will refresh the screen. That will solve the repainting, but because you are sleeping the UI will be unresponsive during your loop (since button and key presses aren't "idle tasks").

另一种解决方案是编写一个函数,该函数接受一个字符串,从字符串中提取一个字符并将其添加到小部件中.然后它安排自己通过事件循环再次被调用.例如:

Another solution is to write a function that takes a string, pulls one character off the string and adds it to the widget. Then it arranges for itself to be called again via the event loop. For example:

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

This type of solution guarantees that your UI stays responsive while still running your code in a loop. Only, instead of using an explicit loop you add work to the already running event loop.

这篇关于Tkinter 中的小部件如何更新?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆