闲着没什么事,最近才开始学习PYTHON和PYQT5了,参考相关资料,写了一个同时创建三个线程,并采用两种方法得到线程中的变量值的小程序:
一、第一种方法采用PYQT5信号槽的方式,这种方法实时性高,可以即时得到对应线程的变更数据内容。方法为:自定义一多线程类ThreadClass,该类重载PYQT5的多线程类QtCore.QThread,并在类中定义信号signal_ID,在需要时在线程类中发送此信号,让主窗体来接收此信号。接着需要在主窗口类中定义线程对象:
self.thread={} #数据内容为空,在后面要创建新线程时再增加对象数量,本示例只同时创建三个线程。
self.thread[1] = ThreadClass(parent=None,index=1)
在主窗口中绑定线程的信号槽函数(所有线程可绑定同一槽函数,通过线程的索引号来区分中哪个线程返回的变量值),如将上面定义的信号名称为signal_ID绑定到窗体类的一自定义(槽)函数
my_function,即可以在此槽函数来接收各线程发送的变更数据了。
self.thread[1].signal_ID.connect(self.my_function) #将线程1中的自定义信号signal_ID绑定槽函数self.my_function
二、如不想使用信号槽函数,对实时性要求不高的数据,也可以采用在窗体中的计时器事件,来定时从多线程对象中查询对应变量的值情况,方法相对简单,在窗体计时器事件中直接得到上面实例化线程对象的成员变量值即可(建议采用多线程中定义函数体返回变量值)
全部代码如下:
import sys
import PyQt5
from PyQt5 import *
from PyQt5 import QtCore #不加此行要报错,上行不是全导入了嘛,没懂
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import time
class Main(QWidget):
btime=False #是否开启计时器
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setWindowTitle('多线程(3个)示例【同时使用QT信号槽和窗体计时器同线程变量通信】')
self.resize(600,600)
self.btime = False #控制计时器是否运行
layout = QFormLayout()
self.pushButton_1 = QPushButton()
self.pushButton_1.setText("开始新线程1")
self.pushButton_2 = QPushButton()
self.pushButton_2.setText("开始新线程2")
self.pushButton_3 = QPushButton()
self.pushButton_3.setText("开始新线程3")
self.pushButton_4 = QPushButton()
self.pushButton_4.setText("停止新线程1")
self.pushButton_5 = QPushButton()
self.pushButton_5.setText("停止新线程2")
self.pushButton_6 = QPushButton()
self.pushButton_6.setText("停止新线程3")
self.edita1 = QLineEdit()
self.edita1.setText('信号槽:线程1的值')
self.progressBar_1=QProgressBar()
self.progressBar_1.setMinimum(0)
self.progressBar_1.setMaximum(100)
self.edita2 = QLineEdit()
self.edita2.setText('信号槽:线程2的值')
self.progressBar_2=QProgressBar()
self.progressBar_2.setMinimum(0)
self.progressBar_2.setMaximum(100)
self.edita3 = QLineEdit()
self.edita3.setText('信号槽:线程3的值')
self.edita4 = QLineEdit()
self.progressBar_3=QProgressBar()
self.progressBar_3.setMinimum(0)
self.progressBar_3.setMaximum(100)
self.pushButton_7 = QPushButton()
self.pushButton_7.setText("开始计时器(周期100毫秒)")
self.pushButton_8 = QPushButton()
self.pushButton_8.setText("停止计时器")
self.edita4.setText('计时器:线程1的值')
self.edita5 = QLineEdit()
self.edita5.setText('计时器:线程2的值')
self.edita6 = QLineEdit()
self.edita6.setText('计时器:线程3的值')
layout.addRow("单击按纽开始线程1(线程sleep 10毫秒)->",self.pushButton_1)
layout.addRow("单击按纽结束线程1->",self.pushButton_4)
layout.addRow("信号槽方式返回线程1的值->",self.edita1)
layout.addRow("线程1返回值(进度条展示)->",self.progressBar_1)
layout.addRow("单击按纽开始线程2(线程sleep 50毫秒)->",self.pushButton_2)
layout.addRow("单击按纽结束线程2->",self.pushButton_5)
layout.addRow("信号槽方式返回线程2的值->",self.edita2)
layout.addRow("线程2返回值(进度条展示)->",self.progressBar_2)
layout.addRow("单击按纽开始线程3(线程sleep 100毫秒)->",self.pushButton_3)
layout.addRow("单击按纽结束线程3->",self.pushButton_6)
layout.addRow("信号槽方式返回线程3的值->",self.edita3)
layout.addRow("线程3返回值(进度条展示)->",self.progressBar_3)
layout.addRow("单击按纽开始计时器(周期100毫秒)->",self.pushButton_7)
layout.addRow("单击按纽停止计时器->",self.pushButton_8)
layout.addRow("计时器方式得到线程1的值->",self.edita4)
layout.addRow("计时器方式得到线程2的值->",self.edita5)
layout.addRow("计时器方式得到线程3的值->",self.edita6)
self.setLayout(layout)
self.pushButton_4.setEnabled(False)
self.pushButton_5.setEnabled(False)
self.pushButton_6.setEnabled(False)
self.pushButton_8.setEnabled(False)
#定义线程数组
self.thread={}
self.bthreadopen=[0,False,False,False] #定义三个线程打开的状况,供计时器函数中取线程值时使用
self.pushButton_1.clicked.connect(self.start_worker_1)
self.pushButton_2.clicked.connect(self.start_worker_2)
self.pushButton_3.clicked.connect(self.start_worker_3)
self.pushButton_4.clicked.connect(self.stop_worker_1)
self.pushButton_5.clicked.connect(self.stop_worker_2)
self.pushButton_6.clicked.connect(self.stop_worker_3)
self.pushButton_7.clicked.connect(self.start_time)
self.pushButton_8.clicked.connect(self.stop_time)
#点击按纽1的信号槽:开始线程1
def start_worker_1(self):
self.thread[1] = ThreadClass(parent=None,index=1)
self.bthreadopen[1]=True
self.thread[1].start()
self.thread[1].signal_ID.connect(self.my_function) #将线程1中的自定义信号signal_ID绑定槽函数self.my_function
self.pushButton_1.setEnabled(False)
self.pushButton_4.setEnabled(True)
#点击按纽2的信号槽:开始线程2
def start_worker_2(self):
self.thread[2] = ThreadClass(parent=None, index=2)
self.bthreadopen[2]=True
self.thread[2].start()
self.thread[2].signal_ID.connect(self.my_function) #将线程2中的自定义信号signal_ID绑定槽函数self.my_function
self.pushButton_2.setEnabled(False)
self.pushButton_5.setEnabled(True)
#点击按纽3的信号槽:开始线程3
def start_worker_3(self):
self.thread[3] = ThreadClass(parent=None,index=3)
self.bthreadopen[3]=True
self.thread[3].start()
self.thread[3].signal_ID.connect(self.my_function) #将线程3中的自定义信号signal_ID绑定槽函数self.my_function
self.pushButton_3.setEnabled(False)
self.pushButton_6.setEnabled(True)
#点击按纽4的信号槽:结束线程1
def stop_worker_1(self):
self.thread[1].stop()
self.pushButton_1.setEnabled(True)
self.pushButton_4.setEnabled(False)
self.bthreadopen[1]=False
#点击按纽5的信号槽:结束线程2
def stop_worker_2(self):
self.thread[2].stop()
self.pushButton_2.setEnabled(True)
self.pushButton_5.setEnabled(False)
self.bthreadopen[2]=False
#点击按纽6的信号槽:结束线程3
def stop_worker_3(self):
self.thread[3].stop()
self.pushButton_3.setEnabled(True)
self.pushButton_6.setEnabled(False)
self.bthreadopen[3]=False
#绑定线程类中的signal_ID信号对应的槽函数,得到各线程中的变量ID的值
def my_function(self,counter):
ID = counter
index = self.sender().index #在槽函数中被调用,用于获取发出信号的对象,的索引号
if index == 1:
self.progressBar_1.setValue(ID)
ss='线程1通过信号槽返回的值='+str(ID)
self.edita1.setText(ss)
if index == 2:
self.progressBar_2.setValue(ID)
ss='线程2通过信号槽返回的值='+str(ID)
self.edita2.setText(ss)
if index == 3:
self.progressBar_3.setValue(ID)
ss='线程3通过信号槽返回的值='+str(ID)
self.edita3.setText(ss)
#重载计时器事件函数
def timerEvent(self, a):
if(self.btime):
count = len(self.thread)
if(count==0):
print('没有指定的多线程被打开')
return
if(self.bthreadopen[1]==True): #开了1线程
index,id=self.thread[1].getID()
timestr = '窗体计时器得到线程'+str(index)+'中ID变量值:'+ str(id)
self.edita4.setText(timestr)
if(self.bthreadopen[2]==True): #开了2线程
index,id=self.thread[2].getID()
timestr = '窗体计时器得到线程'+str(index)+'中ID变量值:'+ str(id)
self.edita5.setText(timestr)
if(self.bthreadopen[3]==True): #开了3线程
index,id=self.thread[3].getID()
timestr = '窗体计时器得到线程'+str(index)+'中ID变量值:'+ str(id)
self.edita6.setText(timestr)
#点击按纽7的信号槽:开始计时器的方式来分别得到各线程中的ID变量值
def start_time(self):
print("窗体中的计时器开始执行,周期100毫秒")
self.pushButton_7.setEnabled(False)
self.pushButton_8.setEnabled(True)
self.btime=True
self.timerid = self.startTimer(100) #计时器间隔100毫秒
#点击按纽8的信号槽:结束计时器
def stop_time(self):
self.btime=False
self.pushButton_8.setEnabled(False)
self.pushButton_7.setEnabled(True)
#自定义线程类(继承QT的多线程类QtCore.QThread,不是PYTHON的线程类)
class ThreadClass(QtCore.QThread):
signal_ID = QtCore.pyqtSignal(int) #自定义线程中的信号,名称为signal_ID
ID=0
def __init__(self,parent=None,index=0):
super(ThreadClass,self).__init__(parent)
self.index = index
self.is_running = True
def run(self):
print('开始线程...',self.index)
while(True):
self.ID+=1
if self.ID==99: self.ID=0
if(self.index==1):
time.sleep(0.01) #10毫秒间隔
elif(self.index==2):
time.sleep(0.05) #50毫秒间隔
elif(self.index==3):
time.sleep(0.1) #100毫秒间隔
else:
time.sleep(1) #1000毫秒间隔
self.signal_ID.emit(self.ID) #将本线程中的ID值(0-99)通过信号signal_ID槽发送,接收端通过
def stop(self):
self.is_running=False
print('停止线程...',self.index)
self.terminate()
#线程中自定义函数供外部调用线程中的变量值
def getID(self):
return self.index,self.ID
if __name__=="__main__":
app = QApplication([])
main = Main()
main.show()
app.exec()