在后台运行函数 - 如何实现?Python和PyQT
我有一个比较大的应用程序,是用Python写的,前端用的是PyQT。整个应用程序都在一个类里,放在一个文件中。
下面是一个示例代码:
class Application(QMainWindow):
def __init__(self):
super(etc...)
self.connect(self.mainBtn, SIGNAL("clicked()"), self.do_stuff)
def do_stuff(self):
<checking some parameters>
else:
do_some_other_long_stuff()
def do_some_other_long_stuff(self):
500 lines of code of stuff doing
但是,这里有个问题:当我点击mainBtn时,一切都很顺利,除了界面会有点卡住——在这个函数执行期间,我什么都不能做(因为它是个网页抓取工具,所以需要花费不少时间)。等到函数do_some_other_long_stuff结束后,一切又恢复正常。这真的很让人烦。
有没有办法让do_some_other_stuff这个过程在“后台”运行呢?我查了一下QThreads,似乎可以做到这一点,但这就意味着我得重写几乎所有的代码,把程序的一半放到另一个类里,还得改所有的变量名(因为要从GUI类中获取变量,然后放到工作类中)。
1 个回答
2
这段内容是关于如何在不同线程中处理图形用户界面(GUI)的,类似的问题还有很多,比如如何处理不同线程的GUI和如何在Python中跟踪线程进度而不冻结PyQt GUI等。
你的do_stuff()函数需要启动一个计算线程,然后返回。多线程就是在一个程序里同时运行多个任务的意思——简单来说,如果有事情在“后台”进行,那就是在另一个线程上运行。不过,你不需要把函数拆分到不同的类里才能使用线程,只要确保计算函数不和GUI有任何交互,同时主线程也不要调用计算线程使用的任何函数。
编辑于10月23日:这里有个简单的例子,展示如何在一个类里运行多个线程——其实语言或线程库并没有要求每个线程都用不同的类。这个例子可能使用了单独的类来处理,以便展示良好的模块化编程。
from tkinter import *
import threading
class MyApp:
def __init__(self, root):
self.root = root
self.timer_evt = threading.Event()
cf = Frame(root, borderwidth=1, relief="raised")
cf.pack()
Button(cf, text="Run", command=self.Run).pack(fill=X)
Button(cf, text="Pause", command=self.Pause).pack(fill=X)
Button(cf, text="Kill", command=self.Kill).pack(fill=X)
def process_stuff(self): # processing threads
while self.go:
print("Spam... ")
self.timer_evt.wait()
self.timer_evt.clear()
def Run(self): # start another thread
self.go = 1
threading.Thread(target=self.process_stuff, name="_proc").start()
self.root.after(0, self.tick)
def Pause(self):
self.go = 0
def Kill(self): # wake threads up so they can die
self.go = 0
self.timer_evt.set()
def tick(self):
if self.go:
self.timer_evt.set() # unblock processing threads
self.root.after(1000, self.tick)
def main():
root = Tk()
root.title("ProcessingThread")
app = MyApp(root)
root.mainloop()
main()