PyQt5——多线程

多线程

多线程技术设计三种方法,其中一种是使用计数器模块QTimer,一种是使用多线程模块QThread,还有一种使用事件处理的功能。

QTimer

如果要在应用程序汇总周期性地进行某项操作,比如周期性地检测主机的CPU,则需要用到QTimer(定时器)。QTimer类提供了重复和单次的定时器。要使用定时器,则需要先创建一个QTImer实例,将其timeout信号连接到相应的槽,并调用start。

# -*- coding: utf-8 -*-

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

class WinForm(QWidget):
    def __init__(self, parent = None):
        super(WinForm, self).__init__(parent)
        self.setWindowTitle("QTimer Demo")
        self.listFile =QListWidget()
        self.label = QLabel('显示当前时间')
        self.startBtn = QPushButton("开始")
        self.endBtn = QPushButton("结束")
        layout = QGridLayout(self)
        # 初始化一个定时器
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.showTime)

        layout.addWidget(self.label,0,0,1,2)
        layout.addWidget(self.startBtn,1,0)
        layout.addWidget(self.endBtn,1,1)

        self.startBtn.clicked.connect(self.startTimer)
        self.endBtn.clicked.connect(self.endTimer)
        self.setLayout(layout)
    def showTime(self):
        time = QDateTime.currentDateTime()
        timeDisplay = time.toString("yyyy-MM-dd hh:mm:ss dddd")
        self.label.setText(timeDisplay)
    def startTimer(self):
        # 设置时间间隔并启动定时器
        self.timer.start(1000)
        self.startBtn.setEnabled(False)
        self.endBtn.setEnabled(True)
    def endTimer(self):
        self.timer.stop()
        self.startBtn.setEnabled(True)
        self.endBtn.setEnabled(False)

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

在这里插入图片描述
在这里插入图片描述

演示弹出一个窗口,然后这个窗口10s后消失

# -*- coding: utf-8 -*-

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

if __name__ == '__main__':
    app = QApplication(sys.argv)
    label = QLabel("<font color=red size=128><b>Hello PyQT, 窗口10后消失</b></font>")
    label.setWindowFlags(Qt.SplashScreen| Qt.FramelessWindowHint)
    label.show()
    QTimer.singleShot(10000, app.quit)
    sys.exit(app.exec_())

在这里插入图片描述

QThread

QThread是Qt线程中最核心的底层类

使用线程时可以直接调用Thread实例,调用其start()函数即可启动线程,线程启动后,会自动调用其实现的run方法,该方法就先线程的执行函数

业务的线程任务就写在run函数中,当run退出之后线程就结束了。QThread有strarted和finished信号,可以为这两个信号指定槽函数,在线程启动和结束后指定一段代码进行资源的初始化和释放操作。

常用的方法

  • start
  • wait
  • sleep
# -*- coding: utf-8 -*-

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

class MainWidget(QWidget):
    def __init__(self, parent =None):
        super(MainWidget, self).__init__(parent)
        self.setWindowTitle("QThread 例子")
        self.thread = Worker()
        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)
        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)

class Worker(QThread):
    sinout=  pyqtSignal(str)
    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)
            self.num += 1
            # 发射信号
            self.sinout.emit(file_str)
            # 线程休眠2秒
            self.sleep(2)
if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = MainWidget()
    demo.show()
    sys.exit(app.exec_())

在这里插入图片描述

虽然界面的数据显示和数据读写的分了,但是如果数据的读写非常的耗费时间,则会造成界面卡死

# -*- coding: utf-8 -*-

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

global sec
sec =0

def setTime():
    global sec
    sec += 1
    lcdNumber.display(sec)
def work():
    timer.start(1000)
    for i in  range(200000000):
        pass
    timer.stop()
if __name__ == "__main__":
    app = QApplication(sys.argv)
    top = QWidget()
    top.resize(300,120)

    layout = QVBoxLayout(top)
    lcdNumber = QLCDNumber()
    layout.addWidget(lcdNumber)
    button = QPushButton("测试")
    layout.addWidget(button)
    timer = QTimer()
    timer.timeout.connect(setTime)
    button.clicked.connect(work)
    top.show()
    sys.exit(app.exec_())

在这里插入图片描述

我们用循环来模拟非常耗时的工作,当点击测试按钮之后,程序界面会直接停止响应,知道循环结束才重新更新,计时器始终显示为0。

在PyQt中所有的窗口都在UI的主线程中,这个线程执行耗时的操作就会阻塞UI线程,从而使窗口停止响应。如果窗口长时间没有响应就会影响用户体验。为了避免出现这种问题,要使用QThread开启一个新的线程,从而在这个线程完成耗时的操作。

# -*- coding: utf-8 -*-

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

global sec
sec = 0
class WorkThread(QThread):
    trigger = pyqtSignal()
    def __init__(self):
        super(WorkThread, self).__init__()
    def run(self):
        for i in range(2000000000):
            pass
        self.trigger.emit()

def countTime():
    global sec
    sec += 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)
    layout = QVBoxLayout(top)
    lcdNumber = QLCDNumber()
    layout.addWidget(lcdNumber)
    button = QPushButton("测试")
    layout.addWidget(button)

    timer = QTimer()
    workThread = WorkThread()
    button.clicked.connect(work)
    timer.timeout.connect(countTime)
    top.show()
    sys.exit(app.exec_())

在这里插入图片描述

WorkThread继承来自QThread类,重写其run函数,run()函数就是新的线程需要执行的,在run函数中就要执行一个循环,然后发射计算完成的信号。

事件处理

PyQt为事件处理体用了两种机制:高级的信号与槽机制,以及低级的事件处理程序。我们介绍低级的事件处理程序,即processEvents()函数的使用方法,他们的作用就是处理时间,简单的说就是刷新页面。

对于执行很耗时的程序来说,由于PyQt需要等待程序执行完毕只有才能进行下一步,在页面上表现为卡顿。

# -*- coding: utf-8 -*-

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

class WinForm(QWidget):
    def __init__(self):
        super(WinForm, self).__init__()
        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.btnStart.clicked.connect(self.slotAdd)
        self.setLayout(layout)
    def slotAdd(self):
        for n in range(10):
            str_n = "File index {0}".format(n)
            self.listFile.addItem(str_n)
            QApplication.processEvents()
            time.sleep(1)

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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值