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

『pyqt5 从0基础开始项目实战』02. 页面布局设计(保姆级图文)

目录

    • 弹性布局介绍
    • 导包和框架代码
    • 布局框架搭建
      • 1. 总体布局框架
      • 2. 顶部菜单布局
      • 3. form添加内容布局
      • 4. table数据展示布局
      • 5. footer底部菜单
    • 完整项目代码
    • 总结


欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中
欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中

弹性布局介绍

当然你也可以用可视化工具designer设计ui然后转为为py文件,本专栏注重学习基础,就不再做这方面的介绍了。

并不是采用安卓开发中的绝对定位布局(画坐标系,按照x,y坐标布局,这样很容易因为空间的大小造成重叠控件等问题)

一般设计思路是首先窗口整体是垂直布局,然后每一行是水平布局,在每一行内部通过空白占位的弹簧设置各个控件的位置。
在这里插入图片描述


导包和框架代码

在上一文的基础框架上加入了本节需要用到的包

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QDesktopWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtWidgets import QPushButton, QLineEdit, QTableWidget, QTableWidgetItem, QLabelclass MainWindow(QWidget):def __init__(self):# 用super 继承父类的初始化super().__init__()# 设置窗口的窗体标题self.setWindowTitle('发现你走远了的xx系统')# 设置窗体的尺寸self.resize(1000, 450)# 设置窗体位置#获取整个窗口部分的宽高和左上角坐标信息,返回值是一个QRect类型,(x,y width,height)qr = self.frameGeometry()cp = QDesktopWidget().availableGeometry().center()#得到屏幕中间的位置信息qr.moveCenter(cp)#让我们的窗体移动到屏幕中间if __name__ == '__main__':app = QApplication(sys.argv)#实例化一个Application应用,所有的窗口均在其下运行window = MainWindow()  # 实例化窗口对象window.show()  # 窗口展示sys.exit(app.exec_())# app.exec_()运行主循环,并在退出时返回状态代码。# sys.exit(n)退出您的应用程序并返回n到父进程(通常是您的shell)

布局框架搭建

我们的窗口布局下有4个部分的子布局

1. 总体布局框架

在这里插入图片描述

        # 创建窗口总布局layout = QVBoxLayout()# 1.顶部菜单布局header_layout = QHBoxLayout()  # 创建顶部菜单布局layout.addLayout(header_layout)  # 将顶部菜单布局添加到总布局# 2.添加内容布局form_layout = QHBoxLayout()  # 创建添加内容布局layout.addLayout(form_layout)  # 将添加内容布局添加到总布局# 3.表格数据展示布局table_layout = QHBoxLayout()layout.addLayout(table_layout)# 4.底部菜单footer_layout = QHBoxLayout()layout.addLayout(footer_layout)# 给窗体设置元素的排列方式self.setLayout(layout)
  • 不要忘记最后给窗体设置元素的排列方式(不然布局不会生效,我一开始学找了半天的bug······)
    • self.setLayout(layout)

2. 顶部菜单布局

在这里插入图片描述
顶部菜单布局代码修改为:

        # 1.顶部菜单布局header_layout = QHBoxLayout()  # 创建顶部菜单布局# 1.1 放入按钮btn_start =QPushButton("开始")#新建一个开始按钮header_layout.addWidget(btn_start)#将开始按钮添加到顶部菜单布局btn_stop =QPushButton("停止")#新建一个开始按钮header_layout.addWidget(btn_stop)#将开始按钮添加到顶部菜单布局# 1.2 加入弹簧header_layout.addStretch()layout.addLayout(header_layout)  # 将顶部菜单布局添加到总布局

在这里插入图片描述

3. form添加内容布局

        # 2.添加内容布局form_layout = QHBoxLayout()  # 创建添加内容布局# 2.1 输入框txt_asin=QLineEdit()#新建一个输入框对象txt_asin.setText("B07YN82X3B=100")#设置默认的form数据txt_asin.setPlaceholderText("请输入商品ID和价格,例如:B0818JJQQ8=88")#设置灰色的提示信息form_layout.addWidget(txt_asin)#将输入框加入到布局中# 2.2 添加按钮btn_add = QPushButton("添加")#新建一个添加按钮form_layout.addWidget(btn_add)#将添加按钮添加到form布局layout.addLayout(form_layout)  # 将添加内容布局添加到总布局

