新手在使用pyqt开发界面时,想要使用sleep函数或者其他耗时操作,会发现窗口卡死,显示未相应这种情况。
这种情况是因为pyqt在执行这个操作时,使用的是单线程,线程被阻塞导致的,所以这个时候就需要使用pyqt的qthread。
有人想到用python自带的threading来进行多线程控制,这个也不是不可以,也能够解决相关问题,不过好像qthread是真线程,而且思想上也更加接近qt的信号和槽机制,比较适合在pyqt编程时使用。
下面就说下这个qthread如何使用,也是一个小demo,尽量一行一行解释吧。
class StartEXE(QtCore.QThread):
def __int__(self):
super(StartEXE, self).__init__()
def run(self):
os.chdir(os.path.dirname(self.tool_path))
p = subprocess.Popen(self.tool_path, shell=True, stdout = subprocess.PIPE)
if __name__ == "__main__":
mythread = StartEXE()
mythread.tool_path = self.configOBJ.config.get(section_name, 'tool_path')
mythread.start()
这端代码是我写的软件中的一段demo,是使用多线程启动传入路径的exe文件的,正好可以拿来说明下这个qt的多线程使用方法。
首先qthread使用上是要写一个继承qthread的类,然后在类中重写这个qthread的run方法,从而达到使用多线程的目的。
代码中在main中首先是初始化了这个类,然后紧接着看这个类中,
class StartEXE(QtCore.QThread)
这个是说明这个类是继承这个QThread的;
def __int__(self):
这个初始化方法是初始化父类,也就是QThread中的__init__方法用的,这个一般照抄就行了,有兴趣可以看下QThread中的初始化方法是什么样子的。
def run(self):
这个方法是重写QThread中run方法的,直接把你想要多线程运行的东西都放在这个方法里面就行了。
然后回到这个main中,
mythread.tool_path = self.configOBJ.config.get(section_name, 'tool_path')
这句是给多线程的类中值赋值,当然这种传递值的方法没有使用相关的信号槽机制。
最后这句
mythread.start()
这个是启动这个多线程的,
这个就是QThread的一个初级使用。
因为一般我们使用QThread的时候都是在图形化编程的时候使用的,肯定会使用到信号和槽相关机制,这种机制如果在多线程中使用,就可以控制主窗口中的一些控件,比如说在textbrower中实时的显示文字等。
想在多线程中使用信号和槽机制,最好的办法就是使用自定义的信号和槽。
还是以刚刚的例子举例,不同的是向其中添加了下自定义的信号和槽。
class StartEXE(QtCore.QThread):
trigger = QtCore.pyqtSignal(str)
def __int__(self):
super(StartEXE, self).__init__()
def run(self):
os.chdir(os.path.dirname(self.tool_path))
p = subprocess.Popen(self.tool_path, shell=True, stdout = subprocess.PIPE)
self.trigger.emit("success")
if __name__ == "__main__":
mythread = StartEXE()
mythread.tool_path = self.configOBJ.config.get(section_name, 'tool_path')
mythread.start()
mythread.trigger.connect(self.xxxx)
这段代码也是节选,省略了主界面得到值之后具体处理的过程,不过也不重要。
这个代码的比上面多出的几行的具体解释是这样的。
首先这个多线程函数多了一行,
trigger = QtCore.pyqtSignal(str)
这个是pyqt中自定义信号和槽机制的语句
run中多了一行
self.trigger.emit("success")
这个就是发送信号
main中也多了一行
mythread.trigger.connect(self.xxxx)
这个就是将信号和槽关联起来的语句,可以将线程中的信号发射到主线程中,从而可以完成传递信息的操作。(这个connext中可以不用写名参数,在self.xxxx会自动收到相应的信号)