PyQt5桌面应用开发(10):界面布局基本支持

news2024/12/23 18:43:47

本文目录

  • PyQt5桌面应用系列
  • 布局
  • 利器
  • 游戏
  • 总结

PyQt5桌面应用系列

  • PyQt5桌面应用开发(1):需求分析
  • PyQt5桌面应用开发(2):事件循环
  • PyQt5桌面应用开发(3):并行设计
  • PyQt5桌面应用开发(4):界面设计
  • PyQt5桌面应用开发(5):对话框
  • PyQt5桌面应用开发(6):文件对话框
  • PyQt5桌面应用开发(7):文本编辑+语法高亮与行号
  • PyQt5桌面应用开发(8):从QInputDialog转进到函数参数传递
  • PyQt5桌面应用开发(9):经典布局QMainWindow
  • PyQt5桌面应用开发(10):界面布局基本支持

布局

布局是设计报表和交互中的重要工作。但是布局的内涵有两个层面上的:总体布局和界面布局。

从报表设计的角度出发,布局应该把最重要的信息显示在最显眼的位置,把次要的信息放在次显眼的位置,把不重要的信息放在不显眼的位置。报表设计始终还是要围绕报表的目的(也就是用户利用数据、信息进行决策的目的)来进行的。围绕一个决策来布局信息的分类、汇总、分析、比较、评价、预测等功能,这些功能的实现都是为了帮助用户做出决策。

从交互设计的角度出发,应该把核心、重要的功能放在最显眼的位置,把次要的功能放在次显眼的位置,把不重要的功能放在不显眼的位置,这与报表设计相同;此外,还应该把相互关联的操作放在一起,把相互独立的功能分开。

这个在实际的设计中,可以通过分组、分页、分栏、分区等方式来实现报表信息和交互的总体布局。

而在较低的一个层次上,则是一个具体的界面上的控件如何定位、缩放、对齐,控件上相关的控件之间如何相互协调。这个层次上的布局,可以通过控件的定位位置、几何尺寸来描述。最基础的布局就是控件的位置和尺寸,这也叫绝对位置布局。在这个基础上,还能实现相对位置布局,通过以某个控件的位置和尺寸为基准,把其它控件的位置和尺寸转换相对坐标系来描述。这都是直接和更底层的布局算法,当然所有的更抽象的布局都会归结成相对布局算法和绝对布局算法。

  1. 抽象布局
  2. 相对布局
  3. 绝对布局

而抽象布局是在人类认知的概念中对一组控件的排列进行抽象的描述,比如一列、一行、一个网格、一个表格、一个树形结构,等等。抽象的层次较高的界面布局,就更加便于人类使用,为思考布局提供了工具,但是也限制了布局的灵活性;较低层次的布局,需要更多的精力来思考,但是也提供了更强大的功能和灵活性。

大部分的UI开发工具包,都提供了一定层次的抽象布局工具。例如JavaFX、Qt、Web前端工具中都有类似的概念和工具支持。Qt5提供的布局工具并不丰富,但是也足够形成复杂的界面。

利器

Qt5提供布局的方式是每一个QWidget都有一个QLayout对象,通过setLayout方法来设置。QWidget的子节点,通过加入布局类中来获得自动计算相对位置、大小和绝对位置大小的能力。Qt5中最常用的布局类有四个:QHBoxLayout、QVBoxLayout、QGridLayout、QFormLayout。

在这里插入图片描述

其中QHBoxLayout和QVBoxLayout是QBoxLayout的子类,这三个类描述的就是一行或者一列控件。当控件排成一列时,其x方向的位置和尺寸都保持一致,y方向的位置成线性增长,尺寸通过按比例伸缩、固定最小尺寸、固定最大尺寸、扩张、最小化等概念来计算。最后这个部分通常称为sizePolicy,也就是伸缩策略。同样,当控件拍成一行时,其y方向的位置和尺寸都保持一致,x方向的位置成线性增长,尺寸通过按比例伸缩、固定最小尺寸、固定最大尺寸、扩张、最小化等概念来计算。

