Qt-布局管理

news2024/12/25 1:01:56

布局管理

Qt布局系统提供了一种简单而强大的方式,可以自动在窗口组件中排列子窗口组件,以确保它们充分利用可用空间。

介绍

Qt包含了一组布局管理类,用于描述窗口组件在应用程序用户界面中的布局方式。当可用空间发生变化时,这些布局会自动定位和调整窗口组件的大小,确保它们的排列一致,并且用户界面作为一个整体保持可用。

所有QWidget子类都可以使用布局来管理它们的子组件。函数QWidget::setLayout()为部件应用布局。当以这种方式在部件上设置布局时,它将负责以下任务:

  • 子部件的定位
  • 合理的窗口默认大小
  • 合理的窗口最小尺寸
  • 调整处理
  • 内容变更时自动更新:
    • 子部件的字体大小、文本或其他内容
    • 隐藏或显示子部件
    • 移除子部件

Qt的布局类

Qt的布局类是为手写的c++代码设计的,为了简单起见,可以用像素来指定测量值,所以它们很容易理解和使用。使用Qt Designer创建的表单生成的代码也使用了layout类。在尝试设计表单时,Qt Designer非常有用, 因为它避免了用户界面开发中通常涉及的编译、链接和运行循环。

QBoxLayout

水平或垂直排列子部件

QButtonGroup

容器来组织按钮小部件组

QFormLayout

管理输入小部件的表单及其相关标签

QGraphicsAnchor

表示QGraphicsAnchorLayout中两个项目之间的锚点

QGraphicsAnchorLayout

可以在图形视图中将小部件固定在一起的布局

QGridLayout

在网格中布局小部件

QGroupBox

带标题的组框框架

QHBoxLayout

水平排列小部件

QLayout

几何图形管理器的基类

QLayoutItem

QLayout操作的抽象项

QSizePolicy

描述水平和垂直调整大小策略的布局属性

QSpacerItem

布局中的空白空间

QStackedLayout

一次只能看到一个小部件的小部件堆栈

QStackedWidget

一次只能看到一个小部件的小部件堆栈

QVBoxLayout

垂直排列部件

QWidgetItem

表示小部件的布局项

使用布局的技巧

使用布局时,在构造子部件时不需要传递父组件。布局将自动重新设置小部件的父部件(使用QWidget::setParent()),使它们成为安装了布局的小部件的子部件。

注意:布局中的部件是安装布局的部件的子部件,而不是布局本身的子部件。部件只能有其他部件作为父部件,而不能有布局。

你可以在布局上使用addLayout()嵌套布局;然后,内部布局成为它插入的布局的子布局。

向布局中添加部件

向布局中添加部件时,布局过程如下所示:

  1. 所有小部件最初将根据它们的QWidget::sizePolicy()和QWidget::sizeHint()分配一定的空间。
  2. 如果任何小部件设置了拉伸因子,且其值大于零,则按其拉伸因子的比例为它们分配空间(将在下面解释)。
  3. 如果任何部件将拉伸因子设置为0,则只有在没有其他部件需要空间的情况下,它们才会获得更多空间。其中,空间首先分配给具有扩展大小策略的部件。
  4. 任何分配的空间小于其最小大小(如果没有指定最小大小,则为最小大小提示)的部件都会分配其所需的最小大小。(部件不需要有最小尺寸或最小尺寸提示,在这种情况下,拉伸因子是它们的决定因子。)
  5. 任何分配的空间超过其最大尺寸的部件都会分配它们所需的最大尺寸空间。(部件不需要有最大尺寸,在这种情况下,拉伸因子是它们的决定因子。)

延伸的因素

widget通常在创建时没有设置任何拉伸因子。当它们在布局中被布局时,小部件根据它们的QWidget::sizePolicy()或它们的最小大小提示(以较大的为准)获得一份空间份额。拉伸因子用于改变部件之间的空间比例。

如果我们使用没有设置拉伸因子的QHBoxLayout布局三个窗口组件,我们将得到如下布局:

如果我们对每个小部件应用拉伸因子,它们将按比例布局(但绝不会小于它们的最小尺寸提示),例如:

布局中的自定义部件