在这里插入图片描述
在这里插入图片描述

4. table数据展示布局

因为表格比较多,修改一下前文提到的窗体尺寸

        # 窗体的尺寸self.resize(1228, 450)
  • 给表格添加单个行索引或者列索引的值
        # 3.表格数据展示布局table_layout = QHBoxLayout()# 3.1 创建表格table_widget=QTableWidget(2,8)#新建一个2行8列的表格# 修改表格索引名item=QTableWidgetItem()item.setText("标题0")table_widget.setHorizontalHeaderItem(0,item)table_widget.setColumnWidth(0,150)#设置水平单元格0号位置的宽度 150item2=QTableWidgetItem()item2.setText("网址1")table_widget.setHorizontalHeaderItem(1,item2)table_widget.setColumnWidth(1,400)#设置水平单元格1号位置的宽度 400item3=QTableWidgetItem()item3.setText("行索引0")table_widget.setVerticalHeaderItem(0,item3)table_layout.addWidget(table_widget)#把表格添加到表格布局中layout.addLayout(table_layout)

在这里插入图片描述

  • 给表格批量添加行索引 列索引的值,通过字典键值对和循环实现,不会用enumerate循环的话也可以用for循环代替

  • 注意新建表格的时候,因为没有数据,所以新建0行的表格

# 3.表格数据展示布局table_layout = QHBoxLayout()# 3.1 创建表格table_widget=QTableWidget(0,8)#新建一个0行2列的表格table_header = [{"field": "asin", "text": "ASIN", 'width': 120},{"field": "title", "text": "标题", 'width': 150},{"field": "url", "text": "URL", 'width': 400},{"field": "price", "text": "底价", 'width': 100},{"field": "success", "text": "成功次数", 'width': 100},{"field": "error", "text": "503次数", 'width': 100},{"field": "status", "text": "状态", 'width': 100},{"field": "frequency", "text": "频率(N秒/次)", 'width': 100},]for idx,info in enumerate(table_header):item=QTableWidgetItem()item.setText(info['text'])table_widget.setHorizontalHeaderItem(idx,item)table_widget.setColumnWidth(idx,info['width'])table_layout.addWidget(table_widget)#把表格添加到表格布局中layout.addLayout(table_layout)

在这里插入图片描述

5. footer底部菜单

        # 4.底部菜单footer_layout = QHBoxLayout()label_status = QLabel("未检测", self)footer_layout.addWidget(label_status)footer_layout.addStretch()#添加弹簧,更加美观btn_reset = QPushButton("重新初始化")footer_layout.addWidget(btn_reset)btn_recheck = QPushButton("重新检测")footer_layout.addWidget(btn_recheck)btn_reset_count = QPushButton("次数清零")footer_layout.addWidget(btn_reset_count)btn_delete = QPushButton("删除检测项")footer_layout.addWidget(btn_delete)btn_alert = QPushButton("SMTP报警配置")footer_layout.addWidget(btn_alert)btn_proxy = QPushButton("代理IP")footer_layout.addWidget(btn_proxy)layout.addLayout(footer_layout)

我们在没有新增弹簧时,所有的按钮平均宽度。
在这里插入图片描述
新增宽度后,按钮会自适应文本内容,相对而言更加美观
在这里插入图片描述


完整项目代码

