当前位置: 首页 > news >正文

Qt布局管理

前言

最近做上位机开发,由于 VS studio 被禁用了,所以为了弥补上位机开发的空白,最近花了 2 周时间将由 MFC 框架下编写的软件,改用成用 QT 编写的上位机软件,并且再这过程中,学习使用了如何编写 QT 上位机,虽说之前有短暂接触到 QT 开发,但都是没有系统学习,而且界面布局都是用的 QT Creator 布局出来的软件,无法随窗口界面放大缩小。仔细研究 Qt 布局系统后,终于对这一块了解的更加熟悉了。接下来我将简单介绍一下如何实现布局。

成熟软件展示

这里展示一下平时最常用的串口软件 XCOM
image.png
如图所示,该软件分为 3 个大块,上面两块为水平布局合并为一整块,再与下方一块竖直布局。
这里以我正在做的一个上位机来说明,如何进行布局。
image.png

完整代码

import sys
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QFormLayout,
    QPushButton, QComboBox, QLineEdit, QCheckBox, QLabel, QScrollArea, QTextEdit,QSizePolicy,
    QGridLayout, QGroupBox, QLayout, QTabWidget)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt, QSizeclass SerialHelperWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("串口调试工具")
        self.resize(1600, 800)
        self.setWindowIcon(QIcon("./icon/app.ico")); # 确保路径正确    
        # 串口选择部分
        self.SerialLabel = QLabel("串口:")
        self.SerialCombo = QComboBox()
        self.SerialCombo.setMaximumWidth(100)
        self.SerialCombo.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Maximum)
        self.SerialLabel.setBuddy(self.SerialCombo)        self.BaudLabel = QLabel("波特率:")
        self.BaudCombo = QComboBox()
        self.BaudCombo.setMaximumWidth(100)
        self.BaudCombo.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Maximum)
        self.BaudLabel.setBuddy(self.BaudCombo)        self.DatabitsLabel = QLabel("数据位:")
        self.DatabitsCombo = QComboBox()
        self.DatabitsCombo.setMaximumWidth(100)
        self.DatabitsCombo.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Maximum)
        self.DatabitsLabel.setBuddy(self.DatabitsCombo)        self.StopbitsLabel = QLabel("停止位:")
        self.StopbitsCombo = QComboBox()
        self.StopbitsCombo.setMaximumWidth(100)
        self.StopbitsCombo.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Maximum)
        self.StopbitsLabel.setBuddy(self.StopbitsCombo)        self.CheckbitsLabel = QLabel("校验位:")
        self.CheckbitsCombo = QComboBox()
        self.CheckbitsCombo.setMaximumWidth(100)
        self.CheckbitsCombo.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Maximum)
        self.CheckbitsLabel.setBuddy(self.CheckbitsCombo)        self.SerialStatusLabel = QLabel("串口操作:")
        self.SerialStatusicon = QLabel()
        self.SerialStatusicon.setMinimumSize(QSize(20, 20))
        self.SerialStatusicon.setMaximumSize(QSize(20, 20))
        self.SerialStatusicon.setSizeIncrement(QSize(0, 0))
        self.SerialStatusicon.setBaseSize(QSize(0, 0))
        self.SerialStatusicon.setStyleSheet("border-radius:10px;background-color:red")
        self.SerialStatusicon.setText("")        self.SerialStatusButton = QPushButton("打开串口")
        self.SerialStatusButton.setMaximumWidth(80)
      	self.SerialStatusButton.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Maximum)        self.SerialSettingGridLayout = QGridLayout()
        self.SerialSettingGridLayout.addWidget(self.SerialLabel, 0, 0)
        self.SerialSettingGridLayout.addWidget(self.SerialCombo, 0, 1)
        self.SerialSettingGridLayout.addWidget(self.BaudLabel, 1, 0)
        self.SerialSettingGridLayout.addWidget(self.BaudCombo, 1, 1)
        self.SerialSettingGridLayout.addWidget(self.DatabitsLabel, 2, 0)
        self.SerialSettingGridLayout.addWidget(self.DatabitsCombo, 2, 1)
        self.SerialSettingGridLayout.addWidget(self.StopbitsLabel, 3, 0)
        self.SerialSettingGridLayout.addWidget(self.StopbitsCombo, 3, 1)
        self.SerialSettingGridLayout.addWidget(self.CheckbitsLabel, 4, 0)
        self.SerialSettingGridLayout.addWidget(self.CheckbitsCombo, 4, 1)        self.SerialStatusLayout = QHBoxLayout()
        self.SerialStatusLayout.addWidget(self.SerialStatusLabel)
        self.SerialStatusLayout.addWidget(self.SerialStatusicon)
        self.SerialStatusLayout.addWidget(self.SerialStatusButton)        self.SerialSettingsLayout = QVBoxLayout()
        self.SerialSettingsLayout.addLayout(self.SerialSettingGridLayout)
        self.SerialSettingsLayout.addLayout(self.SerialStatusLayout)
        # self.SerialSettingsLayout.addStretch()        self.SerialSettingsGroupBox = QGroupBox("设备设置")
        self.SerialSettingsGroupBox.setLayout(self.SerialSettingsLayout)        # 接收区
        self.receiveTextEdit = QTextEdit()
        self.receiveTextEdit.setReadOnly(True)
        self.receiveTextEdit.setPlaceholderText("接收区")        self.tabWidget = QTabWidget()
        self.tabWidget.addTab(self.receiveTextEdit, "接收区")        # 左边
        self.mainVBoxLayout1 = QVBoxLayout()
        self.mainVBoxLayout1.setSizeConstraint(QLayout.SetFixedSize)
        self.mainVBoxLayout1.addWidget(self.SerialSettingsGroupBox)
        self.mainVBoxLayout1.addStretch()
        # 右边
        self.mainVBoxLayout2 = QVBoxLayout()
        self.mainVBoxLayout2.setSizeConstraint(QLayout.SetFixedSize)
        self.mainVBoxLayout2.addWidget(self.tabWidget)        # 主界面布局
        self.widget = QWidget(self)
        self.mainLayout = QHBoxLayout()        self.mainLayout.addLayout(self.mainVBoxLayout1)
        self.mainLayout.addLayout(self.mainVBoxLayout2)
        # 自适应布局
        self.widget.setLayout(self.mainLayout)
        # 设置主窗口的中央部件
        self.setCentralWidget(self.widget)if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = SerialHelperWindow()
    window.show()
    sys.exit(app.exec_())

