用 PyQt5 快速开发专业桌面工具 —— 从 PyCharm 到界面设计全流程详解

购买与学习资源



用 PyQt5 快速开发专业桌面工具 —— 从 PyCharm 到界面设计全流程详解


1. PyQt5:Python 的强大桌面开发利器

PyQt5 是 Python 的 Qt 框架绑定,拥有丰富的界面控件、跨平台(Windows/Linux/Mac 都支持)、学习曲线平缓,非常适合自动化、数据可视化、硬件调试工具等桌面开发场景。


在这里插入图片描述

2. 环境与工具准备

2.1 Python 环境

  • 推荐使用 Python 3.7 及以上,建议用 PyCharm 作为开发环境(写 Python GUI,PyCharm 功能非常强大)。

2.2 安装核心包

pip install pyqt5 pyqt5-tools

pyqt5-tools 里包含 Qt Designer(可视化界面编辑工具)。


3. PyCharm 的核心使用技巧

  • 项目结构清晰:左侧 Project 面板管理文件,便于拆分模块(如 main.py、ui.py、worker.py)。
  • 智能补全:输入类名或方法,自动补齐、跳转,提升开发速度。
  • 终端集成:右下角 Terminal,支持 pip、git、pyuic5 命令,不必离开 PyCharm。
  • 可视化调试:断点、变量观察,调试界面事件和多线程异常都很方便。

4. Qt Designer —— 所见即所得的界面设计

4.1 打开 Designer

  • 终端输入 designer(Windows下pyqt5-tools的安装目录下有 Designer.exe)。

4.2 拖拽控件

  • 拖拽按钮、输入框、标签等控件,布局完毕后保存为 xxx.ui 文件。

4.3 用 pyuic5 转换

pyuic5 xxx.ui -o xxx_ui.py
  • 得到标准 Python 界面类,便于代码调用。

5. PyQt5 核心开发模式

5.1 典型结构

  • 界面代码:由 .ui.py 或自己写。
  • 主逻辑:主窗口/主逻辑类(继承自 QWidget/QMainWindow)。
  • 数据/任务线程:如后台监听、串口/USB等,放在线程 worker 中。
  • 信号与槽:事件响应,界面与业务解耦。

5.2 最常用控件/类

控件/类作用用法简述
QPushButton按钮触发事件
QLabel文本/图片显示显示状态、标签
QLineEdit单行输入框输入命令、参数等
QTextEdit多行日志显示显示数据、日志
QComboBox下拉选择框设备、端口、模式选择
QTableWidget表格控件批量数据显示
QThread线程后台监听或数据处理
pyqtSignal自定义信号线程/界面通信

6. 实用案例:USB 设备监听工具界面(主程序精简版)

实现:设备选择、接口选择、端点选择、监听数据、发送数据,全流程演示。

import usb.core
import usb.util
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QComboBox, QTextEdit, QLabel, QLineEdit
from PyQt5.QtCore import QThread, pyqtSignal

# Worker 线程用于数据监听(防止界面卡死)
class USBReceiver(QThread):
    data_received = pyqtSignal(str)
    def __init__(self, dev, ep):
        super().__init__()
        self.dev = dev
        self.ep = ep
        self.running = True

    def run(self):
        self.data_received.emit("✅ 开始监听...")
        while self.running:
            try:
                data = self.dev.read(self.ep.bEndpointAddress, self.ep.wMaxPacketSize, timeout=1000)
                hex_str = " ".join(f"{b:02X}" for b in data)
                self.data_received.emit(f"📥 数据: {hex_str}")
            except Exception:
                continue

    def stop(self):
        self.running = False
        self.wait()

