Как обновляются виджеты в Tkinter? - PullRequest
3 голосов
/ 25 апреля 2011

Хорошо, поэтому я просто пытаюсь получить некоторые пояснения о том, почему мой код не работает так, как я думал.

Я создаю графический интерфейс и хочу отобразить текст на 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"

1 Ответ

5 голосов
/ 25 апреля 2011

Пользовательский интерфейс будет обновляться каждый раз при входе в цикл событий. Это происходит потому, что рисование выполняется с помощью событий (также называемых «незанятыми задачами», потому что они выполняются, когда пользовательский интерфейс в противном случае простаивает).

Ваша проблема заключается в следующем: когда вы пишете цикл и делаете time.sleep, цикл событий не будет введен во время выполнения цикла, поэтому перерисовка не произойдет.

Вы можете решить свою проблему, по крайней мере, несколькими различными способами. Во-первых, вы можете просто позвонить update_idletasks, что обновит экран. Это решит проблему перекраски, но поскольку вы спите, пользовательский интерфейс будет не отвечать на запросы во время цикла (поскольку нажатия кнопок и клавиш не являются «простоями»).

Другое решение - написать функцию, которая берет строку, вытаскивает один символ из строки и добавляет его в виджет. Затем он организует повторный вызов через цикл обработки событий. Например:

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

Этот тип решения гарантирует, что ваш пользовательский интерфейс остается отзывчивым, пока код выполняется в цикле. Только вместо использования явного цикла вы добавляете работу в уже запущенный цикл обработки событий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...