Вопрос-Ответ

tkinter: how to use after method

tkinter: как использовать метод after

Привет, я новичок в python и использую tkinter для своего графического интерфейса. У меня возникли проблемы с использованием frame.after метода.
Цель состоит в том, чтобы заставить случайную букву появляться каждые 5 секунд.

Вот мой код:

import random
import time
from tkinter import *


root = Tk()

w = Label(root, text="GAME")
w.pack()

frame = Frame(root, width=300, height=300)
frame.pack()

L1 = Label(root, text="User Name")
L1.pack(side=LEFT)
E1 = Entry(root, bd =5)
E1.pack(side=LEFT)


tiles_letter = ['a', 'b', 'c', 'd', 'e']


while len(tiles_letter) > 0:
rand = random.choice(tiles_letter)
tile_frame = Label(frame, text=rand)
tile_frame.pack()
frame.after(500)
tiles_letter.remove(rand) # remove that tile from list of tiles

root.mainloop()

Кто-нибудь, пожалуйста, может мне помочь?

Проблема определенно в frame.after(500),
Я не уверен, правильно ли его использовать frame и я не знаю, какой аргумент следует за 500 параметром.

Спасибо

Переведено автоматически
Ответ 1

Вам нужно указать функцию, которая будет вызываться после временной задержки, в качестве второго аргумента для after:


after(delay_ms, callback=None, *args)


Регистрирует аварийный обратный вызов, который вызывается по истечении заданного времени.


Итак, что вы действительно хотите сделать, так это:

tiles_letter = ['a', 'b', 'c', 'd', 'e']

def add_letter():
rand = random.choice(tiles_letter)
tile_frame = Label(frame, text=rand)
tile_frame.pack()
root.after(500, add_letter)
tiles_letter.remove(rand) # remove that tile from list of tiles


root.after(0, add_letter) # add_letter will run as soon as the mainloop starts.
root.mainloop()

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


Обратный вызов вызывается только один раз для каждого вызова этого метода. Чтобы продолжать вызывать обратный вызов, вам необходимо повторно зарегистрировать обратный вызов внутри самого метода.


Обратите внимание, что ваш пример выдаст исключение, как только вы исчерпаете все записи в tiles_letter, поэтому вам нужно изменить свою логику, чтобы обрабатывать этот случай любым удобным для вас способом. Проще всего было бы добавить проверку в начале add_letter, чтобы убедиться, что список не пуст, и просто return если это так:

def add_letter():
if not tiles_letter:
return
rand = random.choice(tiles_letter)
tile_frame = Label(frame, text=rand)
tile_frame.pack()
root.after(500, add_letter)
tiles_letter.remove(rand) # remove that tile from list of tiles

Live-демо: repl.it

Ответ 2

Я полагаю, 500 мс выполняются в фоновом режиме, в то время как остальная часть кода продолжает выполняться и очищает список.

Затем через 500 мс ничего не происходит, поскольку в after-callup не реализован вызов функции (такой же, как frame.after(500, function=None))

Ответ 3

after используется для задержки выполнения программы или для выполнения команды в фоновом режиме когда-нибудь в будущем. Но вы можете создать цикл внутри mainloop, вызвав сам цикл.

import tkinter as tk #import tkinter
import datetime #import datetime for our clock

def tick(): #function to update the clock
showed_time = clock['text'] #current showed time
current_time = datetime.datetime.now().strftime("%H:%M:%S") #real time
if showed_time != current_time: #if the showed time is not the real time
clock.configure(text=current_time) #update the label with the current time
clock.after(1000, tick) #call yourself in 1000ms (1sec.) again to update the clock
return None

root=tk.Tk()

clock = tk.Label(root)
clock.pack()
tick()

root.mainloop()

В приведенном выше скрипте мы создали цифровые часы и связались с методом after. Метод after - это не что иное, как интервал, и в конце этого интервала мы хотим, чтобы что-то произошло.

Чтобы узнать больше об этом базовом методе виджета [нажмите]


after(delay_ms, обратный вызов = Нет, аргументы)


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


import tkinter as tk 
import datetime

def tick():
showed_time = clock['text']
current_time = datetime.datetime.now().strftime("%H:%M:%S")
if showed_time != current_time:
clock.configure(text=current_time)
global alarm #make sure the alarm is reachable
alarm = clock.after(1000, tick)#assign the alarm to a variable
return None
def stop():
stop.after_cancel(alarm) #cancel alarm


root=tk.Tk()

clock = tk.Label(root)
clock.pack()
stop = tk.Button(root, text='Stop it!', command=stop)
stop.pack()
tick()


root.mainloop()

Здесь у нас есть тот же код, но с возможностью отменить наш цикл с помощью after_cancel метода tkinter. Вам не нужно глобализировать сигнал тревоги внутри класса. self.alarm = self.clock.after(...) работает нормально.


after_cancel(идентификатор)


Отменяет аварийный обратный вызов.


ID


Идентификатор сигнала тревоги.


python tkinter