最近在用qt做项目的时候,由于项目只有一个线程,所以在处理图片的时候,视频流就卡住了。以下用一个例子简单记录如何解决新建子线程时传参和子线程返回数据到主线程的问题。
UI代码(untitled.py)
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.lineEdit = QtWidgets.QLineEdit(Form)
self.lineEdit.setGeometry(QtCore.QRect(140, 80, 113, 21))
self.lineEdit.setObjectName("lineEdit")
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(150, 150, 93, 28))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton.setText(_translate("Form", "test"))
槽函数代码(slot.py)
from PyQt5.QtWidgets import QWidget
from PyQt5.QtCore import QThread, pyqtSignal
from untitled import Ui_Form
# 子线程类
class TestThread(QThread):
声明用于传递数据到主线程的信号并指定传输的数据类型,
此信号不能在__init__方法中声明,
传递的数据类型支持标准的python数据类型,
如字符串、日期、布尔类型,数字,列表,元组和字典。
testsignal= pyqtSignal(str)
def __init__(self, msg):
super(TestThread, self).__init__()
self.msg = msg
def __del__(self):
self.wait()
def run(self):
self.msg = 'This is a ' + self.msg
# 发射信号
self.testsignal.emit(self.msg)
class Slot(QWidget, Ui_Form):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_Form
self.setupUi(self)
self.pushButton.clicked.connect(self.text)
def text(self):
# 新建有参数的子线程
self.thread = TestThread('test')
# 连接信号和用于更新ui的函数
self.thread.testsignal.connect(self.showText)
self.thread.start()
def showText(self, msg):
self.lineEdit.setText(msg)
运行代码(main.py)
import sys
from qtpy import QtWidgets
from slot import Slot
app = QtWidgets.QApplication(sys.argv)
a = Slot()
a.show()
sys.exit(app.exec_())
参考了这篇博客的内容:https://blog.csdn.net/wuwei_201/article/details/104720386
b.使用多线程模块QThread
c.使用事件处理功能
QTimer相当于一个定时器,每当定时器时间溢出后,会执行相关的函数。这个时候程序会从主线程界面跳到QTimer函数中,如果QTimer函数中有延时或者处理时间较长,就会出现界面失去响应,造成界面卡顿的现象。
QThread等于新开一个线程专门处理耗时间的程序,UI主线程显示界面,当子线程处理好数据后通过自定义的信号与槽,将数据交给主线程刷新界面。由于UI主线程一直运行,子线程的延时
今天想要实现子线程与子线程之间参数的传送,而且是要实现动态传参,上网搜了好久,然后又自己尝试,结果发现实在不知道如何直接实现两个子线程之间参数的传递(利用实例化时参数无法实现动态传参),使用信号与槽机制结果传到另一个线程里的不知道是啥。最后采用了子线程->主线程->子线程的思路。
这里需要搞明白信号发送与接受,还有主线程动态传参到子线程。首先看一下界面:
我想要实现label标签内的数字随着进度的变化而变化,利用线程实现(当然有更简单的方法,这里仅是为了了解线程)。
建立两个线程类:.
问题如下:在主程序中定义两个线程A和B,现要求将线程A中的信息传给B的变量。
事实上,利用Queue,可以解决python函数传入tk.StringVar按值传递的问题:想要在函数体内改变tk.StringVar的值,但是直接将其传入会复制一份tk.StringVar,而不是原来的那个tk.StringVar。
如果不把tk.StringVar提升为跨脚本的全局变量,还有什么办法呢?
答案就是利用Queue,在主程序里定义一个queue,将queue作为参数(这时,queue为一个可变对象,python会做
主线程就是进程,进程代表4个G的资源空间,主线程退出就意味着进程退出,在Qt中,主线程不能是子线程的父对象,因此必须在线程的析构函数中去delete线程对象。
只要定时器启动,自动触发timeout()信号
类A继承了Tread类,在A中写run方法,就会覆盖掉Thread中的run方法,所以此时调用start方法后,实现的是自己的run方法体里面的代码。start()相当于间接的调用run(),如果我们直接调用子线程的run()方法,其方法还是运行在主线程中,代码在程序中是
QT6
多线程Qthread(二),也可以这样写
Qt有两种
多线程的方法,一种是实现
QThread的run函数,另一种是定义一个继承于QObject的对象放入到一个Thread里,其实两种方法区别不大,用起来都比较方便。
Qt官方建议使用第二种方法,由于上一篇已经介绍了第二种方法,为了方便小伙伴们对两种
多线程的使用方法进行比较,本篇对第一种
多线程的使用方法举例讲解。
实现
多线程一共有四步:
创建
线程类,继承
Qthread
重写该
线程类的run()方法
在
主线程中,创建任务对象
使用start()启动
线程
在主线程ui界面点击登录后,加延时10s,(模拟掉接口登录,假设耗时10s),ui主线程在等待请求返回结果,ui界面卡主,转圈,如下图。这个现象在软件中肯定是不能出现的!
现在这个问题解决方法,就是点击按钮后,主线程触发一个子线程去执行,让子线程执行耗时任务,主线程就会处于空闲状态,那么界面就不会出现转圈卡顿的现象!当子线程任务执行完成后,给主线程自定义信号发送消息,主线程收到,消息,反馈到主界面来!
完整的案例代码,如下,点击登录按钮是走主线程执行,会出现卡顿;点击忘记密码按钮,会触发子线程执行任务,主线
由于自己做的pyqt界面经常出现假死,本人实在不堪其扰,所以想学一下多线程。
话不多说,直接进入正题。
我们都知道子线程给ui主线程传递参数可以通过pyqtsignal方式来传递,但是主线程给子线程传递参数却很少人用
#方法一:全局变量法
import cv2
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import QThread, pyqtSignal, QDateTime
from PyQt5.QtWidgets import QApp
窗口文件cmainwindow.cppCMainWindow::CMainWindow(QWidget*parent):
QMainWindow(parent),
ui(newUi::CMainWindow)
ui->setupUi(this);....
connect(threadA,SIGNAL(signalUpdateData(QString)),this,SLOT(sl...
在 PyQt 的多线程编程中,如果你的子线程没有访问主线程的标签,可能是因为你没有正确地使用信号与槽机制。
具体来说,你可以在主线程中定义一个槽函数,用于更新标签的文本,然后在子线程中发射这个信号,从而触发这个槽函数。以下是一个简单的示例代码:
```python
from PyQt5.QtCore import QThread, pyqtSignal
class MyThread(QThread):
update_signal = pyqtSignal(str)
def run(self):
while True:
text = "当前时间:{}".format(datetime.now())
self.update_signal.emit(text)
time.sleep(1)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.label = QLabel()
self.setCentralWidget(self.label)
self.thread = MyThread()
self.thread.update_signal.connect(self.update_label)
self.thread.start()
def update_label(self, text):
self.label.setText(text)
在上面的代码中,`MyThread` 类继承自 `QThread`,并定义了一个 `update_signal` 信号,用于在子线程中更新标签的文本。`MainWindow` 类继承自 `QMainWindow`,并包含一个标签 `label`。在 `MainWindow` 的构造函数中,创建一个 `MyThread` 的实例,并将它的 `update_signal` 信号连接到 `MainWindow` 的 `update_label` 槽函数上。然后,启动子线程,这样,每隔一秒钟,子线程就会发射 `update_signal` 信号,从而触发 `update_label` 槽函数,在主线程中更新标签的文本。
请注意,在使用 PyQt 的多线程编程时,应该避免直接访问主线程的 UI 元素,因为这样会导致线程不安全的问题。相反,你应该使用信号与槽机制来实现线程间的通信。