PyQt5信号、定时器及多线程

信号

  信号是用于界面自动变化的一个工具,原理是信号绑定了一个函数,当信号被触发时函数即被调用

举个例子

from PyQt5 import QtWidgets,QtCore
from untitled import Ui_Form
import  time

class MyWindow(QtWidgets.QWidget,Ui_Form):
    _signal=QtCore.pyqtSignal(str) #定义信号,定义参数为str类型
    def __init__(self):
        super(MyWindow,self).__init__()
        self.setupUi(self)
        self.myButton.clicked.connect(self.myPrint)# 按下按钮执行myPrint
        self._signal.connect(self.mySignal) #将信号连接到函数mySignal

    def myPrint(self):
        self.tb.setText("")
        self.tb.append("正在打印,请稍候")
        self._signal.emit("打印结束了吗")# 信号被触发
    def mySignal(self,string):
        print(string)
        self.tb.append("打印结束")

if __name__=="__main__":
    # 以下代码作用为展现ui界面
    import sys  

    app=QtWidgets.QApplication(sys.argv)
    myshow=MyWindow()
    myshow.show()
    sys.exit(app.exec_())  

定时器

  定时器的作用是让某个函数定时的启动,原理是创建一个QTimer对象,将其timeout信号连接到相应的槽(绑定函数名),并调用start(),定时器会以恒定的间隔发出timeout信号,直到调用stop()。

举个例子:秒表功能(每隔一秒刷新界面,直到按下停止按钮)

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

class WinTimer(QWidget):
    def __init__(self,parent=None):
        super(WinTimer,self).__init__(parent)

        ###界面显示
        self.label_start=QLabel("开始时间:")
        self.label_curr=QLabel("当前时间:")
        self.label_total=QLabel("时间总计:")
        self.startBtn=QPushButton("开始")
        self.endBtn=QPushButton("停止")
        self.endBtn.setEnabled(False)

        ##时间变量
        self.start_time=QDateTime.currentDateTime()
        self.stop_time = QDateTime.currentDateTime()

        ###定时器
        self.timer=QTimer()
        self.timer.timeout.connect(self.currTime)

        layout=QGridLayout()
        layout.addWidget(self.label_start,0,0,1,2)
        layout.addWidget(self.label_curr, 1,0,1,2)
        layout.addWidget(self.label_total, 2,0,1,2)
        layout.addWidget(self.startBtn, 3, 0)
        layout.addWidget(self.endBtn, 3, 1)
        self.setLayout(layout)

        self.startBtn.clicked.connect(self.startTimer)
        self.endBtn.clicked.connect(self.endTimer)

        self.setWindowTitle("QTimer")
        self.resize(250,100)

    def currTime(self):
        self.stop_time=QDateTime.currentDateTime()
        str_time = self.stop_time.toString("yyyy-MM-dd hh:mm:ss dddd")
        self.label_curr.setText("当前时间:"+str_time)

        str_start = self.start_time.toString("yyyy-MM-dd hh:mm:ss")
        str_curr = self.stop_time.toString("yyyy-MM-dd hh:mm:ss")
        startTime = datetime.strptime(str_start, "%Y-%m-%d %H:%M:%S")
        endTime = datetime.strptime(str_curr, "%Y-%m-%d %H:%M:%S")
        seconds = (endTime - startTime).seconds
        self.label_total.setText("时间总计:" + str(seconds)+"s")

    def startTimer(self):
        self.start_time = QDateTime.currentDateTime()
        str_time = self.start_time.toString("yyyy-MM-dd hh:mm:ss dddd")
        self.label_start.setText("开始时间:" + str_time)
        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=WinTimer()
    form.show()

多线程

  假设我们的主界面有一个用于显示时间的 LCD 数字面板和一个用于启动任务的按钮。程序的目的是用户点击按钮,开始一个非常耗时的运算(程序中我们以一个 2000000000 次的循环来替代这个非常耗时的工作,在真实的程序中,这可能是一个网络访问,可能是需要复制一个很大的文件或者其它任务),同时 LCD 开始显示逝去的毫秒数。毫秒数通过一个计时器QTimer进行更新。计算完成后,计时器停止。这是一个很简单的应用,也看不出有任何问题。但是当我们开始运行程序时,问题就来了:点击按钮之后,程序界面直接停止响应,直到循环结束才开始重新更新,于是计时器使用显示0。

  这是因为 Qt 中所有界面都是在 UI 线程中(也被称为主线程,就是执行了QApplication::exec()的线程),在这个线程中执行耗时的操作(比如那个循环),就会阻塞 UI 线程,从而让界面停止响应。界面停止响应,用户体验自然不好,不过更严重的是,有些窗口管理程序会检测到你的程序已经失去响应,可能会建议用户强制停止程序,这样一来程序可能就此终止,任务再也无法完成。所以,为了避免这一问题,我们要使用 QThread 开启一个新的线程:

# coding=utf-8
__author__ = ‘a359680405‘
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
global sec
sec=0
class WorkThread(QThread):
  trigger = pyqtSignal()
  def __int__(self):
    super(WorkThread,self).__init__() 

  def run(self):
    for i in range(203300030):
      pass
    self.trigger.emit()     #循环完毕后发出信号 

def countTime():
  global sec
  sec+=1
  lcdNumber.display(sec)     #LED显示数字+1 

def work():
  timer.start(1000)        #计时器每秒计数
  workThread.start()       #计时开始
  workThread.trigger.connect(timeStop)  #当获得循环完毕的信号时,停止计数 

