demo1 from https://www.cnblogs.com/hhh5460/p/5175322.html
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QGridLayout
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
import time
import sys
class Worker(QObject):
finished = pyqtSignal()
intReady = pyqtSignal(int)
@pyqtSlot()
def work(self): # A slot takes no params
for i in range(1, 100):
time.sleep(1)
self.intReady.emit(i)
self.finished.emit()
class Form(QWidget):
def __init__(self):
super().__init__()
self.label = QLabel("0")
# 1 - create Worker and Thread inside the Form
self.worker = Worker() # no parent!
self.thread = QThread() # no parent!
self.worker.intReady.connect(self.updateLabel)
self.worker.moveToThread(self.thread)
self.worker.finished.connect(self.thread.quit)
self.thread.started.connect(self.worker.work)
#self.thread.finished.connect(app.exit)
self.thread.start()
self.initUI()
def initUI(self):
grid = QGridLayout()
self.setLayout(grid)
grid.addWidget(self.label,0,0)
self.move(300, 150)
self.setWindowTitle('thread test')
def updateLabel(self, i):
self.label.setText("{}".format(i))
#print(i)
app = QApplication(sys.argv)
form = Form()
form.show()
sys.exit(app.exec_())
demo2 from https://blog.csdn.net/qq_34710142/article/details/80936986
qt_prj/interface_jamming$ cat QThread4.py
#!/usr/bin/env python
# coding=utf-8
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class Worker(QThread):
sinOut = pyqtSignal(str) # 自定义信号,执行run()函数时,从相关线程发射此信号
def __init__(self, parent=None):
super(Worker, self).__init__(parent)
self.working = True
self.num = 0
def __del__(self):
self.working = False
self.wait()
def run(self):
while self.working == True:
file_str = 'File index {0}'.format(self.num) # str.format()
self.num += 1
# 发出信号
self.sinOut.emit(file_str)
# 线程休眠2秒
self.sleep(2)
class MainWidget(QWidget):
def __init__(self, parent=None):
super(MainWidget, self).__init__(parent)
self.setWindowTitle("QThread 例子")
# 布局管理
self.listFile = QListWidget()
self.btnStart = QPushButton('开始')
layout = QGridLayout(self)
layout.addWidget(self.listFile, 0, 0, 1, 2)
layout.addWidget(self.btnStart, 1, 1)
# 连接开始按钮和槽函数
self.btnStart.clicked.connect(self.slotStart)
# 创建新线程,将自定义信号sinOut连接到slotAdd()槽函数
self.thread = Worker()
self.thread.sinOut.connect(self.slotAdd)
# 开始按钮按下后使其不可用,启动线程
def slotStart(self):
self.btnStart.setEnabled(False)
self.thread.start()
# 在列表控件中动态添加字符串条目
def slotAdd(self, file_inf):
self.listFile.addItem(file_inf)
if __name__ == "__main__":
app = QApplication(sys.argv)
demo = MainWidget()
demo.show()
sys.exit(app.exec_())
demo3 卡死 from https://blog.csdn.net/qq_34710142/article/details/80936986
qt_prj/interface_jamming$ cat QThread_sleep.py
#!/usr/bin/env python
# coding=utf-8
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import time
global sec
sec = 0
def setTime():
global sec
sec += 1
# LED显示数字+1
lcdNumber.display(sec)
def work():
# 计时器每秒计数
timer.start(1000)
# 开始一次非常耗时的计算
# 这里用一个2 000 000 000次的循环来模拟
#for i in range(200000000):
# pass
print('start sleep: %s'%time.time())
time.sleep(1000)
#timer.stop()
if __name__ == "__main__":
app = QApplication(sys.argv)
top = QWidget()
top.resize(300, 120)
# 垂直布局类QVBoxLayout
layout = QVBoxLayout(top)
# 添加控件
lcdNumber = QLCDNumber()
layout.addWidget(lcdNumber)
button = QPushButton("测试")
layout.addWidget(button)
timer = QTimer()
# 每次计时结束,触发setTime
timer.timeout.connect(setTime)
# 连接测试按钮和槽函数work
button.clicked.connect(work)
top.show()
sys.exit(app.exec_())
似乎还是有顺序的,就是要睡完1000秒后,才去执行setTime函数。改成睡完5秒测试的确是这样的。
正常情况下,在点击按钮之后,LCD上的数字会随着时间发生变化,但是在实际运行过程中会发现点击按钮之后,程序界面直接停止响应,直到循环结束才开始重新更新,于是计时器始终显示为0。
为了避免出现上述问题,要使用QThread开启一个新的线程,在这个线程中完成耗时的操作
分离出干活的线程
qt_prj/interface_jamming$ cat QThread_live.py
#!/usr/bin/env python
# coding=utf-8
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
global sec
sec = 0
# 增加了一个继承自QThread类的类,重新写了它的run()函数
# run()函数即是新线程需要执行的:执行一个循环;发送计算完成的信号。
class WorkThread(QThread):
trigger = pyqtSignal()
def __int__(self):
super(WorkThread, self).__init__()
def run(self):
for i in range(2000000000):
pass
# 循环完毕后发出信号
self.trigger.emit()
def countTime():
global sec
sec += 1
# LED显示数字+1
lcdNumber.display(sec)
def work():
# 计时器每秒计数
timer.start(1000)
# 计时开始
workThread.start()
# 当获得循环完毕的信号时,停止计数
workThread.trigger.connect(timeStop)
def timeStop():
timer.stop()
print("运行结束用时", lcdNumber.value())
global sec
sec = 0
if __name__ == "__main__":
app = QApplication(sys.argv)
top = QWidget()
top.resize(300, 120)
# 垂直布局类QVBoxLayout
layout = QVBoxLayout(top)
# 加个显示屏
lcdNumber = QLCDNumber()
layout.addWidget(lcdNumber)
button = QPushButton("测试")
layout.addWidget(button)
timer = QTimer()
workThread = WorkThread()
button.clicked.connect(work)
# 每次计时结束,触发 countTime
timer.timeout.connect(countTime)
top.show()
sys.exit(app.exec_())
实时刷新
qt_prj/interface_jamming$ cat QThread_process.py
#!/usr/bin/env python
# coding=utf-8
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication, QListWidget, QGridLayout
import sys
import time
class WinForm(QWidget):
def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
self.setWindowTitle("实时刷新界面例子")
self.listFile = QListWidget()
self.btnStart = QPushButton('开始')
layout = QGridLayout(self)
layout.addWidget(self.listFile, 0, 0, 1, 2)
layout.addWidget(self.btnStart, 1, 1)
self.setLayout(layout)
self.btnStart.clicked.connect(self.slotAdd)
def slotAdd(self):
for n in range(10):
str_n = 'File index {0}'.format(n)
self.listFile.addItem(str_n)
QApplication.processEvents()
time.sleep(0.1)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = WinForm()
form.show()
sys.exit(app.exec_())
demo5
进度条
qt_prj/interface_jamming$ cat QThread5.py
#!/usr/bin/env python
# coding=utf-8
from PyQt5 import QtWidgets, QtCore
import sys
from PyQt5.QtCore import *
import time
# 继承QThread
class Runthread(QtCore.QThread):
# 通过类成员对象定义信号对象
_signal = pyqtSignal(str)
def __init__(self):
super(Runthread, self).__init__()
def __del__(self):
self.wait()
def run(self):
for i in range(100):
time.sleep(0.05)
self._signal.emit(str(i)) # 注意这里与_signal = pyqtSignal(str)中的类型相同
self._signal.emit(str(100))
class Example(QtWidgets.QWidget):
def __init__(self):
super().__init__()
# 按钮初始化
self.button = QtWidgets.QPushButton('开始', self)
self.button.setToolTip('这是一个 <b>QPushButton</b> widget')
self.button.resize(self.button.sizeHint())
self.button.move(120, 80)
self.button.clicked.connect(self.start_login) # 绑定多线程触发事件
# 进度条设置
self.pbar = QtWidgets.QProgressBar(self)
self.pbar.setGeometry(50, 50, 210, 25)
self.pbar.setValue(0)
# 窗口初始化
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('OmegaXYZ.com')
self.show()
self.thread = None # 初始化线程
def start_login(self):
# 创建线程
self.button.setEnabled(False)
self.thread = Runthread()
# 连接信号
self.thread._signal.connect(self.call_backlog) # 进程连接回传到GUI的事件
# 开始线程
self.thread.start()
def call_backlog(self, msg):
self.pbar.setValue(int(msg)) # 将线程的参数传入进度条
if msg == '100':
#self.thread.terminate()
del self.thread
self.button.setEnabled(True)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
myshow = Example()
myshow.show()
sys.exit(app.exec_())
demo 稍微复杂一点的例子
/interface_jamming$ cat QThread6.py
#!/usr/bin/env python
# coding=utf-8
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
import random
class Example(QObject):
signalStatus = pyqtSignal(str)
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
# Create a gui object.
self.gui = Window()
# Setup the worker object and the worker_thread.
self.worker = WorkerObject()
self.worker_thread = QThread()
self.worker.moveToThread(self.worker_thread)
self.worker_thread.start()
# Make any cross object connections.
self._connectSignals()
self.gui.show()
def _connectSignals(self):
self.gui.button_start.clicked.connect(self.worker.startWork)
self.gui.button_cancel.clicked.connect(self.forceWorkerReset)
self.signalStatus.connect(self.gui.updateStatus)
self.worker.signalStatus.connect(self.gui.updateStatus)
self.parent().aboutToQuit.connect(self.forceWorkerQuit)
def forceWorkerReset(self):
if self.worker_thread.isRunning():
self.worker_thread.terminate()
self.worker_thread.wait()
self.signalStatus.emit('Idle.')
self.worker_thread.start()
def forceWorkerQuit(self):
if self.worker_thread.isRunning():
self.worker_thread.terminate()
self.worker_thread.wait()
class WorkerObject(QObject):
signalStatus = pyqtSignal(str)
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
@pyqtSlot()
def startWork(self):
for ii in range(7):
number = random.randint(0,5000**ii)
self.signalStatus.emit('Iteration: {}, Factoring: {}'.format(ii, number))
factors = self.primeFactors(number)
print('Number: ', number, 'Factors: ', factors)
self.signalStatus.emit('Idle.')
def primeFactors(self, n):
i = 2
factors = []
while i * i <= n:
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors
class Window(QWidget):
def __init__(self):
QWidget.__init__(self)
self.button_start = QPushButton('Start', self)
self.button_cancel = QPushButton('Cancel', self)
self.label_status = QLabel('', self)
layout = QVBoxLayout(self)
layout.addWidget(self.button_start)
layout.addWidget(self.button_cancel)
layout.addWidget(self.label_status)
self.setFixedSize(400, 200)
@pyqtSlot(str)
def updateStatus(self, status):
self.label_status.setText(status)
if __name__=='__main__':
app = QApplication(sys.argv)
example = Example(app)
sys.exit(app.exec_())
他的退出方式,似乎挺奇怪的,注意到他的父类是app,他这样做到底想干啥?
一个线程定义多个信号
from https://blog.csdn.net/weixin_34150224/article/details/88320458
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2019年1月16日
@author: yiluo
@site: https://github.com/bingshilei
@email: 786129166@qq.com
@file: QThreadDemo2
@description: 使用多线程动态添加控件
"""
import time
from PyQt5.QtCore import QThread, pyqtSignal, QDateTime
from PyQt5.QtWidgets import QWidget, QLineEdit, QListWidget, QPushButton,\
QVBoxLayout, QLabel
'''
声明线程类
'''
class addItemThread(QThread):
add_item = pyqtSignal(str)
show_time = pyqtSignal(str)
'''
添加控件
'''
def __init__(self,*args, **kwargs):
super(addItemThread, self).__init__(*args, **kwargs)
self.num = 0
def run(self, *args, **kwargs):
while True:
file_str = 'File index{0}'.format(self.num,*args, **kwargs)
self.num +=1
#发送添加信号
self.add_item.emit(file_str)
date = QDateTime.currentDateTime()
currtime = date.toString('yyyy-MM-dd hh:mm:ss')
print(currtime)
self.show_time.emit(str(currtime))
time.sleep(1)
class Window(QWidget):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
self.setWindowTitle('多线程动态添加控件')
# x,y,w,h
self.setGeometry(800, 100, 500, 750)
#创建QListWidget控件
self.listWidget = QListWidget()
#创建按钮控件
self.btn = QPushButton('开始',self)
self.lb = QLabel('显示时间',self)
#创建布局控件
self.vlayout = QVBoxLayout()
#将按钮和列表控件添加到布局
self.vlayout.addWidget(self.btn)
self.vlayout.addWidget(self.lb)
self.vlayout.addWidget(self.listWidget)
#设置窗体的布局
self.setLayout(self.vlayout)
#绑定按钮槽函数
self.btn.clicked.connect(self.startThread)
#声明线程实例
self.additemthread = addItemThread()
#绑定增加控件函数
self.additemthread.add_item.connect(self.addItem)
#绑定显示时间函数
self.additemthread.show_time.connect(self.showTime)
'''
@description:按钮开始,启动线程
'''
def startThread(self):
#按钮不可用
self.btn.setEnabled(False)
#启动线程
self.additemthread.start()
'''
@description:为listwidget增加项
@param:项的值
'''
def addItem(self,file_str):
self.listWidget.addItem(file_str)
'''
@description:显示时间
@param:项的值
'''
def showTime(self,time):
self.lb.setText(time)
if __name__ == '__main__':
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
QThread 线程里面启用常规子线程干活
from https://blog.csdn.net/weiyang_tang/article/details/82748111
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon
import sys
import os
import threading
class fileSearchThread(QThread):
sinOut = pyqtSignal(str)
# 自定义信号,执行run()函数时,从相关线程发射此信号
def __init__(self,key):
super().__init__()
self.key = key
def run(self):
threads=[]
path = [r"c:\\", r"d:\\", r"e:\\", r"f:\\"]
#通过多线程对windows下的多个盘符进行文件的遍历查找
for each in path:
t = threading.Thread(target=self.search, args=(self.key,each,))
threads.append(t)
t.start()
for i in range(len(threads)): #将主线程阻塞
threads[i].join()
print("搜索结束")
def search(self,keyword, path):
for dirpath, dirnames, filenames in os.walk(path):
for filename in filenames:
if filename.__contains__(keyword):
print(os.path.join(dirpath, filename))
self.sinOut.emit(os.path.join(dirpath, filename))
for folder in dirnames:
if folder.__contains__(keyword):
print(os.path.join(dirpath,folder))
self.sinOut.emit(os.path.join(dirpath,folder))
class fileSearch(QListWidget):
def __init__(self):
super().__init__()
self.Ui()
def Ui(self):
self.key= QLineEdit()
self.bt=QPushButton("搜索")
self.result = QListWidget()
self.bt.clicked.connect(self.ButtonClicked) #按钮单击信号绑定到槽
# self.line.editingFinished.connect(self.Action)
self.key.editingFinished.connect(self.ButtonClicked)
grid = QGridLayout()
grid.setSpacing(10) # 创建标签之间的空间
grid.addWidget(self.key, 1, 0) # (1,0)表示显示的位置
grid.addWidget(self.bt, 1, 1)
grid.addWidget(self.result, 2, 0, 5, 2) # 指定组件的跨行和跨列的大小,指定这个元素跨5行显示
self.setLayout(grid)
for i in range(1,100):
self.result.addItem("搜索"+str(i)+"个项目")
self.result.itemClicked.connect(self.Clicked)
self.setGeometry(300, 300, 500, 500)
self.setWindowTitle('文件搜索')
self.setWindowIcon(QIcon('icon.jpg'))
self.show()
def Clicked(self, item):
QMessageBox.information(self, "ListWidget", "You clicked: " + item.text())
os.startfile(item.text()) #打开文件
def ButtonClicked(self):
# 创建新线程,将自定义信号sinOut连接到slotAdd()槽函数
keyword = self.key.text()
self.result.clear()
self.thread=fileSearchThread(keyword)
self.thread.sinOut.connect(self.slotAdd)
self.thread.start()
def slotAdd(self,filename):
self.result.addItem(str(filename))
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = fileSearch()
sys.exit(app.exec_())