#python #user-interface #tkinter #widget
#python #пользовательский интерфейс #tkinter #виджет
Вопрос:
Хорошо, итак, я просто пытаюсь получить некоторые разъяснения о том, почему мой код работает не так, как я ожидал.
Я создаю графический интерфейс, и я хочу отображать текст в 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"
Ответ №1:
Пользовательский интерфейс будет обновляться каждый раз, когда вводится цикл событий. Это потому, что рисование выполняется с помощью событий (также известных как «задачи ожидания», потому что они выполняются, когда пользовательский интерфейс в противном случае простаивает).
Ваша проблема заключается в следующем: когда вы пишете цикл и выполняете 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()
Этот тип решения гарантирует, что ваш пользовательский интерфейс остается отзывчивым, продолжая выполнять ваш код в цикле. Только вместо использования явного цикла вы добавляете работу к уже запущенному циклу событий.