写在前面
前言
-
自定义波特率
-
自动换行
-
RTS 控
-
DTR 控
-
Hex 发送和接收
开发必备工具
-
Python 3.8 环境
-
PyCharm 2020.1.1 x64
-
QT Designer 5.2
对于如何选择一款开发工具,我也是挑了蛮久的,还是选择熟悉强大的IDEA系列软件,再配合QT Designer使用起来,非常Nice。下面分享下,我的快捷键,能使你的开发效率加倍。
纯技术公众号
1
PyCharm 如何集成 QT Designer
1.1 UI代码 –>可视化
QT Designer 为我们提供了将UI代码可视化的实现,打开下面终端并配置在IDE就可以了!
指令终端
Python38-32Libsite-packagespyqt5_toolsQtbindesigner.exe
1.2 可视化 –>UI代码
同样地,QT Designer 为我们提供了将可视化转UI代码的实现!
指令终端
终端:Python38-32Libsite-packagespyqt5_toolsQtbindesigner.exe
参数:-m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
1.3 打包成 exe 软件
QT Designer 为我们提供了将整个工程打包成执行文件:
指令终端
终端:Python38-32Libsite-packagespyqt5_toolsQtbindesigner.exe
参数:-F -w $FileName$
1.4 如何自定义控件
在开发过程中,欲要在QT Designer实现自定义控件如何做呢?看我操作过程!
那么问题来了,如何移除自定义控件呢?
代码结构说明
3.1
串口通讯应用层封装
-
包括串口异常中断处理;
-
提供上层应用接口有配置、发送和接收;
-
子线程和信号槽应用实现无缝读取串口通讯接收到的数据给上位机;
class UartRecieveThread(QThread):
def __init__(self, run):
super(UartRecieveThread, self).__init__()
self.runfun = run
def run(self):
self.runfun()
class UartSerial(QObject):
# 定义一个信号变量,1个参数
signalRecieve = pyqtSignal(object)
CODE_RECIEVE, CODE_DISCONNECT = 0, 1
def __init__(self):
super(UartSerial, self).__init__()
self.mThread = UartRecieveThread(self.data_receive) # 创建线程
self.mSerial = serial.Serial()
self.data_num_received = 0
def init(self, _port="/dev/ttyUSB0", _baudrate=115200, _bytesize=8, _stopbits="N", _parity=serial.PARITY_NONE):
self.mSerial.port = _port
self.mSerial.baudrate = _baudrate
self.mSerial.bytesize = _bytesize
self.mSerial.stopbits = _stopbits
self.mSerial.parity = _parity
self.data_num_received = 0
def is_port_open(self, _port_name, _baudrate):
try:
self.mSerial.port = _port_name
self.mSerial.baudrate = _baudrate
return not self.mSerial.isOpen()
except Exception:
return False
# 关闭串口
def port_close(self, _port_name, _baudrate):
self.mSerial.port = _port_name
self.mSerial.baudrate = _baudrate
try:
self.mSerial.close()
except:
return False
self.mThread.quit()
return True
# 串口检测
def get_all_port(self):
# 检测所有存在的串口,将信息存储在字典中
self.port_list_name = []
port_list = list(serial.tools.list_ports.comports())
i = 0
if len(port_list) <= 0:
return []
else:
for port in port_list:
i = i + 1
self.port_list_name.append(port[0])
return self.port_list_name
# 打开串口
def try_port_open(self, _port, _baudrate=115200):
self.mSerial.port = _port
self.mSerial.baudrate = _baudrate
try:
self.mSerial.open()
except:
return False
if not self.mThread.isRunning():
self.mThread.start()
return True
def set_rts(self, IsTrue):
self.mSerial.setRTS(IsTrue)
def set_dts(self, IsTrue):
self.mSerial.setDTR(IsTrue)
def get_rts(self):
return self.mSerial.rts
def get_dts(self):
return self.mSerial.dtr
def set_bytesize(self, _bytesize):
self.mSerial.bytesize = _bytesize
def set_parity(self, _parity):
self.mSerial.parity = _parity
def set_stopbits(self, _stopbits):
self.mSerial.stopbits = _stopbits
# 接收数据
def data_receive(self):
while True:
data = {}
try:
num = self.mSerial.inWaiting()
except:
self.mSerial.close()
data['code'] = self.CODE_DISCONNECT
data['data'] = 0
data['length'] = 0
self.signalRecieve.emit(data)
return None
if num > 0:
if self.mSerial.isOpen():
buff = self.mSerial.read(num)
data['code'] = self.CODE_RECIEVE
data['data'] = buff
data['length'] = len(buff)
self.signalRecieve.emit(data)
time.sleep(0.1)
# 设置回调函数
def setCallBack(self, funtion):
self.signalRecieve.connect(funtion)
# send data
def send_data(self, buff="", isHexSend=False, _port="", _baudrate=115200):
if buff != "":
# 非空字符串
if isHexSend:
# hex发送
buff = buff.strip()
send_list = []
while buff != '':
try:
num = int(buff[0:2], 16)
except ValueError:
return None
buff = buff[2:].strip()
send_list.append(num)
buff = bytes(send_list)
num = self.mSerial.write(buff)
3.2
自定义的实现
在实现某些功能时候,发现自带的控件无法满足需求时候,我们只能自定义控件,我重写了几个控件:
1 、重写 QComboBox
为了实现能自定义波特率,比如用户输入74880;
class MyQComBox(QComboBox):
popupAboutToBeShown = pyqtSignal() # 创建一个信号
def showPopup(self): # 重写showPopup函数
super(MyQComBox, self).showPopup()
self.popupAboutToBeShown.emit() # 发送信号
2 、重写 QWidget
为了能够全局监听键盘按键,实现一键清空数据接受栏;
class MineWidget(QWidget):
# 定义一个信号变量,1个参数
signalMineWidget = pyqtSignal(object)
def set_connect_key_press(self, fun):
self.signalMineWidget.connect(fun)
# 检测键盘回车按键
def keyPressEvent(self, event):
self.signalMineWidget.emit(event.key())
def mousePressEvent(self, event):
self.signalMineWidget.emit(event.button())
3 、接受数据并显示
这里要特别说明的是,在解码时候,特要指明 utf-8
编码,以及带上 ignore
表示接受解码失败异常;
def at_callback_handler(obj):
if obj['code'] == 1:
if ui.bt_open_off_port.text() != '打开串口':
QMessageBox.critical(MainWindow, '错误信息', '串口异常断开!')
# 面板可操作
checkoutPortStatus(True)
ui.bt_open_off_port.setText('打开串口')
refreshPort()
else:
buff = (obj['data'])
now_time = datetime.now() # 获取当前时间
# new_time = now_time.strftime('[%H:%M:%S]') # 打印需要的信息,依次是年月日,时分秒,注意字母大小写
if ui.checkBox_show_hex.checkState():
out_s = ''
for i in range(0, len(buff)):
out_s = out_s + '{:02X}'.format(buff[i]) + ' '
if ui.checkBox_show_add_ctrl.checkState():
ui.textBrowserShow.append(out_s)
else:
ui.textBrowserShow.insertPlainText(out_s)
ui.textBrowserShow.moveCursor(QTextCursor.End)
else:
try:
if ui.checkBox_show_add_ctrl.checkState():
ui.textBrowserShow.append(buff.decode('utf-8', 'ignore'))
else:
ui.textBrowserShow.insertPlainText(buff.decode('utf-8', 'ignore'))
ui.textBrowserShow.moveCursor(QTextCursor.End)
except:
# 乱码显示
pass
后面
-推荐阅读-
点击文字即可阅读全文
☞ 2019年年终总结:平凡的我,仍然在平淡的生活里打拼,寻找未来的曙光。
☞ 2020年终总结:跌跌撞撞,沉下心来,不卑不燥,欲戴王冠,必承其重。
☞ 基于SpringBoot私有服务器对接阿里云物联网服务器,实现M2M数据流。
☞ 开源架构XClouds专题|私有云之天猫精灵等平台对接Oauth2.0协议详解!
☞ esp32蓝牙配网高度封装,集成简单、使用简单,提高开发效率!
☞ 重磅开源,微信小程序ble蓝牙配网乐鑫esp32,开源奉献物联网;
部分图片摘取网络 侵删
原文始发于微信公众号(徐宏blog):PyQT5上位机开发,如何自定义控件,入门做一个上位电脑串口调试软件,全部开源。