標籤:_for hid 其它 idg trigger 網路 計時器 參數 setup
訊號
訊號是用於介面自動變化的一個工具,原理是訊號綁定了一個函數,當訊號被觸發時函數即被調用
舉個例子
from PyQt5 import QtWidgets,QtCorefrom untitled import Ui_Formimport 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 sysfrom 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()View Code
多線程
假設我們的主介面有一個用於顯示時間的 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=0class 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()View Code
上述代碼增加了一個WorkerThread類。WorkerThread繼承自QThread類,重寫了其run()函數。可以認為,run()函數就是新的線程需要執行的代碼。在這裡就是要執行這個迴圈,然後發出計算完成的訊號。而在按鈕點擊的槽函數中,使用work()中的workThread.start()函數啟動一個線程(注意,這裡不是run()函數)。再次運行程式,你會發現現在介面已經不會被阻塞了。
PyQt5訊號、定時器及多線程