def timeStop():
  timer.stop()
  print("运行结束用时",lcdNumber.value())
  global sec
  sec=0
app=QApplication([])
top=QWidget()
layout=QVBoxLayout(top)       #垂直布局类QVBoxLayout;
lcdNumber=QLCDNumber()       #加个显示屏
layout.addWidget(lcdNumber)
button=QPushButton("测试")
layout.addWidget(button)
timer=QTimer()
workThread=WorkThread()
button.clicked.connect(work)
timer.timeout.connect(countTime)   #每次计时结束,触发setTime
top.show()
app.exec()

  上述代码增加了一个WorkerThread类。WorkerThread继承自QThread类,重写了其run()函数。可以认为,run()函数就是新的线程需要执行的代码。在这里就是要执行这个循环,然后发出计算完成的信号。而在按钮点击的槽函数中,使用work()中的workThread.start()函数启动一个线程(注意,这里不是run()函数)。再次运行程序,你会发现现在界面已经不会被阻塞了。

原文地址:https://www.cnblogs.com/zhuminghui/p/9507982.html

时间: 2024-10-24 03:36:45

PyQt5信号、定时器及多线程的相关文章

定时器在多线程中的使用

在多线程中使用定时器必须开启Runloop,因为只有开启Runloop保持现成为活动状态,才能保持定时器不断执行 - (void)viewDidLoad { [super viewDidLoad]; [self performSelectorInBackground:@selector(testMultiThread) withObject:nil]; } - (void) testMultiThread { NSAutoreleasePool * pool = [[NSAutoreleaseP

C#多线程学习之(五)使用定时器进行多线程的自动管理

本文实例讲述了C#多线程学习之使用定时器进行多线程的自动管理.分享给大家供大家参考.具体分析如下: Timer类:设置一个定时器,定时执行用户指定的函数. 定时器启动后,系统将自动建立一个新的线程,执行用户指定的函数. 初始化一个Timer对象: ? 1 Timer timer = new Timer(timerDelegate, s,1000, 1000); 第一个参数:指定了TimerCallback 委托,表示要执行的方法:第二个参数:一个包含回调方法要使用的信息的对象,或者为空引用:第三

PyQt5快速入门(二)PyQt5信号槽机制

PyQt5快速入门(二)PyQt5信号槽机制 一.信号槽机制简介 1.信号槽简介 信号槽是Qt的核心机制,也是PyQt编程中对象进行通信的机制.在Qt中,QObject对象和PyQt中所有继承自QWidget的控件都支持信号槽机制.当信号发射时,连接的槽函数会自动执行.在PyQt5中,信号与槽函数通过object.signal.connect()方法进行连接.信号槽特点如下:(1)一个信号可以连接多个槽(2)一个信号可以连接另一个信号(3)信号参数可以是任意Python类型(4)一个槽可以监听多

PyQt5信号与槽详解

1.信号与槽函数基础'''信号与槽函数基础,信号是一个事件,发射信号之后槽函数就会执行'''from PyQt5.QtWidgets import *import sys class signal(QWidget): def __init__(self): super(signal,self).__init__() self.initUI() #编辑控件及其关联的信号 def initUI(self): self.resize(300,200) self.setWindowTitle("信号与槽

PyQt5信号-槽机制

signal -> emit -> slot signal.connect(slot) signal.disconnect(slot) 信号 (singal) 可以连接无数多个槽 (slot),或者没有连接槽也没有问题,信号也可以连接其他的信号. 连接的基本语句形式如下: who.singal.connect(slot) 信号是 QObject 的一个属性.只有通过 connect方法连接起来,信号-槽机制就建立起来了.类似的信号还有 disconnect 方法和emit 方法. discon

Java中基本知识梳理【定时器实现多线程】-----2015年3月15日

Timer介绍: (1)基本方法: public Timer():创建一个新计时器.相关的线程不 作为守护程序运行. public void schedule(TimerTask task, long delay, long period) 安排指定的任务从指定的延迟后开始进行重复的固定延迟执行.以近似固定的时间间隔(由指定的周期分隔)进行后续执行. public void schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务.如果此时间已过去,

QTcpSocket服务器 定时器,多线程结合

QTcpsocket 写服务器程序时,需要定时向客户端发送监控数据,同时需要响应客户端请求. 问题是: QTcpSocket 只能在同一个线程中使用,定时器会在主线程中运行 解决方案:在定时器中发送信号给封装的客户端数据处理socket,并在线程中将该信号与socket中的操作相连接. //clientsocket.h #ifndef CLIENTSOCKET_H #define CLIENTSOCKET_H #include <QTcpSocket> #include <QTimer&

定时器非多线程

本文由 代码助手软件 整理发布 内容与本软件无关 更惬意的读.更舒心的写.更轻松的发布 首先,要说明的是:定时器使用感觉像是一个线程,但其实并不是多线程. 他是通过消息触发实现的,通过SetTimer函数设定定时器后,在规定的时间内向消息队列中加入WM_TIMER来触发事件,并且只有该消息返回后才处理下个消息. 定时器是系统消息,如同左键按下消息一样,所以需要添加此定时器消息 ON_WM_TIMER()     afx_msg void OnTimer(UINT nIDEvent); void 

PyQt5 信号和槽

信号发出,连接的槽函数即可运行. 通用表达式:widget.signal.connect(slot) import sys from PyQt5.QtWidgets import QApplication, QWidget, QPushButton class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.resize(600,400) self.setW