布局详解

这里说明下为啥用 PyQt 制作,其实本质上 PyQt 和 Qt C++ 都是差不多的没有过于本质的区别,两者的接口调用 API 都是一样的,最多也就需要遵循下相应的语法规则。我这里是因为后续项目需要用到相应 Python 的库所以就直接用 PyQt 了。我这里主要以 API 接口进行说明。

窗口全局信息设置

self.setWindowTitle("串口调试工具")
self.resize(1600, 800)
self.setWindowIcon(QIcon("./icon/app.ico")); # 确保路径正确   
  • SetWindowTitle:设置窗口标题
  • resize:设置窗口大小
  • setWindowIcon:设置窗口图标

串口设置区域布局

串口设置区域采用QGridLayout(网格布局)来排列标签和输入控件。每个控件通过指定行和列的位置精确放置在网格中。

# 串口选择部分
self.SerialLabel = QLabel("串口:")
self.SerialCombo = QComboBox()
self.SerialCombo.setMaximumWidth(100)
self.SerialCombo.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Maximum)
self.SerialLabel.setBuddy(self.SerialCombo)

这部分代码创建了一个标签(QLabel)用于显示“串口:”,一个组合框(QComboBox)供用户选择串口。通过setBuddy方法将标签与组合框关联,这样当用户点击标签时,焦点会自动跳转到组合框。

self.SerialSettingGridLayout = QGridLayout()
self.SerialSettingGridLayout.addWidget(self.SerialLabel, 0, 0)
self.SerialSettingGridLayout.addWidget(self.SerialCombo, 0, 1)
self.SerialSettingGridLayout.addWidget(self.BaudLabel, 1, 0)
self.SerialSettingGridLayout.addWidget(self.BaudCombo, 1, 1)
self.SerialSettingGridLayout.addWidget(self.DatabitsLabel, 2, 0)
self.SerialSettingGridLayout.addWidget(self.DatabitsCombo, 2, 1)
self.SerialSettingGridLayout.addWidget(self.StopbitsLabel, 3, 0)
self.SerialSettingGridLayout.addWidget(self.StopbitsCombo, 3, 1)
self.SerialSettingGridLayout.addWidget(self.CheckbitsLabel, 4, 0)
self.SerialSettingGridLayout.addWidget(self.CheckbitsCombo, 4, 1)

以上代码创建了一个网格布局,并将串口相关的标签和控件按照行列位置添加到布局中。例如,SerialLabel被放置在第0行第0列,而SerialCombo被放置在第0行第1列。

