Qt/C++ 开源控件 可折叠的标签管理控件

embedded/2024/11/18 12:52:58/

在 Qt 开发中,许多项目需要处理标签管理功能,例如分类管理、标签筛选等需求。本文将分享如何利用 Qt/C++ 实现一个具备动态增删标签、展开折叠功能的控件。此控件由 TagWindowTagItemWidget 两个类组成,前者负责整个标签管理窗口的布局与逻辑,后者表示单个标签项。文章将详细介绍控件实现的核心逻辑与思路。
在这里插入图片描述

设计思路

功能需求

  1. 标签项展示:显示带编号和颜色的标签项。
  2. 动态增删标签项:允许用户动态添加或删除标签项。
  3. 窗口展开折叠:控制标签窗口的展开与折叠,优化界面显示空间。

架构概述

  • TagWindow 类用于管理标签项的整体窗口布局,包括标签的列表显示、添加按钮、展开折叠按钮等。
  • TagItemWidget 类表示单个标签项,包含标签编号、可编辑的标签名称、删除按钮等。

接下来我们将从 TagWindowTagItemWidget 的具体实现入手,逐步解析各个模块的实现逻辑和思路。


TagItemWidget 类:实现单个标签项

TagItemWidget 代表单个标签项,包含标签的编号、名称和删除按钮。下面是 TagItemWidget.h 中的定义:

class TagItemWidget : public QWidget {Q_OBJECTpublic:TagItemWidget(int id, const QString &text, const QColor &color, QWidget *parent = nullptr);QString getText() const;         ///< 获取标签的文本内容void setText(const QString &text); ///< 设置标签的文本内容void enableEditing(bool enable); ///< 控制标签名称是否可编辑signals:void requestDeletion(TagItemWidget *item); ///< 请求删除该标签项的信号protected:bool eventFilter(QObject *obj, QEvent *event) override; ///< 事件过滤器用于双击进入编辑模式private:QLabel *idLabel;        ///< 显示标签编号QLineEdit *nameEdit;    ///< 标签名称编辑框QPushButton *deleteButton; ///< 删除按钮
};

构造函数解析

构造函数的主要任务是初始化各组件,并实现标签编号的圆角背景色效果。以下是构造函数的实现:

TagItemWidget::TagItemWidget(int id, const QString &text, const QColor &color, QWidget *parent): QWidget(parent) {QHBoxLayout *layout = new QHBoxLayout(this);// 标签编号idLabel = new QLabel(QString::number(id), this);idLabel->setFixedSize(20, 20);idLabel->setAlignment(Qt::AlignCenter);idLabel->setStyleSheet("background-color: " + color.name() + "; border-radius: 10px; color: white;");// 标签名称编辑框nameEdit = new QLineEdit(text, this);nameEdit->setReadOnly(true); // 默认不可编辑// 删除按钮deleteButton = new QPushButton("删除", this);deleteButton->setFixedSize(40, 20);connect(deleteButton, &QPushButton::clicked, this, [this]() {emit requestDeletion(this);});layout->addWidget(idLabel);layout->addWidget(nameEdit);layout->addWidget(deleteButton);layout->addStretch();// 双击进入编辑模式connect(nameEdit, &QLineEdit::editingFinished, this, [this]() {nameEdit->setReadOnly(true);});nameEdit->installEventFilter(this);
}

事件过滤器

为了实现双击标签名称进入编辑模式,TagItemWidget 类重写了 eventFilter 方法:

bool TagItemWidget::eventFilter(QObject *obj, QEvent *event) {if (obj == nameEdit && event->type() == QEvent::MouseButtonDblClick) {enableEditing(true);return true;}return QWidget::eventFilter(obj, event);
}

该方法会在检测到双击事件时调用 enableEditing,使标签名称进入可编辑状态。


TagWindow 类:实现标签管理窗口