import os
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QDesktopWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtWidgets import QPushButton, QLineEdit, QTableWidget, QTableWidgetItem, QLabelclass MainWindow(QWidget):def __init__(self):# 用super 继承父类的初始化super().__init__()# 设置窗口的窗体标题self.setWindowTitle('发现你走远了的xx系统')# 设置窗体的尺寸self.resize(1228, 450)# 设置窗体位置# 获取整个窗口部分的宽高和左上角坐标信息,返回值是一个QRect类型,(x,y width,height)qr = self.frameGeometry()cp = QDesktopWidget().availableGeometry().center()  # 得到屏幕中间的位置信息qr.moveCenter(cp)  # 让我们的窗体移动到屏幕中间# 创建窗口总布局layout = QVBoxLayout()# 1.顶部菜单布局header_layout = QHBoxLayout()  # 创建顶部菜单布局# 1.1 放入按钮btn_start =QPushButton("开始")#新建一个开始按钮header_layout.addWidget(btn_start)#将开始按钮添加到顶部菜单布局btn_stop =QPushButton("停止")#新建一个开始按钮header_layout.addWidget(btn_stop)#将开始按钮添加到顶部菜单布局# 1.2 加入弹簧header_layout.addStretch()layout.addLayout(header_layout)  # 将顶部菜单布局添加到总布局# 2.添加内容布局form_layout = QHBoxLayout()  # 创建添加内容布局# 2.1 输入框txt_asin=QLineEdit()#新建一个输入框对象txt_asin.setText("B07YN82X3B=100")#设置默认的form数据txt_asin.setPlaceholderText("请输入商品ID和价格,例如:B0818JJQQ8=88")#设置灰色的提示信息form_layout.addWidget(txt_asin)#将输入框加入到布局中# 2.2 添加按钮btn_add = QPushButton("添加")#新建一个添加按钮form_layout.addWidget(btn_add)#将添加按钮添加到form布局layout.addLayout(form_layout)  # 将添加内容布局添加到总布局# 3.表格数据展示布局table_layout = QHBoxLayout()# 3.1 创建表格table_widget=QTableWidget(0,8)#新建一个0行8列的表格# # 修改表格索引名# item=QTableWidgetItem()# item.setText("标题0")# table_widget.setHorizontalHeaderItem(0,item)# table_widget.setColumnWidth(0,150)#设置水平单元格0号位置的宽度 150## item2=QTableWidgetItem()# item2.setText("网址1")# table_widget.setHorizontalHeaderItem(1,item2)# table_widget.setColumnWidth(1,400)#设置水平单元格1号位置的宽度 400## item3=QTableWidgetItem()# item3.setText("行索引0")# table_widget.setVerticalHeaderItem(0,item3)table_header = [{"field": "asin", "text": "ASIN", 'width': 120},{"field": "title", "text": "标题", 'width': 150},{"field": "url", "text": "URL", 'width': 400},{"field": "price", "text": "底价", 'width': 100},{"field": "success", "text": "成功次数", 'width': 100},{"field": "error", "text": "503次数", 'width': 100},{"field": "status", "text": "状态", 'width': 100},{"field": "frequency", "text": "频率(N秒/次)", 'width': 100},]for idx,info in enumerate(table_header):item=QTableWidgetItem()item.setText(info['text'])table_widget.setHorizontalHeaderItem(idx,item)table_widget.setColumnWidth(idx,info['width'])table_layout.addWidget(table_widget)#把表格添加到表格布局中layout.addLayout(table_layout)# 4.底部菜单footer_layout = QHBoxLayout()label_status = QLabel("未检测", self)footer_layout.addWidget(label_status)footer_layout.addStretch()#添加弹簧,更加美观btn_reset = QPushButton("重新初始化")footer_layout.addWidget(btn_reset)btn_recheck = QPushButton("重新检测")footer_layout.addWidget(btn_recheck)btn_reset_count = QPushButton("次数清零")footer_layout.addWidget(btn_reset_count)btn_delete = QPushButton("删除检测项")footer_layout.addWidget(btn_delete)btn_alert = QPushButton("SMTP报警配置")footer_layout.addWidget(btn_alert)btn_proxy = QPushButton("代理IP")footer_layout.addWidget(btn_proxy)layout.addLayout(footer_layout)# 给窗体设置元素的排列方式self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)  # 实例化一个Application应用,所有的窗口均在其下运行window = MainWindow()  # 实例化窗口对象window.show()  # 窗口展示sys.exit(app.exec_())# app.exec_()运行主循环,并在退出时返回状态代码。# sys.exit(n)退出您的应用程序并返回n到父进程(通常是您的shell)

总结

大家喜欢的话,给个👍,点个关注!给大家分享更多计算机专业学生的求学之路!

版权声明:

发现你走远了@mzh原创作品,转载必须标注原文链接

Copyright 2023 mzh

Crated:2023-3-1

欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中
欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中
『未完待续』


