Qt-布局管理

2024-09-06 21:36
文章标签 布局 qt 管理

本文主要是介绍Qt-布局管理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

布局管理

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_itemsreturn 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 rangereturn m_items.value(idx);
}QLayoutItem *CardLayout::takeAt(int idx)
{// QVector::take does not do index checkingreturn 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 sizeint 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

这篇关于Qt-布局管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1143183

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Sentinel 高可用流量管理框架

Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。 Sentinel 具有以下特性: 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应

【QT】基础入门学习

文章目录 浅析Qt应用程序的主函数使用qDebug()函数常用快捷键Qt 编码风格信号槽连接模型实现方案 信号和槽的工作机制Qt对象树机制 浅析Qt应用程序的主函数 #include "mywindow.h"#include <QApplication>// 程序的入口int main(int argc, char *argv[]){// argc是命令行参数个数,argv是

lvgl8.3.6 控件垂直布局 label控件在image控件的下方显示

在使用 LVGL 8.3.6 创建一个垂直布局,其中 label 控件位于 image 控件下方,你可以使用 lv_obj_set_flex_flow 来设置布局为垂直,并确保 label 控件在 image 控件后添加。这里是如何步骤性地实现它的一个基本示例: 创建父容器:首先创建一个容器对象,该对象将作为布局的基础。设置容器为垂直布局:使用 lv_obj_set_flex_flow 设置容器

Python QT实现A-star寻路算法

目录 1、界面使用方法 2、注意事项 3、补充说明 用Qt5搭建一个图形化测试寻路算法的测试环境。 1、界面使用方法 设定起点: 鼠标左键双击,设定红色的起点。左键双击设定起点,用红色标记。 设定终点: 鼠标右键双击,设定蓝色的终点。右键双击设定终点,用蓝色标记。 设置障碍点: 鼠标左键或者右键按着不放,拖动可以设置黑色的障碍点。按住左键或右键并拖动,设置一系列黑色障碍点