TagWindow 类负责管理多个标签项,包括标签项的添加、删除、窗口的展开和折叠等功能。以下是 TagWindow.h 中的定义:

class TagWindow : public QWidget {Q_OBJECTpublic:explicit TagWindow(QWidget *parent = nullptr);private slots:void toggleExpandCollapse();    ///< 控制窗口的展开/折叠void addItem();                 ///< 添加标签项void deleteItem(TagItemWidget *item); ///< 删除指定的标签项void adjustListWidgetHeight();  ///< 调整 listWidget 的高度private:QVBoxLayout *mainLayout;        ///< 主布局QPushButton *expandCollapseButton; ///< 展开/折叠按钮QPushButton *addButton;         ///< 添加按钮QListWidget *listWidget;        ///< 标签列表QPropertyAnimation *animation;  ///< 控制展开/折叠的动画int collapsedHeight;            ///< 折叠时的高度QString getRandomText();        ///< 生成随机文本QColor getRandomColor();        ///< 生成随机颜色
};

初始化布局

TagWindow 的构造函数实现了控件的初始化和布局:

TagWindow::TagWindow(QWidget *parent) : QWidget(parent) {mainLayout = new QVBoxLayout(this);mainLayout->setContentsMargins(0, 0, 0, 0);// 标题和展开/折叠按钮QHBoxLayout *headerLayout = new QHBoxLayout();QLabel *titleLabel = new QLabel(tc("标签类别:"));expandCollapseButton = new QPushButton("+");connect(expandCollapseButton, &QPushButton::clicked, this, &TagWindow::toggleExpandCollapse);headerLayout->addWidget(titleLabel);headerLayout->addWidget(expandCollapseButton);mainLayout->addLayout(headerLayout);// 添加按钮addButton = new QPushButton("+");connect(addButton, &QPushButton::clicked, this, &TagWindow::addItem);mainLayout->addWidget(addButton);// 标签列表listWidget = new QListWidget(this);listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);listWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);listWidget->setVisible(false);mainLayout->addWidget(listWidget);// 折叠高度collapsedHeight = addButton->sizeHint().height() + expandCollapseButton->sizeHint().height();animation = new QPropertyAnimation(this, "maximumHeight");animation->setDuration(300);setFixedHeight(collapsedHeight);
}

添加与删除标签项

用户点击添加按钮会调用 addItem,随机生成标签内容和颜色,创建新标签项并添加到 listWidget 中:

void TagWindow::addItem() {QColor color = getRandomColor();QString randomText = getRandomText();TagItemWidget *itemWidget = new TagItemWidget(listWidget->count() + 1, randomText, color);QListWidgetItem *listItem = new QListWidgetItem(listWidget);listItem->setSizeHint(itemWidget->sizeHint());listWidget->setItemWidget(listItem, itemWidget);connect(itemWidget, &TagItemWidget::requestDeletion, this, &TagWindow::deleteItem);listWidget->setVisible(true);adjustListWidgetHeight();
}

删除标签项时通过 deleteItem 实现:

void TagWindow::deleteItem(TagItemWidget *item) {for (int i = 0; i < listWidget->count(); ++i) {QListWidgetItem *listItem = listWidget->item(i);if (listWidget->itemWidget(listItem) == item) {delete listWidget->takeItem(i);break;}}if (listWidget->count() == 0) {listWidget->setVisible(false);}adjustListWidgetHeight();
}

控制窗口的展开和折叠

点击展开/折叠按钮会触发 toggleExpandCollapse 方法,通过动画效果平滑展开或折叠窗口:

void TagWindow::toggleExpandCollapse() {if (listWidget->count() == 0) return;bool isExpanded = !listWidget->isVisible();int targetHeight = isExpanded ? (collapsedHeight + listWidget->sizeHint().height()) : collapsedHeight;animation->stop();animation->setStartValue(height());animation->setEndValue(targetHeight);animation->start();expandCollapseButton->setText(isExpanded ? "-" : "+");connect(animation, &QPropertyAnimation::finished, this, [=]() {setFixedHeight(targetHeight);listWidget->setVisible(isExpanded);});adjustListWidgetHeight();
}

