Python Tkinter循环无法操作UI接口



我是tkinter的新手。当我试图创建一个循环(如for i in range(100)(时,GUI"崩溃"了,这意味着在循环结束之前我无法操作GUI(即使我没有在文本中插入任何内容(。在我检查了一些信息后,我尝试了线程。它确实有效。但是

from tkinter import *
import time
from threading import Thread
class Application(Frame):
def __init__(self):
self.root = Tk()
self.root.title('tkinter')
self.root.geometry('400x300+400+100')

self.createWidget()
self.root.mainloop()

def createWidget(self):
self.text = Text(self.root, width=40, height=15, relief=SOLID, borderwidth=1)
self.text.grid(row=0, column=0)
self.button = Button(self.root, text="click", relief=SOLID, borderwidth=1, command=self.button_click)
self.button.grid(row=1, column=0)
pass
def button_click(self):
t1 = Thread(target=self.loop)
t1.start()            

def loop(self):
for i in range(100):
self.text.insert(END, chars=str(i)+'n')
time.sleep(1)
self.root.update()
self.text.see(END)

if __name__=="__main__":
Application()

但不可能每次遇到循环都使用线程(太难了,在某些情况下,必须按顺序执行(。有什么有用/简单的方法来处理它吗?

如果您正在寻找一种以给定速度插入文本的方法,那么可以使用tkinterafter来实现。

该代码试图阐明after的用法。

按下Escape键可以中断该过程。这将立即cancel_after并完成文本插入。

import tkinter as tk
data = dir(tk) # or str.split('n')
root = tk.Tk()
text = tk.Text(root, undo = 1, wrap = tk.NONE)
text.pack()
def insert_text():
global delay
d = data.pop(0)
text.insert(tk.END, f"{d}n")
if len(data) > 0:
delay = root.after(500, insert_text)
# cancel timed input
def stop(event):

root.after_cancel(delay)
for d in data:
text.insert(tk.END, f"{d}n")
root.bind("<Escape>", stop)
# start output
delay = root.after(50, insert_text)
root.mainloop()

在tkinter循环实践中,我已经找到了一种更好的方法来解决由其他循环或多线程引起的接口不更新问题。只要用子线程打开窗口类MainWindows中的函数操作函数,无论子线程打开的函数中有多少个循环或多线程(线程池(,都不会影响GUI更新,并且可以实时滚动日志。

from tkinter import *
import time
import requests
from threading import Thread
from concurrent.futures import ThreadPoolExecutor
class MainWindows(Frame):
def __init__(self, master):
super().__init__(master=master)
self.master=master
self.createWidget()
self.pack()
pass
def createWidget(self):
self.text = Text(self, width=50, height=20, relief=SOLID, borderwidth=1, fg="gray")
self.text.pack()
self.button = Button(self, text="click", command=self.thread)
self.button.pack()
pass
def thread_show_info(self, i):
self.text.insert(END, chars=str(i)+'n')
self.text.see(END)
time.sleep(1)
def threadpool_show_info(self):
with ThreadPoolExecutor(10) as t:
for q in range(1, 1000):
t.submit(self.thread_show_info, i=q)
def thread(self):
t1 = Thread(target=self.threadpool_show_info,daemon=True)
t1.start()

if __name__=="__main__":
root = Tk()
root.title('test')
root.geometry('400x300+450+100')
a = MainWindows(master=root)
root.mainloop()

最新更新