Qt实现水平方向流式布局FlowLayout简单又实用!

Qt中常见的布局管理器有:

QHBoxLayout:水平布局(常用)

QVBoxLayout:垂直布局(常用)

QGridLayout:表格布局(常用)

QFormLayout:表单布局(很少用)

QStackedLayout:堆栈布局(罕见使用)

这些布局管理器都不能直接支持当窗体尺寸变化时,内部子控件的自动换行流式布局(FlowLayout),容易出问题。Qt 官方提供了一个 FlowLayout 的例子,但是并没有将其收录进基础模块中(要是收录了,应该叫QFlowLayout),而是以源码的形式直接给出了可运行测试的例子程序。该类继承自 QLayout,意味着它可以直接被QWidget及其子类setLayout(QLayout *layout)来使用。

以下是Qt官方提供的例子源码,我在此基础上增加3个接口,使其更加实用!

flowlayout.h

#ifndef FLOWLAYOUT_H
#define FLOWLAYOUT_H#include <QLayout>
#include <QRect>
#include <QStyle>
//! [0]
class FlowLayout : public QLayout
{
public:explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);~FlowLayout() override;void addItem(QLayoutItem *item) override;int horizontalSpacing() const;int verticalSpacing() const;Qt::Orientations expandingDirections() const override;bool hasHeightForWidth() const override;int heightForWidth(int) const override;int count() const override;QLayoutItem *itemAt(int index) const override;QSize minimumSize() const override;void setGeometry(const QRect &rect) override;QSize sizeHint() const override;QLayoutItem *takeAt(int index) override;// 重新调整水平/垂直方向的间距void setHorizontalSpacing(int hSpacing);void setVerticalSpacing(int vSpacing);// 立即刷新布局(重新设置水平/垂直方向的间距后,如果布局没有变化,可调用此接口显式刷新布局)void refreshLayout();private:int doLayout(const QRect &rect, bool testOnly) const;int smartSpacing(QStyle::PixelMetric pm) const;QList<QLayoutItem *> itemList;int m_hSpace;int m_vSpace;
};
//! [0]#endif // FLOWLAYOUT_H

flowlayout.cpp

#include <QtWidgets>#include "flowlayout.h"
//! [1]
FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing): QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
{setContentsMargins(margin, margin, margin, margin);
}FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing): m_hSpace(hSpacing), m_vSpace(vSpacing)
{setContentsMargins(margin, margin, margin, margin);
}
//! [1]//! [2]
FlowLayout::~FlowLayout()
{QLayoutItem *item;while ((item = takeAt(0)))delete item;
}
//! [2]//! [3]
void FlowLayout::addItem(QLayoutItem *item)
{itemList.append(item);
}
//! [3]//! [4]
int FlowLayout::horizontalSpacing() const
{if (m_hSpace >= 0) {return m_hSpace;} else {return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);}
}int FlowLayout::verticalSpacing() const
{if (m_vSpace >= 0) {return m_vSpace;} else {return smartSpacing(QStyle::PM_LayoutVerticalSpacing);}
}
//! [4]//! [5]
int FlowLayout::count() const
{return itemList.size();
}QLayoutItem *FlowLayout::itemAt(int index) const
{return itemList.value(index);
}QLayoutItem *FlowLayout::takeAt(int index)
{if (index >= 0 && index < itemList.size())return itemList.takeAt(index);return nullptr;
}
//! [5]//! [6]
Qt::Orientations FlowLayout::expandingDirections() const
{return 0;
}
//! [6]//! [7]
bool FlowLayout::hasHeightForWidth() const
{return true;
}int FlowLayout::heightForWidth(int width) const
{int height = doLayout(QRect(0, 0, width, 0), true);return height;
}
//! [7]//! [8]
void FlowLayout::setGeometry(const QRect &rect)
{QLayout::setGeometry(rect);doLayout(rect, false);
}QSize FlowLayout::sizeHint() const
{return minimumSize();
}QSize FlowLayout::minimumSize() const
{QSize size;for (const QLayoutItem *item : qAsConst(itemList))size = size.expandedTo(item->minimumSize());const QMargins margins = contentsMargins();size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom());return size;
}
//! [8]//! [9]
int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
{int left, top, right, bottom;getContentsMargins(&left, &top, &right, &bottom);QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);int x = effectiveRect.x();int y = effectiveRect.y();int lineHeight = 0;
//! [9]//! [10]for (QLayoutItem *item : qAsConst(itemList)) {const QWidget *wid = item->widget();int spaceX = horizontalSpacing();if (spaceX == -1)spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);int spaceY = verticalSpacing();if (spaceY == -1)spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
//! [10]
//! [11]int nextX = x + item->sizeHint().width() + spaceX;if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {x = effectiveRect.x();y = y + lineHeight + spaceY;nextX = x + item->sizeHint().width() + spaceX;lineHeight = 0;}if (!testOnly)item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));x = nextX;lineHeight = qMax(lineHeight, item->sizeHint().height());}return y + lineHeight - rect.y() + bottom;
}
//! [11]
//! [12]
int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
{QObject *parent = this->parent();if (!parent) {return -1;} else if (parent->isWidgetType()) {QWidget *pw = static_cast<QWidget *>(parent);return pw->style()->pixelMetric(pm, nullptr, pw);} else {return static_cast<QLayout *>(parent)->spacing();}
}
//! [12]void FlowLayout::setHorizontalSpacing(int hSpacing)
{m_hSpace = hSpacing;
}void FlowLayout::setVerticalSpacing(int vSpacing)
{m_vSpace = vSpacing;
}void FlowLayout::refreshLayout()
{doLayout(this->geometry(), false);
}