总结

本文介绍了一个基于 Qt 的标签管理控件的实现,包括标签项的创建、删除和窗口的展开折叠效果。通过对 TagWindowTagItemWidget 的详细讲解,相信大家能更好地理解如何设计和实现一个可复用的 Qt 控件。在实际开发中,您可以根据需求对控件功能进行扩展,如增加多标签选择、标签项排序等功能。希望本文能为您在 Qt 开发中的自定义控件设计提供参考。


http://www.ppmy.cn/embedded/138543.html

相关文章

Flink算子

文章目录 mapfilterflatMapkeyByaggregationsreduce物理分区算子富函数splitside outputunion(联合)connect(连接&#xff09; map Map 算子会遍历数据流的每一个元素产生一个新的元素。 public static void main(String[] args) throws Exception {StreamExecutionEnvironmen…

STM32 | 空气净化器

空气净化器 一、项目背景 空气净化器又称“空气清洁器”、空气清新机、净化器&#xff0c;是指能够吸附、分解或转化各种空气污染物&#xff08;一般包括PM2.5、粉尘、花粉、异味、甲醛之类的装修污染、细菌、过敏原等&#xff09;&#xff0c;有效提高空气清洁度的产品&…

java判断点是否在多边形内(射线法)

1、我是使用的数组记录点的坐标&#xff0c;索引0为x坐标&#xff0c;1为y坐标 2、也可以使用结构体来记录点x&#xff0c;y&#xff0c;再用List管理点集合。 import java.util.Arrays; import java.util.Objects;/*** Author 宇颀休闲* Date 2024/11/10 11:03* Description…

HTTP/2新型DDoS攻击:技术深度剖析与防御指南

在智能化演进和互联网技术高速发展的背景下&#xff0c;黑客攻击手段不断翻新&#xff0c;DDoS攻击的强度、频率和复杂度也随之持续攀升。金融、政务、互联网等多个领域及其关键基础设施正面临着前所未有的DDoS攻击威胁。 一、大流量攻击&#xff1a;秒级加速的威胁 近年来&a…

Rust 语言学习笔记(五)

终于来到了 Rust 的精髓所在了&#xff0c;那就是使之不依赖于垃圾回收又能保障内存安全且高效运行的所有权系统(Ownership System)。想要用 Rust 做一个稍显规模项目必定绕不过它&#xff0c;所有权系统包括所有权(Ownership), 借用(Borrowing), 生命周期(Lifetimes)。 以下概…

CSS Modules中的 :global

最近写需求遇到如下代码&#xff0c;我们来分析一番&#xff1a; .medicine-bot {:global(.cosd-site-vcard-card) {margin-top: -3px;}:global(.cosd-site-vcard-title-text) {font-size: var(--cos-text-headline-sm);}:global(.cosd-site-vcard-button) {background-color: …

快速上手:Docker 安装详细教程(适用于 Windows、macOS、Linux)

### 快速上手&#xff1a;Docker 安装详细教程&#xff08;适用于 Windows、macOS、Linux&#xff09; --- Docker 是一款开源容器化平台&#xff0c;广泛应用于开发、测试和部署。本文将为您提供分步骤的 Docker 安装教程&#xff0c;涵盖 Windows、macOS 和 Linux 系统。 …

JMeter与大模型融合应用之JMeter日志分析服务化实战应用

JMeter与大模型融合应用之JMeter日志分析服务化 引言 在当今的互联网时代,网站和应用程序的性能直接影响到用户的体验和业务的成功。为了保证系统的稳定性和高效性,性能测试成为了软件开发过程中的一个重要环节。在这其中,Apache JMeter作为一款开源的性能测试工具,凭借其…