QGridLayout是QLayout的子类,它描述的是一个网格布局,也就是一个二维的布局。它的每一个子控件都有一个行号和列号,通过这两个号码来描述控件的位置。每一个行和列都有一个伸缩策略,通过这个策略来计算控件的尺寸。QGridLayout的伸缩策略是通过行和列的伸缩策略来计算的,而不是通过每一个控件的伸缩策略来计算的。

QFormLayout是QLayout的子类,它描述的是一个表格布局,也就是一个二维的布局。它的每一个子控件都有一个行号和列号,通过这两个号码来描述控件的位置。每一个行和列都有一个伸缩策略,通过这个策略来计算控件的尺寸。QFormLayout的伸缩策略是通过行和列的伸缩策略来计算的,而不是通过每一个控件的伸缩策略来计算的。

最后还有一个我不知道有什么用的QStackedLayout,这个布局类描述的是一个堆栈布局,也就是一堆控件,只有一个控件是可见的,其它的控件都是不可见的。这个布局类还没有提供显式的切换方案,必须自己调用QStackedLayout的setCurrentIndex方法来切换。通常会把这个方法作为一个槽函数绑定到某个信号上。

游戏

这里我们设计一个展示这几中布局的小程序。

  • 报表:每种布局的展示;
  • 报表:QStackLayout自动(定时)切换控件。
  • 交互:切换布局;

在这里插入图片描述

程序源代码如下。

import random
import sys
from functools import partial
from typing import Union

from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QFormLayout, \
    QStackedLayout, QComboBox, QLabel, QMainWindow, QDockWidget

# module shared variables
colors = ['yellow', 'red', 'cyan', 'green', 'white',
          'gray', 'orange', 'darkgray', 'transparent']
name_layouts = {'vbox': QVBoxLayout,
                'hbox': QHBoxLayout,
                'grid': QGridLayout,
                'form': QFormLayout,
                'stacked': QStackedLayout}

timer: Union[QTimer, None] = None