在创建自己的窗口组件类时,还应该告知它的布局属性。如果组件使用了Qt的布局,这一点已经解决了。如果部件没有任何子部件,或者使用手动布局,则可以使用以下任何或所有机制更改部件的行为:

  • 重新实现QWidget::sizeHint()以返回widget的首选大小。
  • 重新实现QWidget::minimumSizeHint(),以返回widget可以拥有的最小尺寸。
  • 调用QWidget::setSizePolicy()来指定小部件的空间需求。

每当大小提示、最小大小提示或大小策略发生变化时,调用QWidget::updateGeometry()。这将导致布局重新计算。对QWidget::updateGeometry()的多次连续调用只会导致一次布局重新计算。

如果小部件的首选高度取决于它的实际宽度(例如,具有自动断字功能的标签),则在小部件的大小策略中设置height-for-width标志,并重新实现QWidget::heightForWidth()。

即使您实现了QWidget::heightForWidth(),提供一个合理的sizeHint()仍然是一个好主意。

有关实现这些函数的进一步指导,请参阅Qt季度文章Trading Height For Width。

布局问题

在标签小部件中使用富文本可能会给其父小部件的布局带来一些问题。当标签被换行时,Qt的布局管理器处理富文本的方式会导致问题。

在某些情况下,parent布局被设置为QLayout::FreeResize模式,这意味着它将不能适应其内容的布局以适应小尺寸的窗口,甚至阻止用户使窗口太小而无法使用。这可以通过对有问题的部件进行子类化,并实现适当的sizeHint()和minimumSizeHint()函数来解决。

在某些情况下,当向部件添加布局时,它是相关的。当你设置QDockWidget或QScrollArea

的widget时(使用QDockWidget::setWidget()和QScrollArea::setWidget()), widget上必须已经设置了布局。否则,部件将不可见。

手动布局

如果你正在制作一个独一无二的特殊布局,你也可以像上面描述的那样制作一个自定义部件。重新实现QWidget::resizeEvent()来计算所需的大小分布,并在每个子节点上调用setGeometry()。

当布局需要重新计算时,widget将获得一个类型为QEvent::LayoutRequest的事件。重新实现QWidget::event()来处理QEvent::LayoutRequest事件。

如何编写自定义布局管理器

手动布局的另一种选择是通过继承QLayout来编写自己的布局管理器。Border布局和Flow布局的例子展示了如何做到这一点。

这里我们详细介绍一个例子。CardLayout类的灵感来自于同名的Java布局管理器。它将项目(窗口组件或嵌套布局)置于彼此之上,每个项目通过QLayout::spacing()进行偏移。

要编写自己的布局类,必须定义以下内容:

  • 存储由布局处理的项的数据结构。每一项都是一个QLayoutItem。在这个例子中,我们将使用QVector。
  • addItem(),如何向布局中添加项。
  • setGeometry(),如何执行布局
  • sizeHint(),布局的首选大小。
  • itemAt(),如何遍历布局
  • takeAt():从布局中删除元素的方法。

大多数情况下,还需要实现minimumSize()。

#ifndef CARD_H
#define CARD_H

#include <QtWidgets>
#include <QVector>

class CardLayout : public QLayout
{
public:
    CardLayout(int spacing): QLayout()
    { setSpacing(spacing); }
    CardLayout(int spacing, QWidget *parent): QLayout(parent)
    { setSpacing(spacing); }
    ~CardLayout();

    void addItem(QLayoutItem *item) override;
    QSize sizeHint() const override;
    QSize minimumSize() const override;
    int count() const override;
    QLayoutItem *itemAt(int) const override;
    QLayoutItem *takeAt(int) override;
    void setGeometry(const QRect &rect) override;

private:
    QVector<QLayoutItem*> m_items;
};
#endif

首先定义count()来获取列表中的项数。

int CardLayout::count() const
{
    // QVector::size() returns the number of QLayoutItems in m_items
    return m_items.size();
}

然后定义两个遍历布局的函数:itemAt()和takeAt()。布局系统内部使用这些函数来处理部件的删除。应用程序程序员也可以使用它们。

itemAt()返回指定索引处的元素takeAt()删除给定索引处的元素,并返回它。在这种情况下,我们使用列表索引作为布局索引。在其他数据结构更复杂的情况下,我们可能需要花费更多的精力来定义元素的线性顺序。

QLayoutItem *CardLayout::itemAt(int idx) const
{
    // QVector::value() performs index checking, and returns nullptr if we are
    // outside the valid range
    return m_items.value(idx);
}

