使用 PySide6 编写Qt程序

我想装一个python qt试试,我之前都是用c++ qt


直接上 PySide6

(Qt 官方 Python 绑定,优先选这个,不要 PyQt6)

理由:Qt 官方维护,LGPL 协议宽松,类名、API 和 C++Qt 几乎一模一样,你有 C++Qt 基础,上手几乎零成本

PyQt6 是第三方,商用要付费,直接排除。

最小 Demo

cpp 复制代码
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget
import sys

# 主窗口类,和C++的class MainWindow : public QMainWindow 完全对应
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PySide6 测试窗口")
        self.resize(400,220)

        # 中心部件 + 布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)

        self.btn = QPushButton("点击按钮")
        layout.addWidget(self.btn)

        # 信号槽:C++ connect(btn,&QPushButton::clicked,this,&xxx);
        self.btn.clicked.connect(self.on_button_click)

    def on_button_click(self):
        self.btn.setText("按钮被点击了!")

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



前置条件:

Windows 安装步骤(推荐先建虚拟环境,隔离包)

打开 Windows Terminal / PowerShell

bash 复制代码
# 1. 创建虚拟环境(文件夹叫env,只装本次项目依赖)
python -m venv pyside_env

# 2. 激活虚拟环境(Windows)
.\pyside_env\Scripts\activate

激活成功后,命令行前面会出现 (pyside_env)

cpp 复制代码
# 3. 安装PySide6
pip install pyside6

装好自带工具:pyside6-designer 直接启动 Qt Designer!就是你熟悉的拖拽 UI 编辑器,不用额外装 Qt Creator。

验证安装:

bash 复制代码
python -c "import PySide6;print(PySide6.__version__)"



为什么需要创建虚拟环境

虚拟环境就是给每个 Python 项目单独 "隔离一套独立的 Python 解释器 + 包",项目之间互不干扰。

你写 C/C++ 习惯了,我用你熟悉的开发场景类比。

类比 C/C++ 项目

C/C++:不同项目依赖不同版本的库,一般靠单独的编译环境、CMake 工具链、vcpkg/conan 的独立包目录隔离;如果所有项目共用一套全局库,版本冲突就会编译报错。

Python 默认(不建虚拟环境):所有项目共用同一个全局 pip 包目录。所有库全部装在一处。

虚拟环境解决的核心问题

解决包版本冲突(最主要目的)

举个例子:

  • 项目 A(PySide6 上位机):需要 pyside6==6.7.0
  • 项目 B(老脚本):需要 pyside6==6.4.2

如果装在全局:后安装的版本会覆盖前面的版本,其中一个项目直接报错。

虚拟环境:A 的环境装 6.7,B 的环境装 6.4,互相看不见,完全隔离。
你后面可能还会装 rich、textual、numpy、scipy,不同库对依赖版本要求不一样,很容易踩坑。




让ai生成了一个复杂点的程序:

cpp 复制代码
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
                               QPushButton, QTableWidget, QTableWidgetItem, QLabel, QLineEdit, QHeaderView)
