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

相关文章

Qt如何实现文本编辑器光标高亮技术

《Qt如何实现文本编辑器光标高亮技术》这篇文章主要为大家详细介绍了Qt如何实现文本编辑器光标高亮技术,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录实现代码函数作用概述代码详解 + 注释使用 QTextEdit 的高亮技术(重点)总结用到的关键技术点应用场景举例示例优化建议

Qt 设置软件版本信息的实现

《Qt设置软件版本信息的实现》本文介绍了Qt项目中设置版本信息的三种常用方法,包括.pro文件和version.rc配置、CMakeLists.txt与version.h.in结合,具有一定的参考... 目录在运行程序期间设置版本信息可以参考VS在 QT 中设置软件版本信息的几种方法方法一:通过 .pro

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

Python中bisect_left 函数实现高效插入与有序列表管理

《Python中bisect_left函数实现高效插入与有序列表管理》Python的bisect_left函数通过二分查找高效定位有序列表插入位置,与bisect_right的区别在于处理重复元素时... 目录一、bisect_left 基本介绍1.1 函数定义1.2 核心功能二、bisect_left 与

Spring中管理bean对象的方式(专业级说明)

《Spring中管理bean对象的方式(专业级说明)》在Spring框架中,Bean的管理是核心功能,主要通过IoC(控制反转)容器实现,下面给大家介绍Spring中管理bean对象的方式,感兴趣的朋... 目录1.Bean的声明与注册1.1 基于XML配置1.2 基于注解(主流方式)1.3 基于Java

基于Python+PyQt5打造一个跨平台Emoji表情管理神器

《基于Python+PyQt5打造一个跨平台Emoji表情管理神器》在当今数字化社交时代,Emoji已成为全球通用的视觉语言,本文主要为大家详细介绍了如何使用Python和PyQt5开发一个功能全面的... 目录概述功能特性1. 全量Emoji集合2. 智能搜索系统3. 高效交互设计4. 现代化UI展示效果

VS配置好Qt环境之后但无法打开ui界面的问题解决

《VS配置好Qt环境之后但无法打开ui界面的问题解决》本文主要介绍了VS配置好Qt环境之后但无法打开ui界面的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目UKeLvb录找到Qt安装目录中designer.UKeLvBexe的路径找到vs中的解决方案资源

Mysql中的用户管理实践

《Mysql中的用户管理实践》:本文主要介绍Mysql中的用户管理实践,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录13. 用户管理13.1 用户 13.1.1 用户信息 13.1.2 创建用户 13.1.3 删除用户 13.1.4 修改用户

linux服务之NIS账户管理服务方式

《linux服务之NIS账户管理服务方式》:本文主要介绍linux服务之NIS账户管理服务方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、所需要的软件二、服务器配置1、安装 NIS 服务2、设定 NIS 的域名 (NIS domain name)3、修改主

Qt之QMessageBox的具体使用

《Qt之QMessageBox的具体使用》本文介绍Qt中QMessageBox类的使用,用于弹出提示、警告、错误等模态对话框,具有一定的参考价值,感兴趣的可以了解一下... 目录1.引言2.简单介绍3.常见函数4.按钮类型(QMessage::StandardButton)5.分步骤实现弹窗6.总结1.引言