QLayoutItem *CardLayout::takeAt(int idx)
{
    // QVector::take does not do index checking
    return idx >= 0 && idx < m_items.size() ? m_items.takeAt(idx) : 0;
}

addItem()实现了布局项的默认放置策略。必须实现该函数。它由QLayout::add()使用,由QLayout构造函数使用,该构造函数接受一个布局作为父布局。如果您的布局有需要参数的高级放置选项,则必须提供额外的访问函数,例如QGridLayout::addItem()、QGridLayout::addWidget()和QGridLayout::addLayout()的跨行和跨列重载。

void CardLayout::addItem(QLayoutItem *item)
{
    m_items.append(item);
}

布局承担了添加项目的责任。由于QLayoutItem不继承QObject,我们必须手动删除这些项。在析构函数中,使用takeAt()从列表中移除每一项,然后将其删除。

CardLayout::~CardLayout()
{
     QLayoutItem *item;
     while ((item = takeAt(0)))
         delete item;
}

setGeometry()函数实际执行布局。作为参数提供的矩形不包括margin()。如果相关,使用spacing()作为项目之间的距离。

void CardLayout::setGeometry(const QRect &r)
{
    QLayout::setGeometry(r);

    if (m_items.size() == 0)
        return;

    int w = r.width() - (m_items.count() - 1) * spacing();
    int h = r.height() - (m_items.count() - 1) * spacing();
    int i = 0;
    while (i < m_items.size()) {
        QLayoutItem *o = m_items.at(i);
        QRect geom(r.x() + i * spacing(), r.y() + i * spacing(), w, h);
        o->setGeometry(geom);
        ++i;
    }
}

sizeHint()和minimumSize()在实现上通常非常相似。两个函数返回的大小应该包括spacing(),但不包括margin()。

QSize CardLayout::sizeHint() const
{
    QSize s(0, 0);
    int n = m_items.count();
    if (n > 0)
        s = QSize(100, 70); //start with a nice default size
    int i = 0;
    while (i < n) {
        QLayoutItem *o = m_items.at(i);
        s = s.expandedTo(o->sizeHint());
        ++i;
    }
    return s + n * QSize(spacing(), spacing());
}

QSize CardLayout::minimumSize() const
{
    QSize s(0, 0);
    int n = m_items.count();
    int i = 0;
    while (i < n) {
        QLayoutItem *o = m_items.at(i);
        s = s.expandedTo(o->minimumSize());
        ++i;
    }
    return s + n * QSize(spacing(), spacing());
}

进一步指出

  • 这个自定义布局不处理宽度对应的高度。
  • 我们忽略QLayoutItem::isEmpty();这意味着布局将把隐藏的部件视为可见的。
  • 对于复杂的布局,缓存计算值可以大大提高速度。在这种情况下,实现QLayoutItem::invalidate()来标记缓存的数据是脏的。
  • 调用QLayoutItem::sizeHint()等方法的开销可能很大。因此,如果以后在同一个函数中还需要它,你应该将它的值存储在一个局部变量中。
  • 你不应该在同一个函数中对同一项调用两次QLayoutItem::setGeometry()。如果项目有多个子部件,则此调用可能非常昂贵,因为布局管理器每次都必须执行完整的布局。相反,计算几何形状,然后设置它。(这不仅适用于布局,例如,如果你实现了自己的resizeEvent(),也应该这样做。)

布局的例子

许多Qt Widgets示例已经使用了布局,但是,存在一些示例来展示各种布局

Address Book Tutorial

介绍GUI编程,展示如何组合一个简单但功能齐全的应用程序。

Border Layout Example

演示如何沿边框排列子部件。

Calculator Example

该示例展示了如何使用信号和槽来实现计算器小部件的功能,以及如何使用QGridLayout在网格中放置子小部件。

Calendar Widget Example

CalendarWidget示例展示了QCalendarWidget的用法。

Echo Plugin Example

这个例子展示了如何创建一个Qt插件。

Flow Layout Example

展示如何为不同的窗口大小排列小部件

Image Composition Example

展示了QPainter中的合成模式是如何工作的。

Menus Example

菜单示例演示了如何在主窗口应用程序中使用菜单。

Simple Tree Model Example

