
Есть мой ужасный код и есть цикл, результат которого должен постоянно обновляться в tkinter.Label
. Опыта в программировании мало, не могу никак до конца разобраться в классах и областях видимости.
В общем, суть в том, что лейбл, созданный внутри create_widgets()
, должен обновляться из результата цикла for _ in range(30)
. Функции внутри start_reading()
используются только там, поэтому мне казалось приемлемой идеей поместить функции внутрь другой функции (метода?). Нашел вот этот вопрос, но он мне не особо помог, к сожалению.
Теперь я конкретно запутался и прошу помощи. Как исправить код, чтобы решить проблему?
import tkinter as tk class Application(tk.Frame): def __init__(self, master=None): super().__init__(master) self.create_widgets() def create_widgets(self): ... # Здесь должен быть лейбл def get_resolution(self, handle, client=True): ... def configuration(self): ... def start_reading(self, arg): a = ... b = ... def get_area(self, resolution, area, foo=None): ... spam = get_area(...) eggs = get_area(...) def get_hash(self, img): ... for _ in range(30): # Лейбл должен изменятся каждый раз ... # при изменении result, т.е. 30 раз result = ... del a # После цикла должны быть удалены a и b. del b # Только там не переменные на самом деле, а # .DeleteDC, .ReleaseDC и подобная ересь if __name__ == '__main__': root = tk.Tk() app = Application(master=root) app.configuration() app.mainloop()
2Answers

Еще может заинтересовать:

import tkinter as tk class Application(tk.Frame): def __init__(self, master=None): super().__init__() self.create_widgets() def create_widgets(self): self.label = tk.Label(text='None') # лейбл self.label.pack() def start_reading(self, arg): if arg: self.label['text'] = arg # Лейбл должен изменятся каждый раз self.label.update() # обновить Лейбл root.after(500, self.start_reading, arg - 1) # repeat the call if __name__ == '__main__': root = tk.Tk() app = Application(master=root) root.after(1000, app.start_reading, 30) # запустить start_reading после 1000ms app.mainloop()

Идиоматичный способ организовать цикл обновления GUI элемента—это root.after()
:
#!/usr/bin/env python3 import tkinter def loop(n): label['text'] = str(n) root.after(500, loop, n+1) # call loop(n+1) in 0.5 seconds root = tkinter.Tk() label = tkinter.Label(font=(None, 100)) label.pack() root.after_idle(loop, 0) # start loop root.after(5000, root.destroy) # quit in 5 seconds # center window root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id())) root.mainloop()
Весь цикл в функции loop()
. Ещё пример: countdown()
функция.
Обратите внимание, что НЕ следует явный цикл с time.sleep()
использовать, иначе GUI подвешивается/замораживается:
#XXX DO NOT DO IT for n in range(10): label['text'] = str(n) time.sleep(0.5)
Обработчики событий (таких как нажатие клавиш, движение мыши, обратные вызовы (callback
), запланированные программно с помощью root.after()
) выполняются в одном GUI потоке, поэтому если поток спит на time.sleep()
строчке или крутится в долгом/вечном цикле, то никакие другие события не обрабатываются—эффект «подвисания» GUI.
Это код можно попытаться спасти, используя label.update()
и root.update_idletasks()
, но вариант с root.after()
является более гибким и надёжным.
Связанный вопрос: Мультизадачность на Python: выполнить две долгие функции одновременно, не блокируя GUI.