这是一种方法,它使用线程和队列来不阻塞.mainloop()
和不调用tkinter
另一个线程的方法(这可能会破坏它):
import tkinter as tk
from subprocess import Popen, PIPE
from threading import Thread
from queue import Queue
def start_new_proc():
# text.config(cursor="clock")
root.config(cursor="clock")
text.config(state="normal")
queue = Queue()
Thread(target=lambda: run_proc(queue)).start()
update_text(queue)
def after_proc():
# text.config(cursor="")
root.config(cursor="")
text.config(state="disable")
def update_text(queue):
data = queue.get()
if data == 'break':
after_proc()
return
text.insert('end', data)
root.after(100, update_text, queue)
def run_proc(queue):
command = "ping 8.8.8.8"
proc = Popen(command, shell=True, stdout=PIPE)
for line in iter(proc.stdout.readline, ''):
line = line.decode('utf-8')
if line == '':
queue.put('break')
break
queue.put(line)
# proc.wait()
root = tk.Tk()
text = tk.Text(root, state="disabled")
text.pack()
button = tk.Button(root, text="Run", command=start_new_proc)
button.pack()
root.mainloop()
快速解释:
当您单击按钮时,它会调用start_new_proc()
:
现在首先运行所有配置,所以现在配置了光标和文本(请注意,时钟光标仅在光标不在文本小部件上时可见,因为文本小部件的配置已被注释掉)
然后创建一个队列对象,这将允许线程之间安全地通信(一旦函数“停止”,它将被垃圾收集)
然后在cmd
运行命令的地方启动一个线程(哦,我对其进行了一些更改(删除了“-c 1”),因为我无法进行其他测试)。所以每次迭代都会将数据放入队列中,以便主线程安全地接收它,其他东西是一样的,还要注意一旦循环必须停止,就会有'“break”'放入队列中,以便另一端也知道停止(可能更好地放置一些对象,因为"break"
可以通过line
变量放置在那里)
然后update_text()
调用该函数,该函数从队列接收数据,然后将其插入到文本小部件(还有"break"
检查),然后是.after()
在不阻塞的情况下使函数循环的方法.mainloop()
(并且当"break"
appears 时,配置函数被调用到 config状态和光标)