串口状态区域布局

串口状态区域采用QHBoxLayout(水平布局),将状态标签、状态指示器和操作按钮水平排列。

self.SerialStatusLayout = QHBoxLayout()
self.SerialStatusLayout.addWidget(self.SerialStatusLabel)
self.SerialStatusLayout.addWidget(self.SerialStatusicon)
self.SerialStatusLayout.addWidget(self.SerialStatusButton)

这段代码创建了一个水平布局,并将串口状态相关的控件添加到布局中。

整体串口设置区域

整体串口设置区域使用QVBoxLayout(垂直布局),将网格布局和水平布局垂直堆叠。

self.SerialSettingsLayout = QVBoxLayout()
self.SerialSettingsLayout.addLayout(self.SerialSettingGridLayout)
self.SerialSettingsLayout.addLayout(self.SerialStatusLayout)

这将串口参数设置的网格布局和串口状态的水平布局垂直排列。

self.SerialSettingsGroupBox = QGroupBox("设备设置")
self.SerialSettingsGroupBox.setLayout(self.SerialSettingsLayout)

最后,将整个串口设置区域放入一个分组框(QGroupBox)中,并给分组框添加标题“设备设置”。

主界面布局

主界面分为左右两部分:

# 左边
self.mainVBoxLayout1 = QVBoxLayout()
self.mainVBoxLayout1.setSizeConstraint(QLayout.SetFixedSize)
self.mainVBoxLayout1.addWidget(self.SerialSettingsGroupBox)
self.mainVBoxLayout1.addStretch()
# 右边
self.mainVBoxLayout2 = QVBoxLayout()
self.mainVBoxLayout2.setSizeConstraint(QLayout.SetFixedSize)
self.mainVBoxLayout2.addWidget(self.tabWidget)

左侧区域包含串口设置分组框,并通过addStretch()在底部添加弹性空间,使控件保持在顶部。右侧区域放置了一个标签页控件(QTabWidget)。

# 主界面布局
self.widget = QWidget(self)
self.mainLayout = QHBoxLayout()self.mainLayout.addLayout(self.mainVBoxLayout1)
self.mainLayout.addLayout(self.mainVBoxLayout2)
# 自适应布局
self.widget.setLayout(self.mainLayout)
# 设置主窗口的中央部件
self.setCentralWidget(self.widget)

最终,通过主窗口的水平布局将左右两个垂直布局区域组合在一起,形成了整个应用程序的界面结构。

通过这样的布局设计,界面元素可以随着窗口大小的变化而自适应调整位置和大小,提供更好的用户体验。

http://www.wuyegushi.com/news/568.html

相关文章:

  • 最小树形图:朱刘算法
  • 基于YOLOv8的边坡排水沟堵塞检测与识别项目|完整源码数据集+PyQt5界面+完整训练流程+开箱即用!
  • POLIR-Laws-民法典: 第三编 合同 : 第二分编 典型合同: 20.技术合同 : 1)一般规定、2)技术开发、3)技术转让 和 技术许可、4)技术咨询 和 技术服务
  • hybrid口
  • 利用Transformer模型提升产品检索效果
  • 第二十天
  • 《恶意代码实战分析》笔记
  • POLIR-Laws-民法典: 第三编 合同 : 第二分编 典型合同: 19.运输合同 : 1)一般规定、2)客运合同、3)货运合同、4)多式联运合同
  • 《大道至简》读后感
  • @GetMapping、@PostMapping、@PutMapping、@DeleteMapping
  • 建模神器草图大师!SketchUp 2025 安装激活全流程,新手也能玩转!
  • 【最新专业评测】PDF Reducer专业版:85%超高压缩率的PDF压缩神器|Windows最佳PDF压缩工具推荐
  • @RequestMapping
  • DMP学习路径之入门
  • 第一篇随笔
  • 旋转链表 - 商商
  • 匀速二阶贝塞尔曲线
  • Redis原理
  • HTTP POST请求:初学者指南与示范
  • @Autowired 自动依赖注入
  • 基于接口划分vlan
  • 【AirSim】图像API的使用
  • CSS页面布局
  • switch 语句
  • 优秀书籍随记
  • Golang 文本模板,你指定没用过
  • @RestController
  • Django实时通信实战:WebSocket与ASGI全解析(下)
  • DP 优化——决策单调性优化
  • VS插件报错,g++却完美编译?API调用错因分析