PyQt6 检测串口设备热插拔的方法

发布时间:2026/11/5 9:11:02

PyQt6 检测串口设备热插拔的方法 PyQt6 检测串口设备热插拔的方法一、PyQt6 检测串口设备热插拔的方法1、 引言2、核心思路与原理3、环境准备与依赖安装4、 代码实现热插拔检测器类5、 集成到 PyQt6 主界面6、进阶优化与平台特定方法6.1、 减少轮询开销6.2、 Windows 事件驱动方法可选6.3、 Linux/macOS 目录监控方法可选7、总结二、代码示例1、定时器扫描一、PyQt6 检测串口设备热插拔的方法1、 引言在嵌入式开发、工业控制或物联网应用中经常需要通过串口与外部设备通信。一个常见的需求是当用户插入或拔出一个 USB 转串口适配器如 CH340、CP2102 等时应用程序需要能够自动检测到设备的变化并更新可用的串口列表而无需重启程序。这种功能被称为“设备热插拔检测”。本文将详细介绍如何在基于 PyQt6 的图形界面应用程序中实现跨平台Windows、Linux、macOS的串口设备热插拔检测。我们将结合PyQt6的信号槽机制和 Python 的pyserial库构建一个稳定、响应及时的解决方案。2、核心思路与原理实现热插拔检测的核心在于监听系统底层发出的设备变更事件并在事件发生时重新扫描可用的串口列表。不同操作系统的底层机制不同Windows: 可以通过监听 Windows 消息如WM_DEVICECHANGE或使用 Windows API如RegisterDeviceNotification。在 PyQt6 中我们可以利用其事件过滤器eventFilter来捕获这些系统级消息。Linux/macOS: 通常通过监听/dev目录下文件如ttyUSB*,ttyACM*的变化来实现。我们可以使用QFileSystemWatcher来监控目录。为了简化跨平台开发我们将采用一种更通用的策略使用一个定时器QTimer定期轮询当前可用的串口列表并与之前保存的列表进行比较。如果列表发生变化则发出信号通知界面更新。虽然轮询不如事件驱动高效但对于串口设备变化频率不高的场景来说实现简单且完全跨平台是更稳妥的选择。3、环境准备与依赖安装首先确保你的 Python 环境已安装必要的库pipinstallPyQt6 pyserialPyQt6: 用于构建图形用户界面。pyserial: 用于列举和操作串口设备。4、 代码实现热插拔检测器类我们将创建一个名为SerialPortMonitor的类它继承自QObject以便使用 PyQt6 的信号槽机制。importsysfromPyQt6.QtCoreimportQObject,QTimer,pyqtSignalfromPyQt6.QtWidgetsimportQApplication,QMainWindow,QComboBox,QVBoxLayout,QWidgetimportserial.tools.list_portsclassSerialPortMonitor(QObject): 串口设备热插拔检测器。 使用定时器轮询方式跨平台兼容。 # 定义一个信号当可用串口列表发生变化时发出参数为新的端口名列表ports_changedpyqtSignal(list)def__init__(self,poll_interval2000): 初始化检测器。 :param poll_interval: 轮询间隔单位毫秒默认2秒 super().__init__()self.poll_intervalpoll_interval self._current_ports[]# 保存当前检测到的端口列表self._timerQTimer()self._timer.timeout.connect(self._check_ports)self._init_ports_list()def_init_ports_list(self):初始化当前端口列表self._current_ports[port.deviceforportinserial.tools.list_ports.comports()]def_check_ports(self):定时器触发的检查函数# 获取当前所有可用串口available_ports[port.deviceforportinserial.tools.list_ports.comports()]# 比较列表是否发生变化考虑顺序无关ifset(available_ports)!set(self._current_ports):print(f串口列表已变更。旧列表:{self._current_ports}, 新列表:{available_ports})self._current_portsavailable_ports# 发出信号传递新的端口列表self.ports_changed.emit(available_ports)defstart(self):启动监控self._init_ports_list()# 启动时先获取一次self._timer.start(self.poll_interval)print(串口热插拔监控已启动。)defstop(self):停止监控self._timer.stop()print(串口热插拔监控已停止。)defget_current_ports(self):获取当前检测到的端口列表returnself._current_ports.copy()关键点说明ports_changed信号这是连接检测逻辑和用户界面的桥梁。当端口列表变化时此信号会被触发。_check_ports方法核心轮询逻辑。使用serial.tools.list_ports.comports()获取当前所有串口设备并与之前保存的列表进行对比。start()/stop()方法控制监控的启停。5、 集成到 PyQt6 主界面下面创建一个简单的主窗口包含一个下拉框QComboBox来显示可用串口并将监控器集成进去。classMainWindow(QMainWindow):def__init__(self):super().__init__()self.setWindowTitle(PyQt6 串口热插拔检测示例)self.setGeometry(100,100,400,200)# 创建中央部件和布局central_widgetQWidget()self.setCentralWidget(central_widget)layoutQVBoxLayout(central_widget)# 创建下拉框用于显示串口self.combo_portsQComboBox()layout.addWidget(self.combo_ports)# 初始化串口监控器self.monitorSerialPortMonitor(poll_interval1500)# 每1.5秒检查一次# 连接监控器的信号到更新界面的槽函数self.monitor.ports_changed.connect(self.update_com_port_list)# 启动监控self.monitor.start()# 初始更新一次列表self.update_com_port_list(self.monitor.get_current_ports())defupdate_com_port_list(self,port_list): 更新下拉框中的串口列表。 :param port_list: 新的可用串口设备名列表 current_selectionself.combo_ports.currentText()self.combo_ports.clear()self.combo_ports.addItems(port_list)# 尝试恢复之前的选择如果该端口仍然存在ifcurrent_selectioninport_list:indexself.combo_ports.findText(current_selection)ifindex0:self.combo_ports.setCurrentIndex(index)elifport_list:# 如果列表不为空默认选择第一个self.combo_ports.setCurrentIndex(0)print(f界面已更新可用串口:{port_list})defcloseEvent(self,event):重写关闭事件确保停止监控器self.monitor.stop()event.accept()if__name____main__:appQApplication(sys.argv)windowMainWindow()window.show()sys.exit(app.exec())运行效果运行上述程序后窗口会显示当前可用的串口如COM3,/dev/ttyUSB0。当你插入或拔出一个 USB 串口设备时控制台会打印变更日志并且下拉框中的列表会自动刷新。6、进阶优化与平台特定方法6.1、 减少轮询开销如果担心定时轮询对性能有影响可以动态调整轮询间隔设备稳定时延长间隔如 5 秒检测到一次变化后在短时间内提高频率如 500 毫秒连续检查几次以应对系统枚举设备较慢的情况。使用线程将端口扫描放在单独的线程中避免阻塞主界面。6.2、 Windows 事件驱动方法可选对于 Windows 平台可以实现更高效的事件驱动监听。这需要重写主窗口的nativeEvent方法或使用事件过滤器来捕获WM_DEVICECHANGE消息。此方法更复杂但响应更及时。# 简要示例在MainWindow中增加事件过滤仅Windows有效fromPyQt6.QtCoreimportQEventimportctypesimportwin32con# 需要 pip install pywin32classMainWindow(QMainWindow):# ... 之前的初始化代码 ...defnativeEvent(self,eventType,message):Windows 原生事件处理try:msgctypes.wintypes.MSG.from_address(message.__int__())ifmsg.messagewin32con.WM_DEVICECHANGE:# 收到设备变更消息通知监控器立即检查或直接在这里处理print(收到设备变更系统消息)# 可以在这里直接调用 self.monitor._check_ports() 或发一个信号self.monitor._check_ports()except:passreturnsuper().nativeEvent(eventType,message)6.3、 Linux/macOS 目录监控方法可选在 Linux/macOS 上可以使用QFileSystemWatcher监控/dev目录。fromPyQt6.QtCoreimportQFileSystemWatcherclassSerialPortMonitor(QObject):def__init__(self):super().__init__()self.watcherQFileSystemWatcher()# 注意可能需要监控 /dev 目录但权限和事件粒度需要处理# self.watcher.addPath(/dev)# self.watcher.directoryChanged.connect(self._check_ports)# 更简单的做法是监控一个特定的符号链接目录或结合轮询# 此处作为思路展示不展开实现7、总结本文提供了一种在 PyQt6 应用中实现串口设备热插拔检测的可靠、跨平台的解决方案。核心是使用QTimer定期轮询并结合pyserial库来检测串口列表变化。虽然轮询方式在实时性上略有妥协但其实现简单、稳定性高非常适合大多数桌面应用场景。二、代码示例1、定时器扫描importsysfromPyQt6.QtWidgetsimportQApplication,QMainWindow,QComboBox,QVBoxLayout,QWidget,QLabelfromPyQt6.QtCoreimportQTimer,QtfromPyQt6.QtSerialPortimportQSerialPortInfoclassSerialHotPlugWindow(QMainWindow):def__init__(self):super().__init__()self.setWindowTitle(串口热插拔检测 - 轮询方案)self.resize(400,200)# UIcentralQWidget()self.setCentralWidget(central)layoutQVBoxLayout(central)self.cbx_portQComboBox()self.label_tipQLabel(插拔USB串口会自动刷新下拉框)layout.addWidget(self.label_tip)layout.addWidget(self.cbx_port)# 保存上一次串口列表self.last_port_namesset()# 定时刷新 500ms一次self.timerQTimer(self)self.timer.setInterval(500)self.timer.timeout.connect(self.scan_serial_ports)self.timer.start()defscan_serial_ports(self):# 获取当前所有串口名称current_ports{info.portName()forinfoinQSerialPortInfo.availablePorts()}# 新增new_portscurrent_ports-self.last_port_names# 移除lost_portsself.last_port_names-current_portsifnew_ports:print(f【插入串口】{new_ports})iflost_ports:print(f【拔出串口】{lost_ports})# 更新下拉框self.cbx_port.clear()self.cbx_port.addItems(sorted(current_ports))# 更新历史列表self.last_port_namescurrent_portsif__name____main__:appQApplication(sys.argv)winSerialHotPlugWindow()win.show()sys.exit(app.exec())运行结果
延伸阅读