from PySide6.QtCore import QTimer, Qt
from PySide6.QtCharts import QChart, QChartView, QLineSeries, QValueAxis
from PySide6.QtGui import QPen, QPainter   # 增加 QPainter
import sys
import random

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PySide6 UDP报文监控上位机")
        self.resize(900, 600)

        # 采集状态标记
        self.is_running = False
        self.data_count = 0
        self.series = QLineSeries() # 波形曲线

        # 定时器:模拟UDP接收报文,100ms触发一次
        self.timer = QTimer()
        self.timer.timeout.connect(self.on_timer_recv)

        # ========== 中心部件与总布局 ==========
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QHBoxLayout(central_widget)

        # 左侧布局:控制 + 报文表格
        left_widget = QWidget()
        left_layout = QVBoxLayout(left_widget)
        left_widget.setFixedWidth(420)

        # 控制行:IP、端口、按钮
        ctrl_layout = QHBoxLayout()
        ctrl_layout.addWidget(QLabel("目标IP:"))
        self.edit_ip = QLineEdit("127.0.0.1")
        ctrl_layout.addWidget(self.edit_ip)
        ctrl_layout.addWidget(QLabel("端口:"))
        self.edit_port = QLineEdit("8888")
        ctrl_layout.addWidget(self.edit_port)
        left_layout.addLayout(ctrl_layout)

        # 功能按钮行
        btn_layout = QHBoxLayout()
        self.btn_start = QPushButton("开始采集")
        self.btn_start.clicked.connect(self.toggle_collect)
        self.btn_clear = QPushButton("清空表格")
        self.btn_clear.clicked.connect(self.clear_table)
        btn_layout.addWidget(self.btn_start)
        btn_layout.addWidget(self.btn_clear)
        left_layout.addLayout(btn_layout)

        # 报文表格
        self.table = QTableWidget()
        self.table.setColumnCount(3)
        self.table.setHorizontalHeaderLabels(["序号", "数值", "时间戳"])
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        left_layout.addWidget(self.table)

        # ========== 右侧:QChart波形图 ==========
        self.chart = QChart()
        self.chart.setTitle("实时信号波形")
        self.chart.addSeries(self.series)

        # 坐标轴
        self.axis_x = QValueAxis()
        self.axis_x.setTitleText("采样点")
        self.axis_x.setRange(0, 50)

        self.axis_y = QValueAxis()
        self.axis_y.setTitleText("幅值")
        self.axis_y.setRange(0, 100)

        self.chart.addAxis(self.axis_x, Qt.AlignBottom)
        self.chart.addAxis(self.axis_y, Qt.AlignLeft)
        self.series.attachAxis(self.axis_x)
        self.series.attachAxis(self.axis_y)

        pen = QPen(Qt.blue)
        pen.setWidth(2)
        self.series.setPen(pen)

        chart_view = QChartView(self.chart)
        # ========== 修复这一行 ==========
        chart_view.setRenderHint(QPainter.RenderHint.Antialiasing)

        # 左右布局加入总布局
        main_layout.addWidget(left_widget)
        main_layout.addWidget(chart_view)

    def toggle_collect(self):
        """启停采集"""
        if not self.is_running:
            self.is_running = True
            self.btn_start.setText("停止采集")
            self.timer.start(100) # 100ms周期
        else:
            self.is_running = False
            self.btn_start.setText("开始采集")
            self.timer.stop()

    def on_timer_recv(self):
        """定时器回调:模拟收到UDP报文"""
        self.data_count += 1
        # 模拟信号值
        val = random.randint(20,80)
        # 插入表格新行
        row = self.table.rowCount()
        self.table.insertRow(row)
        self.table.setItem(row, 0, QTableWidgetItem(str(self.data_count)))
        self.table.setItem(row, 1, QTableWidgetItem(str(val)))
        self.table.setItem(row, 2, QTableWidgetItem(f"{self.data_count*0.1:.1f}s"))

        # 添加波形点,只保留最近50个点
        self.series.append(self.data_count, val)
        if self.series.count() > 50:
            self.series.remove(0)

    def clear_table(self):
        """清空表格与波形"""
        self.table.setRowCount(0)
        self.series.clear()
        self.data_count = 0

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

PySide6 示例:UDP 报文监控简易上位机

功能:

  1. 窗口分面板:参数设置、报文接收表格、实时波形曲线(QChart)
  2. QTimer 模拟 UDP 接收数据(你后续可以直接替换成真实 socket recv)
  3. 收到数据自动填入表格,同时绘制波形
  4. 【开始 / 停止】按钮控制采集
  5. 清空表格按钮
相关推荐
努力实干7 小时前
Qt/C++ 模块化设计与工程组织
开发语言·c++·qt
Lhan.zzZ7 小时前
Qt:动态库模块框架设计
开发语言·c++·qt
qq_401700411 天前
TCP 长连接、心跳包与断线自动重连设计:工业级通信的“不死鸟”架构
网络·qt·tcp/ip
dyxal2 天前
A2A 协议 v1.0 完全指南:方法名、Agent Card、三种绑定与 FastAPI 实战
开发语言·qt·fastapi
金色熊族2 天前
在Qt中使用asan检测内存泄漏(一)
linux·qt·asan
前行中的小猪2 天前
Qt 5 踩坑实录:多显示器跨屏拖拽导致窗口异常放大与 setGeometry 报错的深度解析与根治
qt·多显示器·高分辨率·多屏幕
想做小南娘,发现自己是女生喵2 天前
QT项目实战第一周(嵌入式)
开发语言·qt
誰能久伴不乏2 天前
【无标题】
c++·qt·机器人
金色熊族2 天前
在Qt中使用asan检测内存泄漏(二)--检查依赖库的内存使用
linux·qt·asan
qq_401700412 天前
Qt 组播(Multicast)实战详解
开发语言·qt