简单树模型示例展示了如何在Qt的标准视图类中使用分层模型。

Sub-Attaq

这个例子展示了Qt结合动画框架和状态机框架来创建游戏的能力。

Layout Management | Qt Widgets 5.15.17

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

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

相关文章

Typora 写文章时修改图片保存位置

文章目录 为什么要修改图片位置修改图片位置1.打开偏好设置2.修改路径3.再写文章发现图片已经变成了相对路径 为什么要修改图片位置 默认位置不好找 如何修改呢&#xff1f; 修改图片位置 1.打开偏好设置 文件 > 偏好设置 2.修改路径 图像 > 插入图片时 按照下图…

C# 集合(Collection)

集合&#xff08;Collection&#xff09;类是专门用于数据存储和检索的类。这些类提供了对栈&#xff08;stack&#xff09;、队列&#xff08;queue&#xff09;、列表&#xff08;list&#xff09;和哈希表&#xff08;hash table&#xff09;的支持。大多数集合类实现了相同…

超市售货管理系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;会员管理&#xff0c;供应商信息管理&#xff0c;商品管理&#xff0c;出入库管理&#xff0c;公告管理&#xff0c;轮播图信息 微信端账号功能包括&#xff1a;系统首页&#xff0c;公告&#xff0c;…

Midjourney 随机风格 (Style Random),开启奇幻视觉之旅

作者:老余捞鱼 原创不易,转载请标明出处及原作者。 写在前面的话: Midjourney 最近推出了 "Style Random"(随机风格),这项功能可以让我们使用独特的随机 sref 代码创建图像,从而每次都能获得不同的美感。通过对这些功能的探索和尝试,我发现了一些很棒…

vscode安装使用plantuml插件

使用 VSCode 插件 如果你在 Visual Studio Code 中使用 PlantUML 插件&#xff0c;你可以按照以下步骤生成图片&#xff1a; 安装 PlantUML 插件&#xff1a; 在 VSCode 的扩展市场中搜索并安装 PlantUML 插件。 配置插件&#xff1a; 打开设置&#xff0c;确保插件配置正确。…

【Unity小工具】Image组件宽度、高度自适应

Unity开发中&#xff0c;用同一个Image进行动态加载不同尺寸的图片&#xff0c;在显示上会有形变此工具可以进行Image的宽度、高度自适应 实现原理 获取Image原始尺寸&#xff08;sizeDelta&#xff09;获取图片原始尺寸&#xff08;spriteSizeDelta&#xff09;公式&#xff…

PDF标准详解(四)——图形操作符

上一节&#xff0c;我们了解了PDF中cm操作符&#xff0c;它是定义变换矩阵的。同时也了解到re是创建一个矩阵的。上一节也说过&#xff0c;它用来构建一个路径&#xff0c;具体什么是路径&#xff0c;路径有什么作用呢&#xff1f;这些将在本节给出解释 图形操作符是用来在pdf…

移远通信高端5G智能模组SG560D-NA率先通过PTCRB认证

近日&#xff0c;移远通信宣布&#xff0c;其基于高通QCM6490平台打造的高端5G智能模组SG560D-NA顺利通过PTCRB认证。 在此之前&#xff0c;该模组还获得了美国FCC和加拿大IC认证&#xff0c;这意味着&#xff0c;其已完全满足北美地区的相关标准和规定&#xff0c;能够支持相关…

pdf压缩到指定大小需要怎么压缩?2024快速进行文件压缩的软件合集

pdf压缩到指定大小需要怎么压缩&#xff1f;2024快速进行文件压缩的软件合集 当你需要将PDF文件压缩到指定的大小时&#xff0c;选择适当的软件和方法可以帮助你在保持文件质量的同时&#xff0c;尽可能地减小文件体积。以下是五款可以帮助你快速压缩PDF文件并控制其大小的软件…

芯片散热设计

目录 摘要 散热方式分类 1.传导 2.对流 对流换热系数 对流方式 3.辐射 热阻 散热器 作用 材质 底部厚度 鳍片 表面处理 压力设计 界面材料 相关标准 摘要 散热设计是硬件设计中的进阶内容&#xff0c;掌握散热原理和设计要点是很有必要的。 散热方式分类 散…

【C++二分查找】1818. 绝对差值和