说说我为何新增3个接口:

    // 重新调整水平/垂直方向的间距void setHorizontalSpacing(int hSpacing);void setVerticalSpacing(int vSpacing);// 立即刷新布局(重新设置水平/垂直方向的间距后,如果布局没有变化,可调用此接口显式刷新布局)void refreshLayout();

官方例子的源码中,水平和垂直方向的间距是在构造函数中设置的,一旦布局完成就无法修改了,如果我们在窗体resize后需要重新调整这些间距就没办法了,所以新增调整水平/垂直方向间距的单独接口。但是这两个接口调整间距后是无法立即生效的,需要手动刷新一下布局,让它按照最新的间距重新布局!

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

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

相关文章

4.分支与循环

逻辑控制分为三部分&#xff1a; 1.顺序结构---》顺序执行代码 2.分支结构---》if语句和switch语句 3.循环执行---》for语句 while语句 和do while语句 顺序结构比较简单&#xff0c;按照代码书写的顺序一行一行执行 分支结构&#xff08;if、switch语句&#xff09; 也就是…

StarCloud开源行动:激发算力调度的创新潜力

01 关于StarCloud OpenCSG StarCloud 是一个集开源系统(Kubernetes ,K8S)与高性能计算(High Performance Computing,HPC)一体的混合算力调度平台。它专注于大模型训练和推理&#xff0c;并提供一站式服务&#xff0c;包括从训练到部署&#xff0c;以及多模型比较等。除了在人…

【OpenVINO™】在 C# 中使用OpenVINO™ 部署PP-YOLOE实现物体检测

前言 OpenVINO™ C# API 是一个 OpenVINO™ 的 .Net wrapper&#xff0c;应用最新的 OpenVINO™ 库开发&#xff0c;通过 OpenVINO™ C API 实现 .Net 对 OpenVINO™ Runtime 调用&#xff0c;使用习惯与 OpenVINO™ C API 一致。OpenVINO™ C# API 由于是基于 OpenVINO™ 开发…

DevOps 温故知新

【引】伴随着微服务架构以及云技术的广泛使用&#xff0c;DevOps相应地引起了人们的关注&#xff0c;尤其在互联网企业展开了大量的探索和实践。去年赋闲在家的时候&#xff0c; 有幸精读了三本书&#xff0c;分别是《持续架构实践——敏捷和DevOps时代下的软件架构》&#xff…

Linux安装MySQL(CentOS 7)

安装步骤 下载的MySQL版本为mysql-8.0.26 进入网站MySQL&#xff0c;点击下载 找到mysql社区版 点击Archive&#xff0c;查看所有相关不同版本 点击MySQL Community Server 注意下载MySQL对应的Linux版本&#xff0c;CentOS7 对应 Linux7&#xff0c;如果下成Linux 8 则后面…

解决SpringBoot整合MyBatis和MyBatis-Plus,请求后不打印sql日志

问题发现 在整合springBootmyBatis时&#xff0c;发现请求不打印sql日志&#xff0c;示例代码如下&#xff1a; RestController public class MyController {AutowiredProductMapper productMapper;GetMapping("/test")public void test() {System.out.println(&qu…

全国大学生数学建模竞赛【集训营E题】丨 近5年赛题实现,模拟参赛体验

全国大学生数学建模竞赛E题集训营即将开营 基于Python的近5年E题数学建模基础巩固 近5年E题赛题实现 模拟参赛体验与作品评审

数据库笔记-【视图】

视图 视图通俗是企业想展示给用户看的&#xff0c;数据库存储的数据有很多&#xff0c;但是也有很多是不能对外公开的&#xff0c;做项目的过程就通过视图这个媒介达到这种效果 视图也可以保证数据库表结构字段的隐私安全等 create or replace view stu_v_1 as select id st…

