我有一个按钮,命令起作用。此函数内部有2个函数。
。
import multiprocessing
import time
import tkinter.ttk as ttk
from tkinter import *
class Sth:
def __init__(self, main):
Button(main, text='Start processing!', command=self.go).pack(side=TOP)
def popup(self):
t = Toplevel()
t.wm_attributes('-topmost', 1)
self.f = Frame(t)
self.f.pack()
Label(self.f, text='Please, wait...').pack()
self.pb = ttk.Progressbar(self.f, mode="determinate")
self.pb.pack()
def go(self):
p1 = multiprocessing.Process(target=self.popup())
p1.start()
p1.join()
p2 = multiprocessing.Process(target=self.process())
p2.start()
p2.join()
# self.popup()
# self.process()
def process(self):
for i in range(5):
self.pb['value'] += 20
print('doing sth')
time.sleep(0.5)
if __name__ == "__main__":
main = Tk()
Sth(main)
main.mainloop()
但是具有顶层和进度条的func,必须在执行之后才打开主calc函数,然后再打开。我做错了什么?
答案 0 :(得分:0)
首先:所有GUI /小部件(在大多数GUI框架中,在大多数语言中)都必须在主线程(主进程)中运行。
您可以在单独的过程中运行计算,但是ProgressBar
必须在主要过程中。您将需要queue
才能将数据从计算发送到主流程。并且您将需要tkinter.after(milliseconds, function)
来运行将定期运行的功能,以检查队列并更新ProgressBar
(并且不会阻止mainloop
)。
我在主进程中运行popup
,它使用multiprocessing
来运行计算(但没有join()
会阻塞所有代码)。它还运行update_progressbar
,它检查队列中是否有新数据要更新进度条。它使用after()
在100毫秒后再次运行自身-这样就不会阻塞mainloop
。钙
我使用queue.empty()
来检查是否有要获取的数据,因为通常queue.get()
会等待数据和块代码,然后mainloop
我不使用p.join()
,因为它还会阻塞代码。关闭程序时可以检查它-但我跳过了这一部分。
import multiprocessing
import time
import tkinter.ttk as ttk
#from tkinter import * # not preferred
import tkinter as tk
class Sth:
def __init__(self, main):
tk.Button(main, text='Start processing!', command=self.popup).pack(side='top')
def popup(self):
self.t = tk.Toplevel()
self.t.wm_attributes('-topmost', 1)
self.f = tk.Frame(self.t)
self.f.pack()
tk.Label(self.f, text='Please, wait...').pack()
self.pb = ttk.Progressbar(self.f, mode="determinate")
self.pb.pack()
self.queue = multiprocessing.Queue()
p = multiprocessing.Process(target=self.process, args=(self.queue,))
p.start()
#p.join() # don't use in this place becaus it blocks all code
self.update_progressbar()
def update_progressbar(self):
if not self.queue.empty(): # without this `get()` will wait for data and it will block code
self.pb['value'] += self.queue.get()
if self.pb['value'] < 100:
self.t.after(100, self.update_progressbar)
def process(self, q):
for i in range(10):
q.put(10)
print('doing sth')
time.sleep(.5)
if __name__ == "__main__":
main = tk.Tk()
Sth(main)
main.mainloop()