本文涉及的基础知识点 C二分查找 LeetCode1818. 绝对差值和 给你两个正整数数组 nums1 和 nums2 &#xff0c;数组的长度都是 n 。 数组 nums1 和 nums2 的 绝对差值和 定义为所有 |nums1[i] - nums2[i]|&#xff08;0 < i < n&#xff09;的 总和&#xff08;下标从 …

Java获取小程序码示例(三种小程序码)

首先我们可以看到官方文档上是有三种码的 获取小程序码 这里特别要注意的是第一种和第三种是有数量限制的&#xff0c;所以大家生成的时候记得保存&#xff0c;也不要一直瞎生成 还有一点要注意的是第一种和第二种是太阳码 第三种是方形码 好了直接上代码 这里要注意&#xff…

南京网站设计手机用的网站

近年来&#xff0c;随着移动互联网的快速发展&#xff0c;越来越多的用户通过手机浏览网页&#xff0c;这使得网站设计逐渐向移动端倾斜。在南京&#xff0c;网站设计特别注重适配手机端&#xff0c;这不仅是用户体验的提升&#xff0c;也是市场竞争的需要。一个响应式的网站能…

深度评测热门翻译工具,携手你的翻译得力助手

随着互联网技术的飞速发展&#xff0c;全球化交流日益频繁&#xff0c;跨语言沟通的需求也随之激增。对于外语水平有限的朋友来说&#xff0c;翻译器是一个必不可少的工具。今天我就分享几款我用的翻译器吧。 1.福晰在线翻译 链接直达>>https://fanyi.pdf365.cn/doc …

Java语言的Netty框架+云快充协议1.5+充电桩系统+新能源汽车充电桩系统源码

介绍 云快充协议云快充1.5协议云快充1.6云快充协议开源代码云快充底层协议云快充桩直连桩直连协议充电桩协议云快充源码 软件架构 1、提供云快充底层桩直连协议&#xff0c;版本为云快充1.5&#xff0c;对于没有对接过充电桩系统的开发者尤为合适&#xff1b; 2、包含&…

WebAPI (一)DOM树、DOM对象,操作元素样式(style className,classList)。表单元素属性。自定义属性。间歇函数定时器

文章目录 Web API基本认知一、 变量声明二、 DOM1. DOM 树2. DOM对象3. 获取DOM对象(1)、选择匹配的第一个元素(2)、选择匹配多个元素 三、 操作元素1. 操作元素内容2. 操作元素属性(1)、常用属性&#xff08;href之类的&#xff09;(2)、通过style属性操作CSS(3)、通过类名(cl…

Vivado 约束

步骤5&#xff1a;保存约束 约束管理是设计流程的重要一步&#xff0c;Vivado设计套件 为您提供了在现有约束文件中添加新约束、覆盖的灵活性 现有约束&#xff0c;或创建新的约束文件以跟踪设计更改或完成 缺少约束。 您为设计创建了一些定时异常&#xff0c;但这些异常仅存在…

​​NIFI汉化_替换logo_二次开发_Idea编译NIFI最新源码_详细过程记录_全解析_Maven编译NIFI避坑指南002

继续,执行pom.xml引入依赖以后,发现以下几种报错: 可以看到在下载aws-java-sdk-bundle 1.12.710版本的时候报错了 可以看到日志信息,就是在阿里云上下载的,因为阿里云上缺少这个jar包 aws-java-sdk-bundle-1.12.710.jar 这个jar包,我还特意去阿里云上查询了一下 https://deve…

从零到一:Java三层架构下的图书馆管理系统开发指南

引言 使用JavaSE相关知识完成一个以三层架构为设计规范的图书管理系统&#xff0c;不包括前端页面&#xff08;使用main方法Scanner()模拟用户输入&#xff09;&#xff0c;目的是为了基于一个项目快速了解三层架构的项目设计规范的实践。 开发流程 确认需求导入相关的jar包和…

jmeter 梯度测试 如何查看TPS、RT指标

TPS 服务器处理请求总数/花费的总时间 149371 &#xff08;请求量&#xff09; 113&#xff08;1分53秒&#xff09;1321/秒 跟汇总报告的吞吐量差不多&#xff0c;可以认为吞吐量TPS 平均值&#xff0c;中位数&#xff0c;最大值&#xff0c;最小值的单位都是毫秒ms 下载插…