PyQt 多线程基础学习

本文通过两个示例展示了在PyQt中如何利用QThread避免主线程被阻塞导致GUI界面卡死。基础案例说明了直接在槽函数中执行耗时操作会引发的问题,而QThread解决方案则提出将耗时任务移到子线程中执行,确保界面的正常响应。两种在QThread中更新lineEdit的方法分别是直接传递lineEdit对象和使用信号与槽机制。
摘要由CSDN通过智能技术生成
1,基础案例

先来看段代码。功能是按下Button 1的时候控制台打印1-100,同时lineEdit 1也显示1-100,每隔1秒打印显示一次;按下Button 2的时候控制台打印100-1,同时lineEdit 2也显示100-1,每隔1秒打印显示一次。然而当实际按下按钮1时,控制台确实在打印,然而gui却卡死了,lineEdit也无法显示。

import sys
import time

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QThread")
        self.resize(300, 400)
        self.widget = QWidget()
        self.setCentralWidget(self.widget)
        self.layout = QtWidgets.QVBoxLayout(self.widget)
        self.lineEdit1 = QtWidgets.QLineEdit(self.widget)
        self.lineEdit1.setObjectName("lineEdit1")
        self.pushButton1 = QtWidgets.QPushButton(self.widget)
        self.pushButton1.setObjectName("pushButton1")
        self.pushButton1.setText("Button 1")
        self.lineEdit2 = QtWidgets.QLineEdit(self.widget)
        self.lineEdit2.setObjectName("lineEdit2")
        self.pushButton2 = QtWidgets.QPushButton(self.widget)
        self.pushButton2.setObjectName("pushButton2")
        self.pushButton2.setText("Button 2")
        self.layout.addWidget(self.lineEdit1)
        self.layout.addWidget(self.pushButton1)
        self.layout.addWidget(self.lineEdit2)
        self.layout.addWidget(self.pushButton2)
        QtCore.QMetaObject.connectSlotsByName(self)

    @pyqtSlot()
    def on_pushButton1_clicked(self):
        for i in range(100):
            self.lineEdit1.setText(str(i))
            print(i)
            time.sleep(1)

    @pyqtSlot()
    def on_pushButton2_clicked(self):
        for i in range(100):
            self.lineEdit1.setText(str(100-i))
            print(100 - i)
            time.sleep(1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())

在这里插入图片描述

2,QThread解决方案

单独实现控制台打印很简答,增加两个QThread子类,当按下按钮时创建并运行子类的run方法即可。注意thread1和thread2需要定义为实例属性,不要定义为局部变量。

import sys
import time

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import pyqtSlot, QThread
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QThread")
        self.resize(300, 400)
        self.widget = QWidget()
        self.setCentralWidget(self.widget)
        self.layout = QtWidgets.QVBoxLayout(self.widget)
        self.lineEdit1 = QtWidgets.QLineEdit(self.widget)
        self.lineEdit1.setObjectName("lineEdit1")
        self.pushButton1 = QtWidgets.QPushButton(self.widget)
        self.pushButton1.setObjectName("pushButton1")
        self.pushButton1.setText("Button 1")
        self.lineEdit2 = QtWidgets.QLineEdit(self.widget)
        self.lineEdit2.setObjectName("lineEdit2")
        self.pushButton2 = QtWidgets.QPushButton(self.widget)
        self.pushButton2.setObjectName("pushButton2")
        self.pushButton2.setText("Button 2")
        self.layout.addWidget(self.lineEdit1)
        self.layout.addWidget(self.pushButton1)
        self.layout.addWidget(self.lineEdit2)
        self.layout.addWidget(self.pushButton2)
        QtCore.QMetaObject.connectSlotsByName(self)

    @pyqtSlot()
    def on_pushButton1_clicked(self):
        self.thread1 = QThread1()
        self.thread1.start()

    @pyqtSlot()
    def on_pushButton2_clicked(self):
        self.thread2 = QThread2()
        self.thread2.start()


class QThread1(QThread):
    def __init__(self):
        super().__init__()

    def run(self):
        for i in range(100):
            print(i)
            time.sleep(1)


class QThread2(QThread):
    def __init__(self):
        super().__init__()

    def run(self):
        for i in range(100):
            print(100 - i)
            time.sleep(1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())

