【Qt流式布局改造支持任意位置插入和删除】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、源代码
  • 二、删除代码
  • 三、扩展
  • 总结


前言

最近在做一个需求需要流式布局,虽然官方example里有一个流式布局范例,但是不能满足我的需求,我需要支持插入的流式布局,所以就改造了下。


一、源代码

由于我是基于官方改造的,所以就不去大张旗鼓解释了,总体就是增加一个方法:void insertWidget(int index, QWidget *widget);这里给出源代码大家可以自行研究。

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();void addItem(QLayoutItem *item) override;void insertWidget(int index, QWidget *widget);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;private:int doLayout(const QRect &rect, bool testOnly) const;int smartSpacing(QStyle::PixelMetric pm) const;QList<QLayoutItem *> itemList;int m_hSpace;int m_vSpace;
};

FlowLayout .cpp

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/#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);
}void FlowLayout::insertWidget(int index, QWidget *widget)
{if (index < 0 || index > itemList.size()) {index = itemList.size();}QLayoutItem *item = new QWidgetItem(widget);itemList.insert(index, item);addChildWidget(widget);update();
}
//! [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 { };
}
//! [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]

测试代码:

    FlowLayout *flowLayout = new FlowLayout;flowLayout->addWidget(new QPushButton(tr("Short")));flowLayout->addWidget(new QPushButton(tr("Longer")));flowLayout->addWidget(new QPushButton(tr("Different text")));flowLayout->addWidget(new QPushButton(tr("More text")));flowLayout->addWidget(new QPushButton(tr("Even longer button text")));flowLayout->insertWidget(flowLayout->count()-1,new QPushButton(tr("Insert")));

二、删除代码

顺便提一嘴,正常可能没有删除需求,但是如果你想删除控件的话单靠QLayout自带的removeWidget就不行了。下面就介绍删除方法,
假设你插入的QWidgetw,这里要将w彻底回收掉才行,单纯从布局中删除是不够的,所以你插入或加入的控件指针要提前保留下来,等到从流式布局删除的时候需要用到它。

flowLayout->removeWidget(w);
w->deleteLater();

三、扩展

我最近做了一个类似于Ant的Select效果的控件,主要基于流式布局。
在这里插入图片描述
思路就是流式布局里插入一个输入框,当输入框获取焦点的时候弹出下拉框,下拉框可以多选。然后输入框可以搜索过滤

在这里插入图片描述

可以通过点击控件外部让下拉框消失。
在这里插入图片描述
可以通过重复点击下拉框选项或选项流式布局里面的X按钮清除选项解决内容被篡改的问题。


总结

1、总体难度还行
2、代码从官方示例中改进而来,基本能满足我的需求。

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

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

相关文章

“AI玩手机”原理揭秘:大模型驱动的移动端GUI智能体

作者&#xff5c;郭源 前言 在后LLM时代&#xff0c;随着大语言模型和多模态大模型技术的日益成熟&#xff0c;AI技术的实际应用及其社会价值愈发受到重视。AI智能体&#xff08;AI Agent&#xff09;技术通过集成行为规划、记忆存储、工具调用等机制&#xff0c;为大模型装上…

小R的二叉树探险 | 模拟

问题描述 在一个神奇的二叉树中&#xff0c;结构非常独特&#xff1a; 每层的节点值赋值方向是交替的&#xff0c;第一层从左到右&#xff0c;第二层从右到左&#xff0c;以此类推&#xff0c;且该二叉树有无穷多层。 小R对这个二叉树充满了好奇&#xff0c;她想知道&#xf…

Unity类银河战士恶魔城学习总结(P141 Finalising ToolTip优化UI显示)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ UI部分暂时完结&#xff01;&#xff01;&#xff01; 本章节优化了UI中物品描述的显示效果&#xff0c;技能描述的显示效果 并且可以批…

windows实现VNC连接ubuntu22.04服务器

最近弄了一个700块钱的mini主机&#xff0c;刷了ubuntu22.04系统&#xff0c;然后想要在笔记本上通过VNC连接&#xff0c;这样就有了一个linux的开发环境。最后实现的过程为&#xff1a; 安装vnc服务器 安装 VNC 服务器软件&#xff1a; sudo apt update sudo apt install t…

Perforce《2024游戏技术现状报告》Part3:生成式AI、版本控制、CI/CD等游戏技术的未来趋势与应用

游戏开发者一直处于创新前沿。他们的实践、工具和技术受到各行各业的广泛关注&#xff0c;正在改变着组织进行数字创作的方式。 近期&#xff0c;Perforce发布了《2024游戏技术现状报告》&#xff0c;通过收集来自游戏、媒体与娱乐、汽车和制造业等高增长行业的从业者、管理人…

初阶数据结构之队列的实现

1 队列的定义 什么是队列呢&#xff1f;队列只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作。队列具有先进先出FIFO(First In First Out)的特性。 队头&#xff1a;删除数据的一端称为队头。 队尾&#xff1a;插入数据的一端称为队尾。 2 队列底层结构…

阿里云私服地址

1.解压apache-maven-3.6.1-bin 2.配置本地仓库&#xff1a;修改conf/dettings.xml中的<localReoisitory>为一个指定目录。56行 <localRepository>D:\apache-maven-3.6.1-bin\apache-maven-3.6.1\mvn_repo</localRepository> 3.配置阿里云私服&#xff1a;…

小狐狸AI数字人分身声音克隆形象克隆口播口型同步SAAS系统源码

