PyQT多執行緒串列埠 QtDesigner
這篇部落格主要記錄一下PyQT多執行緒串列埠的主要程式碼分析,文末會有工程的原始碼檔案
首先,從PyCharm啟動QtDesigner
之前給客戶做的上位機,保密起見,刪減了大部分的框圖構件,但不影響本篇串列埠教程
QtDesigner介面如下:
忽略 新增資料以及表格資料顯示,這裡用不到
著重講一下類的構成
新建一個串列埠類SerialThread,繼承自QtCore.QThread,實現全部的串列埠收發功能
class SerialThread(QtCore.QThread):
dataReadoutSignal = pyqtSignal(str)
def __init__(self, parent = None, portName = 'COM3', baudrate = 9600, parity = 'N', bytesize = 8, stopbits = 1, timeout = None):
super(SerialThread, self).__init__(parent)
self.m_serialPort = serial.Serial()
self.m_serialPort.port = portName
self.m_serialPort.baudrate = baudrate
self.m_serialPort.parity = parity
self.m_serialPort.bytesize = bytesize
self.m_serialPort.stopbits = stopbits
self.m_serialPort.timeout = timeout
self.OpenScom()
def OpenScom(self):
try:
self.m_serialPort.open()
self.m_serialPort.setRTS(True)
self.m_serialPort.setDTR(True)
except Exception as ex:
print(ex)
return ex
def ScomSendOneData(self,datain):
if isinstance(datain,int):
listTemp = []
listTemp.append(datain)
d = bytes(listTemp)
self.m_serialPort.write(d)
else :
if isinstance(datain,str):
d = datain.encode('utf-8')
self.m_serialPort.write(d)
def ScomGetintData(self):
n = self.m_serialPort.inWaiting()
if n:
data = self.m_serialPort.read(n).hex()
#writefile
print(data)
def ScomGetstrData(self):
if self.m_serialPort.is_open:
n = self.m_serialPort.inWaiting()
if n > 0:
data = self.m_serialPort.read(n).decode('GB2312',errors='ignore')
return data
def run(self):
cnt = 50
while cnt <= 3000:
sendstr = str(cnt)
if len(sendstr) == 2:
sendstr = '00' + sendstr
else:
if len(sendstr) == 3:
sendstr = '0' + sendstr
self.ScomSendOneData('SET' + sendstr + 'V')
cnt = cnt + 5
print('此時設定電壓為:' + sendstr + 'V')
time.sleep(2)
函式功能見名知意,此處不表。這裡主要講一下run函式,run函式實現了一次迴圈,50到3000步進取5,傳送內容是SET0050V到SET3000V,當然,我這樣做是業務需求,如果並不需要這個功能,run函式可以寫成
def run(self):
while true:
time.sleep(2)
介面我們用QtDesigner製作的ui檔案通過pyUIC生成py檔案
生成的程式碼如下(太長,只留前幾行)
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'CashUpdateUI11v.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_cash(object):
def setupUi(self, cash):
**
**
**
此時,新建一個類MyWindow,繼承QMainWindow和Ui_cash,並在類內部,建立SerialThread成員
總體程式碼如下:
class MyWindow(QMainWindow,Ui_cash):
def __init__(self):
super(MyWindow,self).__init__()
self.scomList = []
self.threadList = []
self.setupUi(self)
self.actionOpen.triggered.connect(self.openMsg)
self.actionSave.triggered.connect(self.saveMsg)
self.pushButton.clicked.connect(self.ScomAutoFind)
self.addDataButton.clicked.connect(self.getRHandT)
self.tableWidget.setColumnCount(5)
self.tableWidget.setRowCount(1)
self.tableWidget.setHorizontalHeaderLabels(['11', '22', '33', '44', '55'])
self.tableRowCnt = 0
self.tableColumnCnt = 0
self.ThreadComID = 0
self.addDatasignal = pyqtSignal(str)
self.datadict = {'RHldy':0,'Tldy':0,'meaRT':0,'voltport':0}
def getMCUdata(self):
if self.ThreadComID == 0:
self.showMsgbox('請先連線串列埠')
else:
self.ThreadComID.ScomSendOneData(' 5501AA')
time.sleep(0.1)
strt = self.ThreadComID.ScomGetstrData()
if strt is None:
self.showMsgbox('請將串列埠線連線到電路板')
return None
print(strt)
self.datadict['voltport'] = strt[4:-3] + '.' + strt[-3:-2]
self.ThreadComID.ScomSendOneData(' 5502AA')
time.sleep(0.1)
strt = self.ThreadComID.ScomGetstrData()
if strt is None:
self.showMsgbox('請將串列埠線連線到電路板')
return None
print(strt)
self.datadict['meaRT'] = strt[4:-4] + '.' + strt[-4:-2]
return 1
def insertTableNewLine(self):
self.tableWidget.setItem(self.tableRowCnt, 0, QTableWidgetItem(self.datadict['RHldy']))
self.tableWidget.setItem(self.tableRowCnt, 1, QTableWidgetItem(self.datadict['Tldy']))
self.tableWidget.setItem(self.tableRowCnt, 2, QTableWidgetItem(self.datadict['meaRT']))
self.tableWidget.setItem(self.tableRowCnt, 3, QTableWidgetItem(self.datadict['voltport']))
self.tableWidget.setItem(self.tableRowCnt, 4, QTableWidgetItem(str(datetime.date.today())+' '+str(datetime.datetime.today().hour)+':'+str(datetime.datetime.today().minute)))
self.tableRowCnt += 1
self.tableWidget.insertRow(self.tableRowCnt)
def openMsg(self):
file,ok = QFileDialog.getOpenFileName(self,"開啟記錄表","C:/",".txt")
def getRHandT(self):
if self.ThreadComID == 0:
self.showMsgbox('請先連線串列埠')
else:
data,ok = QInputDialog.getText(self, "露點儀資料", "按如下格式記錄:\n RH空格T\n示例:\n RH(0~100):66.6\n T(0~200):9.8\n 輸入:66.6 9.8", QLineEdit.Normal, "66.6 9.8" )
if ok == True:
data = re.findall('^[0-9]+\.[0-9]+\s+[0-9]+\.[0-9]+$', data.rstrip())
if len(data) == 0:
self.showMsgbox('資料格式有誤,重新錄入')
else:
data = data[0].split()
print(data)
self.datadict['RHldy'] = data[0]
self.datadict['Tldy'] = data[1]
if self.getMCUdata() is None:
return None
print(self.datadict)
self.insertTableNewLine()
else:
self.showMsgbox('請重新錄入資料')
def showMsgbox(self,strtoshow):
QMessageBox.warning(self,'提示',strtoshow,QMessageBox.Ok)
def saveMsg(self):
file,ok = QFileDialog.getSaveFileName(self,"儲存記錄表","C:/",".txt")
def ScomAutoFind(self):
self.pushButton.setDisabled(True)
self.scomList = list(serial.tools.list_ports.comports())
if len(self.scomList) <= 0:
self.showMsgbox('未發現串列埠,請檢查線纜連線')
self.pushButton.setDisabled(False)
else:
comNum = len(self.scomList)
print(str(comNum) + 'Scom is found')
while comNum:
comNum = comNum - 1
if "USB" in str(self.scomList[comNum]):
self.ThreadComID = SerialThread(portName=self.scomList[comNum][0])
self.ThreadComID.start()
self.graphicsView.setStyleSheet("background-color: rgb(0, 255, 0);")
print(str(self.scomList[comNum]) + ' is added')
由於我用的是RS232轉USB接入電腦,裝置名稱是USB-SERIAL CH340,當然還有其他RS232轉USB晶片,如PL2303等。我這裡就單獨檢查USB是否在裝置名稱中,沒有檢查全名,這裡要根據實際需求變動
最後就是main了,沒什麼特別
if __name__ == "__main__":
app = QApplication(sys.argv)
myshow = MyWindow()
myshow.show()
print('程式終止')
sys.exit(app.exec_())
看一下實際執行效果:
實際執行,(忽略 新增資料 與 資料記錄表….)
點選connect後,
當然點選新增資料也是沒問題的哈
奉上全部工程檔案,連線如下:
https://download.csdn.net/download/ysgjiangsu/10324162
時間原因寫的比較粗糙,各位多包涵,以後業務多偏向C++QT,後續會多出相關文章