相关文章:

『pyqt5 从0基础开始项目实战』02. 页面布局设计(保姆级图文)

目录弹性布局介绍导包和框架代码布局框架搭建1. 总体布局框架2. 顶部菜单布局3. form添加内容布局4. table数据展示布局5. footer底部菜单完整项目代码总结欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中 欢迎关注 『pyqt5 从0基础开始项目实战』 专栏&am…...

【Python机器学习】——平均中位数模式

Python机器学习——平均中位数模式 文章目录 Python机器学习——平均中位数模式一、Python 平均中位数模式一、Python 平均中位数模式 均值、中值和众数 从一组数字中我们可以学到什么? 在机器学习(和数学)中,通常存在三中我们感兴趣的值: 均值(Mean) - 平均值 中值(M…...

Windows窗口

Windows窗口 Unit01注册窗口类 01窗口类的概念 窗口类是包括了窗口的各种参数信息的数据结构每个窗口都具有窗口类,基于窗口类创建窗口每个窗口都具有一个名称,使用前必须注册到系统 02窗口类的分类 系统窗口类 系统已经定义好的窗口类,…...

Spring Transaction 源码解读

Spring Transaction 规范的maven坐标如下&#xff1a; <dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>...</version></dependency>该包提供了spring事务规范和默认的jta(ja…...

[Netty] Channel和ChannelFuture和ChannelFutureListener (六)

文章目录1.Channel介绍2.ChannelFuture接口介绍3.GenericFutureListener接口介绍1.Channel介绍 NIO的Channel与Netty的Channel 不一样 Netty重新设计了Channel接口,并且给予了很多不同的实现, Channel是Netty网络的抽象类, 除了NIO中Channel所包含的网络I/O操作, 主动建立和关…...

条件渲染

组件经常需要根据不同条件显示不同内容。在React中&#xff0c;你可以使用类似于if语句、&&和?:运算符的JavaScript语法有条件地呈现JSX。你将学到&#xff1a;如何根据条件返回不同的JSX如何有条件地包含或排除一段JSX在React代码库中常见的条件语法快捷方式有条件地…...

springboot(10)异步任务

文章目录1、SpringBoot异步任务1.1使用注解EnableAsync开启异步任务支持1.2使用Async注解标记要进行异步执行的方法1.3controller测试2.异步任务相关限制3.1自定义 Executor3.1.1应用层级&#xff1a;3.1.2方法层级&#xff1a;3.2自定义 Executor (第二种方式)4.1异常处理4.1.…...

清华大学开源的chatGLM-6B部署实战

Windows部署 win10 通过wsl部署 常见问题: torch.cuda.OutOfMemoryError: CUDA out of memory. 在Windows的系统环境变量中增加 变量名:PYTORCH_CUDA_ALLOC_CONF 变量值:max_split_size_mb:32 文档书写时使用3090 24G显存配置,其他规格酌情调整 32 至其他值,如未设置变…...

通过矩阵从整体角度搞懂快速傅里叶变换原理

离散傅里叶变换公式 公式 f[k]∑n0N−1g[n]e−i(2π/N)kn,其中(0<n<N)f[k]\sum_{n0}^{N-1}g[n]e^{-i(2\pi/N)kn}, 其中(0<n<N) f[k]n0∑N−1​g[n]e−i(2π/N)kn,其中(0<n<N) 逆变换公式 g[n]1N∑k0N−1f[k]ei(2π/N)kn,其中(0<k<N)g[n]\frac{1}{N}\…...

【C++从0到1】25、C++中嵌套使用循环

C从0到1全系列教程 1、实例代码 #include <iostream> // 包含头文件。 using namespace std; // 指定缺省的命名空间。int main() {// 超女分4个小组&#xff0c;每个小组有3名超女&#xff0c;在控制台显示每个超女的小组编号和组内编号。// 用一个循环…...

FastDFS与Nginx结合搭建文件服务器,并内网穿透实现公网访问

文章目录前言1. 本地搭建FastDFS文件系统1.1 环境安装1.2 安装libfastcommon1.3 安装FastDFS1.4 配置Tracker1.5 配置Storage1.6 测试上传下载1.7 与Nginx整合1.8 安装Nginx1.9 配置Nginx2. 局域网测试访问FastDFS3. 安装cpolar内网穿透4. 配置公网访问地址5. 固定公网地址5.1 …...

密集场景下的行人跟踪替代算法,头部跟踪算法 | CVPR 2021

一个不知名大学生&#xff0c;江湖人称菜狗 original author: Jacky LiEmail : 3435673055qq.com Time of completion&#xff1a;2023.4.8 Last edited: 2023.4.8 目录 摘要 主要内容 结果 这篇文章是CVPR 2021 的最新论文&#xff0c;文章的标题&#xff1a; 文章的主要内…...

Matlab与ROS(1/2)---服务端和客户端数据通信(五)

0. 简介 在前几讲我们讲了Matlab中的Message以及Topic的相关知识。而ROS主要支持的通信机制还有服务这一类。服务通过允许请求以及响应的通信方式&#xff0c;来给整个系统完成更紧密的耦合。服务客户端向服务服务器发送请求消息并等待响应。服务器将使用请求中的数据构造响应…...

数字化转型的避坑指南:细说数字化转型十二大坑

随着信息技术的快速发展&#xff0c;数字化转型已经成为许多企业发展的必经之路。然而&#xff0c;数字化转型过程中也存在许多坑&#xff0c;如果不谨慎处理&#xff0c;就可能导致企业陷入困境。本文将细说数字化转型的十二大坑&#xff0c;并提供相应的避坑指南。 1、不了解…...

pt05Encapsulationinherit

Encapsulation &inherit 封装继承 封装 向类外提供必要的功能&#xff0c;隐藏实现的细节, 代码可读性更高优势&#xff1a;简化编程&#xff0c;使用者不必了解具体的实现细节&#xff0c;只需要调用对外提供的功能。私有成员&#xff1a;作用&#xff1a;无需向类外提供…...

面向对象编程(基础)9:封装性(encapsulation)

目录 9.1 为什么需要封装&#xff1f; 而“高内聚&#xff0c;低耦合”的体现之一&#xff1a; 9.2 何为封装性&#xff1f; 9.3 Java如何实现数据封装 9.4 封装性的体现 9.4.1 成员变量/属性私有化 实现步骤&#xff1a; 成员变量封装的好处&#xff1a; 9.4.2 私有化…...

fate-serving-server增加取数逻辑并源码编译

1.什么是fate-serving-server? FATE-Serving 是一个高性能、工业化的联邦学习模型服务系统&#xff0c;专为生产环境而设计,主要用于在线推理。 2.fate-serving-server源码编译 下载fate-serving-serving项目&#xff08;GitHub - FederatedAI/FATE-Serving: A scalable, h…...

循环队列、双端队列 C和C++

队列 目录 概念 实现方式 顺序队列 循环队列 队列的数组实现 用循环链表实现队列 STL 之 queue 实现队列 STL 之 dequeue 实现双端队列 概念 队列是一种特殊的线性表&#xff0c;它只允许在表的前端&#xff08;称为队头&#xff0c;front&#xff09;进行删除操作…...

正则表达式(语法+例子)

文章目录一、介绍二、语法1、匹配字符2、表示数量的字符3、边界字符4、其他字符5、转义字符三、例子1、邮箱2、用逗号分隔的数字集合1,23、允许一位小数4、20yy-mm-dd日期格式5、手机号6、匹配html、xml标签一、介绍 正则表达式&#xff08;Regular Expression&#xff09;&am…...

Properties和IO流集合的方法

方法名说明void load(InputStream inStream)从输入字节流读取属性列表&#xff08;键和元素&#xff09;void load(Reader reader)从输入字符流读取属性列表&#xff08;键和元素对&#xff09;void store(OutputStream out,String comments)将此属性列表&#xff08;键和元素对…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

c# 局部函数 定义、功能与示例

C# 局部函数&#xff1a;定义、功能与示例 1. 定义与功能 局部函数&#xff08;Local Function&#xff09;是嵌套在另一个方法内部的私有方法&#xff0c;仅在包含它的方法内可见。 • 作用&#xff1a;封装仅用于当前方法的逻辑&#xff0c;避免污染类作用域&#xff0c;提升…...