class USBMonitor(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("USB监听调试工具")
        self.resize(680, 480)
        self.device_combo = QComboBox()
        self.ep_combo = QComboBox()
        self.scan_btn = QPushButton("刷新设备")
        self.start_btn = QPushButton("监听")
        self.stop_btn = QPushButton("停止")
        self.send_edit = QLineEdit("01 02 02 02 ...")  # 默认发送数据
        self.send_btn = QPushButton("发送")
        self.log_view = QTextEdit()
        self.log_view.setReadOnly(True)

        layout = QVBoxLayout()
        layout.addWidget(QLabel("设备选择:"))
        layout.addWidget(self.device_combo)
        layout.addWidget(self.scan_btn)
        layout.addWidget(QLabel("端点选择:"))
        layout.addWidget(self.ep_combo)
        layout.addWidget(self.start_btn)
        layout.addWidget(self.stop_btn)
        layout.addWidget(QLabel("发送数据(16进制空格分隔):"))
        layout.addWidget(self.send_edit)
        layout.addWidget(self.send_btn)
        layout.addWidget(self.log_view)
        self.setLayout(layout)

        self.devices = []
        self.endpoints = []
        self.reader = None
        self.scan_btn.clicked.connect(self.scan_devices)
        self.device_combo.currentIndexChanged.connect(self.refresh_endpoints)
        self.start_btn.clicked.connect(self.start_listen)
        self.stop_btn.clicked.connect(self.stop_listen)
        self.send_btn.clicked.connect(self.send_data)

        self.scan_devices()

    def log(self, msg):
        self.log_view.append(msg)

    def scan_devices(self):
        self.device_combo.clear()
        self.devices = []
        for dev in usb.core.find(find_all=True):
            vid, pid = dev.idVendor, dev.idProduct
            try:
                manu = usb.util.get_string(dev, dev.iManufacturer) or "N/A"
                prod = usb.util.get_string(dev, dev.iProduct) or "N/A"
            except Exception:
                manu, prod = "N/A", "N/A"
            label = f"{manu} - {prod} (VID:0x{vid:04X}, PID:0x{pid:04X})"
            self.device_combo.addItem(label)
            self.devices.append(dev)
        self.refresh_endpoints(0)

    def refresh_endpoints(self, idx):
        self.ep_combo.clear()
        self.endpoints = []
        if idx < 0 or idx >= len(self.devices): return
        dev = self.devices[idx]
        try:
            cfg = dev.get_active_configuration()
        except Exception:
            self.log("无法获取设备配置")
            return
        for intf in cfg:
            for ep in intf:
                if usb.util.endpoint_direction(ep.bEndpointAddress) == usb.util.ENDPOINT_IN:
                    self.ep_combo.addItem(f"端点0x{ep.bEndpointAddress:02X}, 长度:{ep.wMaxPacketSize}")
                    self.endpoints.append(ep)

    def start_listen(self):
        idx = self.device_combo.currentIndex()
        ep_idx = self.ep_combo.currentIndex()
        if idx < 0 or ep_idx < 0: return
        dev = self.devices[idx]
        ep = self.endpoints[ep_idx]
        if self.reader: self.reader.stop()
        self.reader = USBReceiver(dev, ep)
        self.reader.data_received.connect(self.log)
        self.reader.start()

    def stop_listen(self):
        if self.reader:
            self.reader.stop()
            self.log("🛑 已停止监听")

    def send_data(self):
        idx = self.device_combo.currentIndex()
        ep_idx = self.ep_combo.currentIndex()
        if idx < 0 or ep_idx < 0: return
        dev = self.devices[idx]
        ep = self.endpoints[ep_idx]
        hex_str = self.send_edit.text().strip()
        try:
            data = [int(x, 16) for x in hex_str.split()]
            sent = dev.write(ep.bEndpointAddress, data, timeout=1000)
            self.log(f"✅ 已发送 {sent} 字节: {hex_str}")
        except Exception as e:
            self.log(f"❌ 发送失败: {e}")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = USBMonitor()
    win.show()
    sys.exit(app.exec_())

可扩展:后台线程监听数据,界面实时显示和发送。更复杂功能可拆分为独立 py 文件和模块。


7. 小结:PyQt5 + PyCharm 实战经验精髓

  1. 界面设计靠 Designer,交互逻辑用 Python
  2. 信号/槽让界面与后台分离,线程防止卡顿
  3. PyCharm 提升开发体验:调试、补全、终端一体化
  4. 可扩展性强,适合工程化管理
  5. 写工具,不必重复造轮子,善用布局和信号机制,维护省心

8. 推荐进阶资源


购买与学习资源


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值