更多相关文章

2026/11/4 23:24:17

composable-functions架构设计:如何设计可组合的业务逻辑层

composable-functions架构设计:如何设计可组合的业务逻辑层 【免费下载链接】domain-functions Types and functions to make composition easy and safe 项目地址: https://gitcode.com/gh_mirrors/do/domain-functions composable-functions是一个专注于函…

2026/11/4 15:39:34

如何利用Damn Vulnerable DeFi进行团队安全培训:完整教学方案

如何利用Damn Vulnerable DeFi进行团队安全培训:完整教学方案 【免费下载链接】damn-vulnerable-defi 项目地址: https://gitcode.com/gh_mirrors/da/damn-vulnerable-defi Damn Vulnerable DeFi是一个专门为DeFi安全培训设计的开源项目,它提供了…

2026/11/5 9:08:22

VS2026 打包 C++ 程序生成 EXE,借助 Installer Project 扩展工具

文章目录1. 安装 Microsoft Visual Studio Installer Projects 20222. 添加 Setup Project3. 在 File System 中添加相关文件及项目输出4. Qt 部署5. 生成桌面快捷方式6. 修改桌面快捷方式图标参考资料本文适用情况为:已经通过 visual studio 平台开发并测试好了程序…

2026/11/5 9:08:22

File、IO流

File用于操作文件,IO流用于读写数据1.File文件对象常用方法package com.popo.filedemo;import java.io.File; import java.io.IOException;public class FileDemo1 {public static void main(String[] args) throws Exception {// 文件对象常用方法File f1 new Fil…

2026/11/5 9:08:22

用 CLion 定位基于 RK3568 嵌入式 Linux 5.10.160 Core Dump 崩溃问题

嵌入式 Linux 上调试偶发崩溃是件头疼事:现场复现成本高、串口打印有限、gdb 直接 attach 又会打断业务。把 core dump 落盘、拿回开发机用 CLion 慢慢分析,是性价比最高的做法。本文以飞凌 OK3568 开发板(RK3568, Linux 5.10.160, Buildroot)为例,走完"板上开启 cor…

2026/11/5 9:08:22

RHCSA快速复习总结

RHCSA 重点总结RHCSA 是红帽认证的入门级,核心是 Linux 系统基础管理。本文按「系统入门 → 文件与文本 → 用户权限 → 网络软件 → 进程磁盘」的顺序提炼重点,方便快速复习。一、系统入门与安装Linux 由内核统一管理硬件,上层通过系统调用对…

2026/11/5 9:03:21

【工程师选酒避坑指南】一桌家常菜,配什么酒

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