✨✨使用vue3打造一个el-form表单及高德地图的关联组件实例✨

✨1. 实现功能 &#x1f31f;表单内显示省市县以及详细地址 点击省市县输入框时&#xff0c;打开对应地图弹窗&#xff0c;进行位置选择选择位置回显入对应输入框表单内的省市县以及地址输入框同外嵌表单走相同的校验方式触发校验后点击reset实现清除校验与清空数据 &#x1f…

Base64在线编码解码方法

Base64在线编码解码 打开网站 在线工具网-梦幻加菲猫 选择“Base64编码解码” 输入需要编码/解码的内容&#xff0c;点击“编码”/“解码”按钮 编码&#xff1a; 解码&#xff1a; 4. 复制已经编码/解码后的内容。

【云原生】Kubeadm搭建K8S

一、部署Kubernetes 实验环境 服务器主机名IP地址主要组件k8s集群master01 etcd01master01192.168.10.100kube-apiserver kube-controller-manager kube-schedular etcdk8s集群node01 etcd02node01192.168.10.101kubelet kube-proxy docker flannelk8s集群node02 etcd03nod…

数据结构-题目

1.已知一颗完全二叉树的第6曾&#xff08;设根为第1层&#xff09;&#xff0c;有8个结点&#xff0c;则完全二叉树的结点个数&#xff0c;最少和最多分别是多少&#xff1f; 因此最少为39&#xff0c;最多为111 2.假设一棵三叉树的结点数为50&#xff0c;则它的最小高度为&…

【声呐仿真】学习记录3-待续

【声呐仿真】学习记录3-后续 第五阶段-获取数据1.运行赫尔库勒斯沉船的世界&#xff1a;2.键盘操纵rov至合适的位置&#xff0c;调整Image topic&#xff0c;查看输出图像3.RVIZ SONAR 图像查看器插件&#xff08;没有对应的topic&#xff09;4.点云5.录制rosbag 第六阶段-查看…

守护数据安全:精选七款数据加密软件

在数字化日益普及的今天&#xff0c;数据安全成为了企业和个人不可忽视的重要问题。加密软件作为数据安全的第一道防线&#xff0c;扮演着至关重要的角色。本文将为读者精选七款优秀的加密软件&#xff0c;帮助大家更好地守护数据安全。 Ping32数据加密软件 Ping32数据加密软…

Timestamp Unix时间戳在线转换

Timestamp Unix时间戳在线转换 打开网站 在线工具网-梦幻加菲猫 选择“时间戳转换” 在前半部分输入框输入时间/时间戳&#xff0c;点击“转换>>”按钮&#xff0c;即可转换完成 得到转换结果

Python自动化SQL注入和数据库取证工具库之sqlmap使用详解

概要 在网络安全领域,SQL注入仍然是最常见的攻击之一。sqlmap是一个开源的自动化SQL注入和数据库取证工具,它提供了广泛的功能来检测和利用SQL注入漏洞。本文将详细介绍sqlmap的安装、特性、基本与高级功能,并结合实际应用场景,展示其在网络安全测试中的应用。 安装 sqlm…

银行监管报送系统系列介绍(十七):一表通2.0

国家金融监督管理总局于9月发布了【一表通2.0&#xff08;试用版&#xff09;】&#xff08;简称&#xff1a;一表通2.0&#xff09;&#xff0c;在原试点报送范围的基础上扩大了试点报送区域&#xff0c;意味着将陆续扩大试报送机构范围&#xff0c;推进的速度已明显加快。尽早…

HQChart使用教程98-右键菜单2.0使用介绍

HQChart使用教程98-右键菜单2.0使用介绍 内置右键菜单启用右键菜单定制右键菜单内容1. 注册内置右键菜单创建回调事件2. 修改内置菜单的显示内容回调函数格式菜单数据结构示例 3. 注册菜单项点击事件回调 右键事件完整示例HQChart代码地址 内置右键菜单 HQChart h5版本内置提供…

Spring Boot + Mybatis-plus代码生成器 自动生成项目结构

首先创建一个新的springboot项目 项目初始化结构如下&#xff1a; 运行自动生成结构代码后的效果如下&#xff1a; 对比初始化项目结构可以发现结构中多了以下几个部分; controller文件夹存储接口类mapper文佳夹存储数据库映射model文件夹存储数据库模型类Service文件夹存储业…

未授权访问:Docker未授权访问漏洞

目录 1、漏洞原理 2、环境搭建 3、未授权访问 4、通过crontab反弹宿主机shell 防御手段 今天继续学习各种未授权访问的知识和相关的实操实验&#xff0c;一共有好多篇&#xff0c;内容主要是参考先知社区的一位大佬的关于未授权访问的好文章&#xff0c;还有其他大佬总结好…