# module shared functions
def show_layout(parent: QMainWindow, layout_short_name: str):
    random.shuffle(colors)

    widgets = [QLabel(c, win) for c in colors]

    for i, (c, w) in enumerate(zip(colors, widgets)):
        w.setStyleSheet(f"background-color: {c}")
        w.setAlignment(Qt.AlignCenter)
        w.setFont(QFont("SimHei", 24))

    widget = QWidget(parent)

    if not (layout_short_name in name_layouts):
        raise ValueError(
            f"{layout_short_name} not in {list(name_layouts.keys())}")
    layout = name_layouts[layout_short_name]()

    for i, w in enumerate(widgets):
        if layout_short_name == 'grid':
            layout.addWidget(w, i // 3, i % 3)
        elif layout_short_name == 'form':
            layout.addRow(w.text() + ":", w)
        else:
            layout.addWidget(w)

    global timer
    if timer is not None:
        timer.stop()
        timer = None

    if layout_short_name == 'stacked':
        timer = QTimer(parent)

        def change_layout():
            try:
                layout.setCurrentIndex((layout.currentIndex() + 1) % layout.count())
            except Exception as e:
                pass

        timer.timeout.connect(change_layout)
        timer.start(1000)

    widget.setLayout(layout)
    parent.setCentralWidget(widget)


class QCycleComboBox(QComboBox):
    """
    A combobox that cycles through its items when the mouse wheel is used, or the up/down keys are pressed.
    """

    def __init__(self, parent: QWidget = None) -> None:
        super(QCycleComboBox, self).__init__(parent)

    def wheelEvent(self, event):
        if event.angleDelta().y() > 0:
            self.setCurrentIndex((self.currentIndex() - 1) % self.count())
        else:
            self.setCurrentIndex((self.currentIndex() + 1) % self.count())

    def keyPressEvent(self, e) -> None:
        if e.key() == Qt.Key_Up:
            self.setCurrentIndex((self.currentIndex() - 1) % self.count())
        if e.key() == Qt.Key_Down:
            self.setCurrentIndex((self.currentIndex() + 1) % self.count())
        else:
            return super(QCycleComboBox, self).keyPressEvent(e)


if __name__ == '__main__':
    app = QApplication([])
    win = QMainWindow()
    
    choice = QCycleComboBox(win)
    choice.addItems(name_layouts.keys())
    dock = QDockWidget('Layouts selection', win)
    dock.setWidget(choice)
    dock.setFeatures(QDockWidget.NoDockWidgetFeatures)
    win.addDockWidget(Qt.TopDockWidgetArea, dock)
    choice.currentTextChanged.connect(partial(show_layout, win))
    show_layout(win, 'vbox')

    win.setWindowTitle("Layouts")
    win.setGeometry(100, 100, 800, 600)
    win.show()

    sys.exit(app.exec_())

这个程序的结构和逻辑非常简单,不再赘述。

总结

  1. 布局分为两种层次,高层次布局和界面布局;
  2. 界面布局分为:概念布局、相对布局和绝对布局;
  3. Qt5的常用布局类有:QVBoxLayout、QHBoxLayout、QGridLayout、QFormLayout和QStackedLayout。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/500159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

星火认知大模型发布,科大讯飞入场科技巨头AI大战?

自从ChatGPT横空出世,一个更美好的世界开始向我们招手。为了推开新时代的大门,几乎所有人工智能厂商都投入了最大的热情逐浪AIGC。 5月6日,科大讯飞召开了“讯飞星火认知大模型”成果发布会。发布会现场,科大讯飞董事长刘庆峰展示…

Hadoop[3.3.x]-1本地环境搭建

环境:Mac Hadoop版本:Apache Hadoop 3.3.4 由于hadoop依赖java环境,所以需要事先安装好java。 Hadoop下载 进入官网进行下载Apache Hadoop 下载后解压到自己的规划的目录。 环境文件配置 Hadoop相关配置文件都在目录的../hadoop-3.3.4/et…

Vulkan 总结

一、Vulkan 对象简介 1、VKInstance 这个对象是我们 Vulkan api 的一个对象,用于通过 Instance 我们与 Vulkan 底层进行交互。 2、VkPhysicalDevice 对应我们当前设备(PC、手机)的一个显卡硬件(GPU ),有的…

如何导出cloudflare warp内部存的私钥和token

结论:管理员身份运行 mimikatz:https://github.com/gentilkiwi/mimikatz/releases/tag/2.2.0-20220919 然后输入: privilege::debug (提升权限到:NT-AUTHORITY\SYSTEM)以及sekurlsa::credman 就能看到&…

Java中的反射(通过反射获取类的结构、invoke方法、获取注解)

文章目录 1. 创建运行时类的对象2. 获取运行时类的完整结构2.1 相关API2.2 获取所有的属性及相关细节2.3 获取所有的方法及相关细节2.4 获取其他结构(构造器、父类、接口、包、注解等)2.5 获取泛型父类信息2.6 获取内部类或外部类信息2.7 总 结 3. 调用运行时类的指定结构3.1 调…

HDOJ 1022 Train Problem Ⅰ 模拟栈操作

🍑 OJ专栏 🍑 HDOJ 1022 Train Problem Ⅰ 输入 3 123 321 3 123 312输出 Yes. in in in out out out FINISH No. FINISH🍑 思路 🍤 栈顶元素与目标元素不匹配就进栈,匹配就出栈 🍤 匹配完:y…

es 7.0.8 常用操作(windwos版本安装,索引crud操作)

一 es7.x的核心 1.1 es的核心概念 1.ES 里的 Index 可以看做一个库(名称必须为小写),而 Types 相当于表,Documents 则相当于表的行。 2.这里 Types 的概念已经被逐渐弱化,Elasticsearch 6.X 中,一个 index 下已经只能包含一个…

分布式搜索引擎——elasticsearch搜索功能

DSL查询语法 DSL Query的分类 Elasticsearch提供了基于JSON的DSL (Domain Specific Language)来定义查询。常见的查询类型包括: 查询所有:查询出所有数据,一般测试用。例如:match_all全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排…

Java 基础进阶篇(九)—— Java集合详细总结

文章目录 一、集合类体系结构二、Collection系列集合2.1 Collection 集合体系2.2 Collection 集合体系特点2.3 Collection 常用API2.4 Collection 集合的遍历方式2.4.1 方式一:迭代器2.4.2 方式二:foreach(增强for循环)2.4.3 方式…

Java8新特性—Optional类

前言 Java 8中引入了一个新的Optional类,它可以让开发人员更好地处理可能为空的值。Optional类提供了一种方式,可以更加优雅地处理null值,并在运行时避免NullPointerException异常的出现。本文将介绍Optional类的基本语法、使用场景和示例。…

Java 基础进阶篇(十)—— 泛型与可变参数

文章目录 一、泛型概述二、泛型的定义2.1 泛型类2.2 泛型方法2.3 泛型接口 三、泛型深入3.1 泛型通配符3.2 泛型上下限3.3 案例:定义一个 “所有车量进行比赛” 的方法 四、可变参数 一、泛型概述 泛型是 JDK5 中引入的特性,可以在编译阶段约束操作的数…

Linux应用开发:进程间通信 System V

目录 1、查看删除IPC对象 1.1 IPC对象 1.2 ipcs 命令查看系统中的 IPC 对象 1.3 ipcrm 命令删除系统中的 IPC 对象 2、共享内存 2.1 共享内存简介 2.2 共享内存相关API 2.2.1 shmget:创建共享内存 2.2.2 shmat:映射共享内存 2.2.3 shmdt&#…

A40i使用笔记:安装python3.7(素装)

一、前言 项目需求,要用到python3以上,就研究了一下如何安装python,这里也是分享出来安装方法,为各位技术研发人员减少不必要的时间损耗 本文没有安装python其他依赖库,因为我也是在摸索中,所以只限指导到…

「程序员的浪漫」使用 Html、Css、JavaScript 实现 DIY 生日祝福页面 快发给你的朋友吧

前言 从网上搜集整理修改的好用网页生日祝福版本 特点 将三剑客放进一个 Html 文件 点开即用封装好 修改几个参数就可以 DIYDIY 的地方有注释 预览 …省略几张图 源码 有用的话点个 star 不迷路谢谢!https://github.com/yangzi0210/Happy-birthday-page

领先的项目协作管理软件OpenProject

本文软件由网友 不长到一百四誓不改名 推荐; 什么是 OpenProject ? OpenProject 是一个开源、基于 Web 的项目管理系统,提供了免费的社区版和收费的企业版。OpenProject 拥有完善的文档,API,及丰富的功能,可…

SlickEdit for Windows and Linux crack

SlickEdit for Windows and Linux crack 现在可以在“新建注释”对话框中对颜色进行排序,使调色板中的颜色阵列看起来更符合逻辑。 在拆分或扩展行注释时添加了撤消步骤,这样您只需点击“撤消”一次即可撤消行注释扩展。 已更新VHDL颜色编码,…

【网络】- 计算机网络体系结构 - OSI七层模型、TCP/IP四层(五层)协议

目录 一、概述 二、计算机网络体系结构的形成  👉2.1 分层的网络体系结构  👉2.2 OSI 参考模型  👉2.3 TCP/IP - 事实的国际标准 三、OSI 参考模型 四、TCP/IP 协议 一、概述 但凡学习计算机网络知识,肯定绕不过网络协议的&…

Java 基础进阶篇(八)—— 常用 API

文章目录 一、Object 类二、Objects 工具类三、Math 类四、System 类五、BigDecimal 类 一、Object 类 一个类要么默认继承了 Object 类,要么间接继承了 Object 类,Object 类是 java 中的祖宗类。Object 类的方法是一切子类都可以直接使用的。 因此&…

7.4 电子信息系统预处理中所用放大电路

在电子信息系统中,通过传感器或其它途径所采集的信号往往很小,不能直接进行运算、滤波等处理,必须进行放大。 一、仪表放大器 集成仪表放大器,也称为精密放大器,用于弱信号放大。 1、仪表放大器的特点 在测量系统中…

Binder“一次拷贝“你真懂吗?

前言 谈到到Binder相对于其他传统进程间通信方式的优点的时候,我们总会说Binder只需要做“一次拷贝”就行了,而其他传统方式需要“两次拷贝”。这确实是Binder的优点,但再进一步思考就会碰到两个问题: 这所谓的“一次拷贝”到底…