信号是用于界面自动变化的一个工具,原理是信号绑定了一个函数,当信号被触发时函数即被调用网络
举个例子多线程
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()。app
举个例子:秒表功能(每隔一秒刷新界面,直到按下中止按钮)ide
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()函数)。再次运行程序,你会发现如今界面已经不会被阻塞了。布局