• 1 多线程QThread
  • 1.1 方法列表
  • 2 多线程示例
  • 2.1 没有使用线程
  • 2.2 使用线程,线程有输出信号
  • 2.3 使用线程和线程锁,线程有输出信号
  • 2.4 使用线程,防止重复触发线程



1 多线程QThread

由于在PyQt5的GUI程序中只存在一个主线程,如果在主线程中进行非常耗时的操作,将会导致GUI界面卡死或者假死,这将十分影响程序的运行。因此后台进行耗时的操作,需要使用线程

1.1 方法列表

QThread的方法

说明

self=QThread()

创建线程

def run(self):

重写run方法定义线程的工作内容

self.start()

启动线程

self.sleep(n)

强制当前线程睡眠多少秒

self.started.connect(fun)

在开始执行run函数之前,从相关线程发射此信号

self.finished.connect(fun)

当程序完成run函数时,从相关线程发射此信号

2 多线程示例

2.1 没有使用线程

此例中没有使用线程,操作过程中非常容易卡死,如果不使用QApplication.processEvents(),文本框中也无法按正常时间显示内容

import sys
from PyQt5.QtWidgets import *
import time

class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.move(500, 400)
        self.setFixedSize(300, 300)
        vlayout = QVBoxLayout()
        self.setLayout(vlayout)

        text_edit = QTextEdit()
        text_edit.setReadOnly(True)
        vlayout.addWidget(text_edit)
        vlayout.addSpacing(10)
        num_button = QPushButton('12345')
        num_button.clicked.connect(lambda: self.numPrint(text_edit))
        vlayout.addWidget(num_button)

    def numPrint(self, text_edit):
        for num in '12345':
            # 休眠1s
            time.sleep(1)
            print(num)
            text_edit.append(num)
            # 在耗时的程序中保持UI刷新
            QApplication.processEvents()


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

python线程Qthread中断 qthread线程安全退出 python_pyqt5

2.2 使用线程,线程有输出信号

此例中使用线程,在线程中print,同时将num通过信号发送给控件。后台与UI独立运行,不会卡顿。
但是线程没有线程锁,多次点击按钮会创建多个独立线程,相互干扰。

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

class Thread_num(QThread):
    # 创建信号,发送str类型数据
    num_signal = pyqtSignal(str)
    def __init__(self):
        super().__init__()

    def run(self):
        for num in '12345':
            # 线程自带休眠方法
            self.sleep(1)
            print(num)
            # 发送信号,num是str类型数据
            self.num_signal.emit(num)


class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.move(500, 400)
        self.setFixedSize(300, 300)
        vlayout = QVBoxLayout()
        self.setLayout(vlayout)
        text_edit = QTextEdit()
        text_edit.setReadOnly(True)
        vlayout.addWidget(text_edit)
        vlayout.addSpacing(10)
        num_button = QPushButton('12345')
        num_button.clicked.connect(lambda: self.numPrint(text_edit))
        vlayout.addWidget(num_button)

    def numPrint(self, text_edit):
        # 创建线程
        self.thread = Thread_num()
        self.text_edit = text_edit
        # 连接信号
        self.thread.num_signal.connect(self.showEdit)
        # 线程启动
        self.thread.start()

    def showEdit(self, num):
        self.text_edit.append(num)


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

python线程Qthread中断 qthread线程安全退出 python_python_02

2.3 使用线程和线程锁,线程有输出信号

线程锁让多次点击的并发线程排队,当上一个线程完成后,下一个线程才开始进行

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

# 创建线程锁
qmut = QMutex()
class Thread_num(QThread):
    # 创建信号,发送str类型数据
    num_signal = pyqtSignal(str)
    def __init__(self):
        super().__init__()

    def run(self):
        # 锁住线程
        qmut.lock()
        for num in '12345':
            # 线程自带休眠方法
            self.sleep(1)
            print(num)
            # 发送信号,num是str类型数据
            self.num_signal.emit(num)
        # 解锁线程
        qmut.unlock()


class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.move(500, 400)
        self.setFixedSize(300, 300)
        vlayout = QVBoxLayout()
        self.setLayout(vlayout)

        text_edit = QTextEdit()
        text_edit.setReadOnly(True)
        vlayout.addWidget(text_edit)
        vlayout.addSpacing(10)
        num_button = QPushButton('12345')
        num_button.clicked.connect(lambda: self.numPrint(text_edit))
        vlayout.addWidget(num_button)

    def numPrint(self, text_edit):
        # 创建线程
        self.thread = Thread_num()
        self.text_edit = text_edit
        # 连接信号
        self.thread.num_signal.connect(self.showEdit)
        # 线程启动
        self.thread.start()

    def showEdit(self, num):
        self.text_edit.append(num)


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

python线程Qthread中断 qthread线程安全退出 python_thread_03

2.4 使用线程,防止重复触发线程

在线程开始时关闭按钮,线程结束后Enable按钮

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

class Thread_num(QThread):
    # 创建信号,发送str类型数据
    num_signal = pyqtSignal(str)

    def __init__(self):
        super().__init__()

    def run(self):
        for num in '12345':
            # 线程自带休眠方法
            self.sleep(1)
            print(num)
            # 发送信号,num是str类型数据
            self.num_signal.emit(num)


class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.move(500, 400)
        self.setFixedSize(300, 300)
        vlayout = QVBoxLayout()
        self.setLayout(vlayout)

        text_edit = QTextEdit()
        text_edit.setReadOnly(True)
        vlayout.addWidget(text_edit)
        vlayout.addSpacing(10)
        num_button = QPushButton('12345')
        num_button.clicked.connect(lambda: self.numPrint(num_button, text_edit))
        vlayout.addWidget(num_button)

    def numPrint(self, num_button, text_edit):
        self.num_button = num_button
        self.num_button.setEnabled(False)
        # 创建线程
        self.thread = Thread_num()
        self.text_edit = text_edit
        # 连接信号
        self.thread.num_signal.connect(self.showEdit)
        # 连接结束信号
        self.thread.finished.connect(self.resetButton)
        # 线程启动
        self.thread.start()

    def showEdit(self, num):
        self.text_edit.append(num)

    def resetButton(self):
        self.num_button.setEnabled(True)


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

python线程Qthread中断 qthread线程安全退出 python_多线程_04