AI数字人软件系统的未来趋势和用途正朝着多模态交互和智能化方向发展。 1. **多模态交互**&#xff1a;AI数字人技术正在从单一的文本或语音交互&#xff0c;转变为更加自然的多模态交互方式&#xff0c;包括语言对话、行为互动和自主学习能力。这种技术的提升使得数字人能够更…

Idea忽略提交文件、Idea设置文件隐藏、Idea提交时隐藏部分文件、git提交时忽略文件

文章目录 一、在idea中commit文件时隐藏文件方式一&#xff1a;创建.gitignore文件&#xff08;推荐&#xff09;方式二&#xff1a;‌通过File Types设置隐藏文件方式三&#xff1a;通过Git配置忽略文件‌&#xff08;不推荐&#xff09;总结 二、可能遇到的问题2.1、.gitigno…

ARM 架构(Advanced RISC Machine)精简指令集计算机(Reduced Instruction Set Computer)

文章目录 1、ARM 架构ARM 架构的特点ARM 架构的应用ARM 架构的未来发展 2、RISCRISC 的基本概念RISC 的优势RISC 的应用RISC 与 CISC 的对比总结 1、ARM 架构 ARM 架构是一种低功耗、高性能的处理器架构&#xff0c;广泛应用于移动设备、嵌入式系统以及越来越多的服务器和桌面…

如何使用Jest测试你的React组件

在本文中&#xff0c;我们将了解如何使用Jest&#xff08;Facebook 维护的一个测试框架&#xff09;来测试我们的React组件。我们将首先了解如何在纯 JavaScript 函数上使用 Jest&#xff0c;然后再了解它提供的一些开箱即用的功能&#xff0c;这些功能专门用于使测试 React 应…

健康养生点点滴滴

在当下纷扰忙碌的尘世中&#xff0c;养生宛如一支灵动的画笔&#xff0c;精心地为人们勾勒出健康生活的绚丽图景。它绝非仅是对躯体的片面保养&#xff0c;更是对精神世界的深度润泽&#xff0c;一种执着于身心交融、契合无间的生活美学。 饮食养生&#xff0c;仿若画卷中那细…

《TCP/IP网络编程》学习笔记 | Chapter 15:套接字与标准 I/O

《TCP/IP网络编程》学习笔记 | Chapter 15&#xff1a;套接字与标准 I/O 《TCP/IP网络编程》学习笔记 | Chapter 15&#xff1a;套接字与标准 I/O标准 I/O 函数标准 I/O 函数的两个优点标准 I/O 函数和系统函数之间的性能对比标准 I/O 函数的几个缺点 使用标准 I/O 函数利用 fd…

[面试]-golang基础面试题总结

文章目录 panic 和 recover**注意事项**使用 pprof、trace 和 race 进行性能调试。**Go Module**&#xff1a;Go中new和make的区别 Channel什么是 Channel 的方向性&#xff1f;如何对 Channel 进行方向限制&#xff1f;Channel 的缓冲区大小对于 Channel 和 Goroutine 的通信有…

鸿蒙进阶-状态管理

大家好啊&#xff0c;这里是鸿蒙开天组&#xff0c;今天我们来学习状态管理。 开始组件化开发之后&#xff0c;如何管理组件的状态会变得尤为重要&#xff0c;咱们接下来系统的学习一下这部分的内容 状态管理机制 在声明式UI编程框架中&#xff0c;UI是程序状态的运行结果&a…

深度学习每周学习总结J6(ResNeXt-50 算法实战与解析 - 猴痘识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 目录 0. 总结ResNeXt基本介绍 1. 设置GPU2. 导入数据及处理部分3. 划分数据集4. 模型构建部分5. 设置超参数&#xff1a;定义损失函数&…

IDEA 2024.3 版本更新主要功能介绍

IDEA 2024.3 版本提供的新特性 IntelliJ IDEA 2024.3 的主要新特性&#xff1a; AI Assistant 增强 改进的代码补全和建议更智能的代码分析和重构建议Java 支持改进 支持 Java 21 的所有新特性改进的模式匹配和记录模式支持更好的虚拟线程调试体验开发工具改进 更新的 UI/UX 设…

java基础概念37:正则表达式2-爬虫

一、定义 【回顾】正则表达式的作用 作用一&#xff1a;校验字符串是否满足规则作用二&#xff1a;在一段文本中查找满足要求的内容——爬虫 二、本地爬虫VS网络爬虫 2-1、本地爬虫 示例&#xff1a; 代码优化&#xff1a; public static void main(String[] args) {// 大…

AmazonS3集成minio实现https访问

最近系统全面升级到https&#xff0c;之前AmazonS3大文件分片上传直接使用http://ip:9000访问minio的方式已然行不通&#xff0c;https服务器访问http资源会报Mixed Content混合内容错误。 一般有两种解决方案&#xff0c;一是升级minio服务&#xff0c;配置ssl证书&#xff0c…

JavaWeb——Mybatis

6. Mybatis MyBatis是一款优秀的持久层框架&#xff0c;用于简化JDBC的开发 6.1. Mybatis入门 6.1.1. 入门程序 6.1.2. JDBC 6.1.3. 数据库连接池 6.1.4. Lombok 6.2. Mybatis基础操作 6.2.1. 删除 6.2.1.1. 根据主键删除 6.2.1.2. 预编译SQL #{id}在编译过程中会替换成?…