第二次更新
说明
上一步已经将基本的串口操作完成,现在可以去肝界面逻辑了。
代码上传至 github仓库:访问请点击此处
创建逻辑代码的主体文件
# 创建类,继承工具生成的界面类
class Main_form_UI(QtWidgets.QMainWindow, QtWidgets.QWidget, Main_form.Ui_MainWindow):
def __init__(self, parent=None):
super(Main_form_UI, self).__init__(parent)
self.setupUi(self)
# 实例化
def mywindow():
mywindow = Main_form_UI()
mywindow.show()
return mywindow
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
myobj = mywindow()
sys.exit(app.exec_())
整理代码的流程图
线程分配
主线程
主线程的定时器
定时器处理
接收线程
发送线程
事件处理
自定义线程类
自定义一个线程类用于处理多个线程
import threading
from PyQt5.QtCore import QObject,pyqtSignal
class Runthread(QObject):
'''
定义一个线程类,实现了线程的阻塞和释放以及线程停止
适用于一直循环的线程
'''
#定义一个信号
sendmsg = pyqtSignal(object)
def __init__(self, run_func):
super(Runthread, self).__init__()
self.thread = threading.Thread(target=self.run)
self.__flag = threading.Event() # 用于暂停线程的标识
self.__flag.set() # 设置为True
self.__running = threading.Event() # 用于停止线程的标识
self.__running.set() # 将running设置为True
self.__run_func = run_func
def start(self):
self.thread.start()
def run(self):
while self.__running.isSet():
self.__flag.wait() # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回
self.__run_func(sendmsg=self.sendmsg)
def pause(self):
self.__flag.clear() # 设置为False, 让线程阻塞
def resume(self):
self.__flag.set() # 设置为True, 让线程停止阻塞
def stop(self):
self.__running.clear() # 设置为False
self.__flag.set() # 将线程从暂停状态恢复, 如何已经暂停的话
if __name__ == "__main__":
import time
def run1():
print("run1 sleep 1s.")
time.sleep(1)
t1 = Runthread(run1)
t1.start()
time.sleep(8)
t1.pause()
print("阻塞了")
time.sleep(10)
t1.resume()
print("解除了")
time.sleep(10)
t1.stop()
print("停止了")
time.sleep(10)
t1 = Runthread(run1)
t1.start()
time.sleep(10)
print("程序退出")
- 这里定义了一个类,用于对创建的线程进行管理,加入了线程阻塞和线程停止的方法,适用于需要一直循环的任务函数。
- 在类的初始化代码里接收一个函数参数,此函数为线程的执行函数。
def __init__(self, run_func):
# 。。。。。。
# 设置一个参数接收线程的处理函数
self.__run_func = run_func
- 由于使用的是PYQT5,这里在线程中定义一个信号,用于给主线程发送信号
sendmsg = pyqtSignal(object)
- 同时在定义线程运行函数时,需要加入此信号的参数,在线程类中调用时将信号传入。
self.__run_func(sendmsg=self.sendmsg)
点击连接按钮的处理
- 这里在点击连接按钮后,获取界面上的各个控件的设置信息,进行配置串口并打开串口。
- 串口打开以后,创建串口接收线程,串口发送线程,数据处理线程。
- 当断开串口时,相应的停止各个线程
def connecthandle(self):
# 点击连接按键后的操作
if self.ComTool_status['isConnect'] is False:
# 获取状态
self._get_current_com_status()
if self.ComTool_status['dev_name'] == '':
# 当前没有选中任何设备,直接弹窗报错
QtWidgets.QMessageBox.warning(self,'串口设备选择错误', '串口设备没有插入。', QtWidgets.QMessageBox.Ok)
return
# 打开串口
try:
self.com_dev.open(self.ComTool_status['dev_name'],
int(self.ComTool_status['baud_rate']),
int(self.ComTool_status['data_bits']),
self.ComTool_status['parity'],
int(self.ComTool_status['stop_bits']))
except:
QtWidgets.QMessageBox.warning(self,'串口设备错误', '串口设备被占用。', QtWidgets.QMessageBox.Ok)
return
# 停止串口扫描的定时器
self.scan_uart_timer.stop()
# 改变连接按键的显示文本
self.pushButton_connect.setText('断开')
# 设置连接状态
self.ComTool_status['isConnect'] = True
# 创建串口接收和发送的线程
self.thread_rx = Runthread.Runthread(self.com_dev.com_rxHandler)
self.thread_tx = Runthread.Runthread(self.com_dev.com_txHandler)
self.thread_rxData = Runthread.Runthread(self.rxDataHandler)
self.thread_rxData.sendmsg.connect(self.display) # 将接收数据处理的线程信号连接到此处
self.thread_rx.start()
self.thread_tx.start()
self.thread_rxData.start()
else:
self.thread_rx.stop()
self.thread_rx.stop()
self.thread_rxData.stop()
self.thread_rxData.sendmsg.disconnect(self.display)
# 关闭串口
self.com_dev.close()
# 设置定时器的间隔时间并启动定时器
self.scan_uart_timer.start(500)
self.pushButton_connect.setText('连接')
# 设置连接状态
self.ComTool_status['isConnect'] = False
接收数据处理线程
- 从接收队列中将队列读空,根据当前的HEX或者ASCII控件状态,来确定当前的显示。
- 将需要显示的字符串通过信号的方式发送给主线程
- 主线程中接收到信号事件,直接进行显示
def rxDataHandler(self,sendmsg = None):
# 从接收缓存中获取数据进行处理
rx_data = []
# 从接收缓存中读空数据
while not self.com_dev.rx_queue.empty():
rx_data.append(self.com_dev.rx_queue.get_nowait())
if len(rx_data) != 0:
if self.radioButton_rev_hex.isChecked():
display_str = ''
# 将接收到的数据按照hex格式显示
hex_rx_data = self.hex_handler.byte_to_hexString(rx_data)
# 将字符串追加到显示区
for str in hex_rx_data:
display_str += str+' '
sendmsg.emit(display_str) # 将数据发送到显示函数中进行显示
else:
# 将接收的数据以ascii字符串的形式保存
if self.comboBox_encode.currentText() == 'UTF-8':
utf8_rx_data = self.hex_handler.byte_to_utf8str(rx_data)
sendmsg.emit(utf8_rx_data) # 将数据发送到显示函数中进行显示
else:
time.sleep(0.08)
def display(self, msg):
self.plainTextEdit_rev.insertPlainText(msg)
self.plainTextEdit_rev.moveCursor(self.plainTextEdit_rev.textCursor().End)
至此接收初步完成。