如果需要实现按下按钮后lineEdit同时显示。有两种方法:
(1)将lineEdit对象传给QThread,然后在run方法里设置文本。

import sys
import time

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import pyqtSlot, QThread
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QThread")
        self.resize(300, 400)
        self.widget = QWidget()
        self.setCentralWidget(self.widget)
        self.layout = QtWidgets.QVBoxLayout(self.widget)
        self.lineEdit1 = QtWidgets.QLineEdit(self.widget)
        self.lineEdit1.setObjectName("lineEdit1")
        self.pushButton1 = QtWidgets.QPushButton(self.widget)
        self.pushButton1.setObjectName("pushButton1")
        self.pushButton1.setText("Button 1")
        self.lineEdit2 = QtWidgets.QLineEdit(self.widget)
        self.lineEdit2.setObjectName("lineEdit2")
        self.pushButton2 = QtWidgets.QPushButton(self.widget)
        self.pushButton2.setObjectName("pushButton2")
        self.pushButton2.setText("Button 2")
        self.layout.addWidget(self.lineEdit1)
        self.layout.addWidget(self.pushButton1)
        self.layout.addWidget(self.lineEdit2)
        self.layout.addWidget(self.pushButton2)
        QtCore.QMetaObject.connectSlotsByName(self)

    @pyqtSlot()
    def on_pushButton1_clicked(self):
        self.thread1 = QThread1(self.lineEdit1)
        self.thread1.start()

    @pyqtSlot()
    def on_pushButton2_clicked(self):
        self.thread2 = QThread2(self.lineEdit2)
        self.thread2.start()


class QThread1(QThread):
    def __init__(self, lineEdit):
        super().__init__()
        self.lineEdit = lineEdit

    def run(self):
        for i in range(100):
            self.lineEdit.setText(str(i))
            print(i)
            time.sleep(1)


class QThread2(QThread):
    def __init__(self, lineEdit):
        super().__init__()
        self.lineEdit = lineEdit

    def run(self):
        for i in range(100):
            self.lineEdit.setText(str(100 -i))
            print(100 - i)
            time.sleep(1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())

(2)在QThread里定义信号,run方法里发射信号。信号和lineEdit的setText方法关联

import sys
import time

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import pyqtSlot, QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QThread")
        self.resize(300, 400)
        self.widget = QWidget()
        self.setCentralWidget(self.widget)
        self.layout = QtWidgets.QVBoxLayout(self.widget)
        self.lineEdit1 = QtWidgets.QLineEdit(self.widget)
        self.lineEdit1.setObjectName("lineEdit1")
        self.pushButton1 = QtWidgets.QPushButton(self.widget)
        self.pushButton1.setObjectName("pushButton1")
        self.pushButton1.setText("Button 1")
        self.lineEdit2 = QtWidgets.QLineEdit(self.widget)
        self.lineEdit2.setObjectName("lineEdit2")
        self.pushButton2 = QtWidgets.QPushButton(self.widget)
        self.pushButton2.setObjectName("pushButton2")
        self.pushButton2.setText("Button 2")
        self.layout.addWidget(self.lineEdit1)
        self.layout.addWidget(self.pushButton1)
        self.layout.addWidget(self.lineEdit2)
        self.layout.addWidget(self.pushButton2)
        QtCore.QMetaObject.connectSlotsByName(self)

    @pyqtSlot()
    def on_pushButton1_clicked(self):
        self.thread1 = QThread1()
        self.thread1.sg[str].connect(self.lineEdit1.setText)
        self.thread1.start()

    @pyqtSlot()
    def on_pushButton2_clicked(self):
        self.thread2 = QThread2()
        self.thread2.sg[str].connect(self.lineEdit2.setText)
        self.thread2.start()


class QThread1(QThread):
    sg = pyqtSignal(str)
    def __init__(self):
        super().__init__()

    def run(self):
        for i in range(100):
            self.sg[str].emit(str(i))
            print(i)
            time.sleep(1)


class QThread2(QThread):
    sg = pyqtSignal(str)
    def __init__(self):
        super().__init__()

    def run(self):
        for i in range(100):
            self.sg[str].emit(str(100 - i))
            print(100 - i)
            time.sleep(1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值