Qt自定义下拉列表-可为选项设置标题、可禁用选项

         在Qt中,ComboBox(组合框)是一种常用的用户界面控件,它提供了一个下拉列表,允许用户从预定义的选项中选择一个。在项目开发中,如果简单的QComboBox无法满足需求,可以通过自定义QComboBox来实现更复杂的功能。本文介绍一个自定义的下拉列表,并为选项设置标题、可禁用选项。

一、简述

         本示例介绍一个Qt自定义下拉列表,可为选项设置标题、可禁用选项。

二、 设计思路             
  1. 继承QComboBox类: 创建一个新的类,继承自QComboBox类。在该类中,可以重写QComboBox的方法以实现自定义功能。

  2. 使用QListWidget和QListWidgetItem: QComboBox默认使用QStandardItemModel来管理下拉列表的数据。扩展时使用QListWidget的QListModel来替代QStandardItemModel。在QListWidget的QListWidgetItem中,可以自定义每个列表项的显示和交互逻辑。

  3. 使用自定义代理类: 通过自定义QItemDelegate类,可以实现对下拉列表中每个项的自定义绘制和交互逻辑。可以通过setItemDelegate方法将自定义的代理类设置为QComboBox的项代理。

三、效果 

四、核心代码  
1、头文件
#ifndef CustomCombo_H
#define CustomCombo_H#include <QComboBox>
#include <QListWidget>
#include <QItemDelegate>class CustomCombo : public QComboBox
{Q_OBJECTpublic:CustomCombo(QWidget *parent=0);QListWidget *list() const{ return list_; }void addTitle(const QString &text);void addItem (const QString &text);void setIsTitle(int ind, bool b);void setSelectable(int ind, bool b);private:void resetCurrentInd();private:QListWidget *list_;
};//------------------------------------------------------------------------------------------------------------
class CustomComboItem : public QListWidgetItem {
public:CustomComboItem(CustomCombo *combo, const QString &str);virtual ~CustomComboItem() { }CustomCombo *combo() const { return combo_; }void setIsTitle(bool b);inline bool isTitle() const { return isTitle_; }void setSelectable(bool selectable);inline bool isSelectable() const {return (flags() & (Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));}private:CustomCombo *combo_;bool isTitle_;bool selectable_;
};//------------------------------------------------------------------------------------------------------------
class CustomComboTitle : public CustomComboItem {
public:CustomComboTitle(CustomCombo *combo, const QString &str) :CustomComboItem(combo, str) {setSelectable(false);setIsTitle(true);}
};//------------------------------------------------------------------------------------------------------------
class CustomComboDelegate : public QItemDelegate {
public:CustomComboDelegate(CustomCombo *combo) ;void paint(QPainter *painter, const QStyleOptionViewItem &option,const QModelIndex &index) const override;QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;QStyleOptionMenuItem getStyleOption(const QStyleOptionViewItem &option,const QModelIndex &index, CustomComboItem *item) const;static bool isSeparator(const QModelIndex &index) {return (index.data(Qt::AccessibleDescriptionRole).toString() == "separator");}private:CustomCombo *combo_;
};#endif
2、实现代码
#include "CustomCombo.h"#include <QPainter>
#include <QApplication>CustomCombo::CustomCombo(QWidget *parent) :QComboBox(parent), list_(nullptr)
{list_ = new QListWidget;list_->setItemDelegate(new CustomComboDelegate(this));setModel(list_->model());setView(list_);
}void CustomCombo::addTitle(const QString &text)
{list_->addItem(new CustomComboTitle(this, text));resetCurrentInd();
}void CustomCombo::addItem(const QString &text)
{list_->addItem(new CustomComboItem(this, text));resetCurrentInd();
}void CustomCombo::setIsTitle(int ind, bool b)
{auto *item = dynamic_cast<CustomComboItem *>(list_->item(ind));item->setIsTitle(b);resetCurrentInd();
}void CustomCombo::setSelectable(int ind, bool b)
{auto *item = dynamic_cast<CustomComboItem *>(list_->item(ind));item->setSelectable(b);resetCurrentInd();
}void CustomCombo::resetCurrentInd()
{auto *item = static_cast<CustomComboItem *>(list()->item(currentIndex()));if (item->isSelectable())return;for (int i = 0; i < count(); ++i) {auto *item = static_cast<CustomComboItem *>(list()->item(i));if (item->isSelectable()) {setCurrentIndex(i);break;}}
}//CustomComboItem
//------------------------------------------------------------------------------------------------------------
CustomComboItem::CustomComboItem(CustomCombo *combo, const QString &str) :QListWidgetItem(str), combo_(combo), isTitle_(false), selectable_(true){}void CustomComboItem::setIsTitle(bool b) {isTitle_ = b;if (isTitle_)setSelectable(false);
}void CustomComboItem::setSelectable(bool selectable) {selectable_ = selectable;if (selectable_)setFlags(flags() |  (Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));elsesetFlags(flags() & ~(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
}//CustomComboDelegate
//------------------------------------------------------------------------------------------------------------
CustomComboDelegate::CustomComboDelegate(CustomCombo *combo) :combo_(combo) {}void CustomComboDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,const QModelIndex &index) const {auto *item = static_cast<CustomComboItem *>(combo_->list()->item(index.row()));QStyleOptionMenuItem opt = getStyleOption(option, index, item);painter->fillRect(opt.rect, opt.palette.window());combo_->style()->drawControl(QStyle::CE_MenuItem, &opt, painter, combo_);
}QSize CustomComboDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {auto *item = static_cast<CustomComboItem *>(combo_->list()->item(index.row()));QStyleOptionMenuItem opt = getStyleOption(option, index, item);return combo_->style()->sizeFromContents(QStyle::CT_MenuItem, &opt, option.rect.size(), combo_);
}QStyleOptionMenuItem CustomComboDelegate::getStyleOption(const QStyleOptionViewItem &option,const QModelIndex &index, CustomComboItem *item) const {QStyleOptionMenuItem menuOption;QPalette resolvedpalette = option.palette.resolve(QApplication::palette("QMenu"));QBrush textBrush = resolvedpalette.brush(QPalette::Active, QPalette::Text);QVariant value = index.data(Qt::ForegroundRole);if (value.canConvert<QBrush>())textBrush = qvariant_cast<QBrush>(value);if (! item->isSelectable())textBrush = resolvedpalette.brush(QPalette::Disabled, QPalette::Text);if (item->isTitle())textBrush = resolvedpalette.brush(QPalette::Active, QPalette::HighlightedText);resolvedpalette.setBrush(QPalette::WindowText, textBrush);resolvedpalette.setBrush(QPalette::ButtonText, textBrush);resolvedpalette.setBrush(QPalette::Text      , textBrush);menuOption.palette = resolvedpalette;menuOption.state   = QStyle::State_None;if (combo_->window()->isActiveWindow())menuOption.state = QStyle::State_Active;if ((option.state & QStyle::State_Enabled) && (index.model()->flags(index) & Qt::ItemIsEnabled))menuOption.state |= QStyle::State_Enabled;elsemenuOption.palette.setCurrentColorGroup(QPalette::Disabled);if (option.state & QStyle::State_Selected)menuOption.state |= QStyle::State_Selected;menuOption.checkType = QStyleOptionMenuItem::NonExclusive;menuOption.checked   = (combo_->currentIndex() == index.row());if (isSeparator(index))menuOption.menuItemType = QStyleOptionMenuItem::Separator;elsemenuOption.menuItemType = QStyleOptionMenuItem::Normal;QBrush bgBrush = menuOption.palette.brush(QPalette::Window);if (index.data(Qt::BackgroundRole).canConvert<QBrush>())bgBrush = qvariant_cast<QBrush>(index.data(Qt::BackgroundRole));if (item->isTitle())bgBrush = resolvedpalette.brush(QPalette::Active, QPalette::Highlight);menuOption.palette.setBrush(QPalette::All, QPalette::Window, bgBrush);menuOption.text = index.model()->data(index, Qt::DisplayRole).toString();menuOption.tabWidth     = 0;menuOption.maxIconWidth = option.decorationSize.width() + 4;menuOption.menuRect     = option.rect;menuOption.rect         = option.rect;menuOption.font         = combo_->font();menuOption.fontMetrics  = QFontMetrics(menuOption.font);if (item->isTitle())menuOption.font.setBold(true);return menuOption;
}

        以上本文实现自定义ComboBox的方法,实际上自定义下拉列表可以根据具体的需求进行定制和扩展,适应不同的应用场景。

五、使用示例

以下是一个简单的示例代码,演示了如何在Qt中使用此控件:

#include "mainwindow.h"
#include "CustomCombo.h"
#include <QVBoxLayout>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{QWidget *pWidget = new QWidget;QHBoxLayout *layout = new QHBoxLayout(pWidget);CustomCombo *combo = new CustomCombo;combo->addTitle("文学类");combo->addItem ("红楼梦");combo->addItem ("三国演义");combo->addItem ("背影");combo->addItem ("荷塘月色");combo->addTitle("科技类");combo->addItem ("几何原本");combo->addItem ("自然哲学的数学原理");combo->addItem ("天工开物");combo->addItem ("梦溪笔谈");combo->setSelectable(3, false);//禁用选项layout->addWidget(combo);setCentralWidget(pWidget);
}MainWindow::~MainWindow()
{
}

        总结一下,自定义下拉列表是Qt中常用的控件之一,用于在界面中显示下拉选择项。一般来说,自定义下拉列表可以分为以下几个步骤:

  1. 创建下拉列表按钮:使用QPushButton或QLineEdit等Qt提供的控件作为下拉列表的按钮,用于显示当前选择的选项。

  2. 创建下拉列表框:使用QFrame或QListWidget等Qt提供的控件作为下拉列表的框,用于显示所有选项。

  3. 设置下拉列表框属性:可以设置下拉列表框的大小、位置、边框等属性,以及确定是否默认展开。

  4. 添加选项:使用addItem()或insertItem()等方法向下拉列表框中添加选项。

  5. 设置选项属性:可以设置选项的文本、图标、状态等属性。

  6. 处理选项选择事件:可以通过重写下拉列表的事件处理函数来实现对选项的选择。

  7. 更新按钮显示:在选项被选择后,需要更新按钮的显示文本,以反映所选选项。

        谢谢您的阅读,希望本文能为您带来一些帮助和启发。如果您有任何问题或意见,请随时与我联系。祝您度过美好的一天!

六、源代码下载

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

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

相关文章

Python研究生毕业设计,数据挖掘、情感分析、机器学习

最近在学校毕业了&#xff0c;其中有很多毕业论文使用到的代码&#xff0c;如数据挖掘、情感分析、机器学习、数据预测处理、划分数据集和测试集&#xff0c;绘制分类任务&#xff0c;词汇表示&#xff1a;使用TF-IDF向量化器&#xff0c;线性回归、多元线性回归、SVR回归模型&…

一文入门SpringSecurity 5

目录 提示 Apache Shiro和Spring Security 认证和授权 RBAC Demo 环境 Controller 引入Spring Security 初探Security原理 认证授权图示​编辑 图中涉及的类和接口 流程总结 提示 Spring Security源码的接口名和方法名都很长&#xff0c;看源码的时候要见名知意&am…

grafana对接zabbix数据展示

目录 1、初始化、安装grafana 2、浏览器访问 3、安装zabbix 4、zabbix数据对接grafana 5、如何导入模板&#xff1f; ① 设置键值 ② 在zabbix web端完成自定义监控项 ③ garafana里添加nginx上面的的三个监控项 6、如何自定义监控项&#xff1f; 以下实验沿用上一篇z…

二、原型模式

文章目录 1 基本介绍2 实现方式深浅拷贝目标2.1 使用 Object 的 clone() 方法2.1.1 代码2.1.2 特性2.1.3 实现深拷贝 2.2 在 clone() 方法中使用序列化2.2.1 代码 2.2.2 特性 3 实现的要点4 Spring 中的原型模式5 原型模式的类图及角色5.1 类图5.1.1 不限制语言5.1.2 在 Java 中…

免费【2024】springboot 趵突泉景区的智慧导游小程序

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

开发桌面程序-Electron入门

Electron是什么 来自官网的介绍 Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发 经验。 总…

普中51单片机:DS1302时钟芯片讲解与应用(十)

文章目录 引言基本特性什么是RAM&#xff1f;什么是涓流充电&#xff1f; 电路图和引脚说明通信协议以及工作流程寄存器控制寄存器日历/时钟寄存器 DS1302读写时序代码演示——数码管显示时分秒 引言 DS1302 是一款广泛使用的实时时钟 (RTC) 芯片&#xff0c;具有低功耗、内置…

本地部署VMware ESXi服务实现无公网IP远程访问管理服务器

文章目录 前言1. 下载安装ESXi2. 安装Cpolar工具3. 配置ESXi公网地址4. 远程访问ESXi5. 固定ESXi公网地址 前言 在虚拟化技术日益成熟的今天&#xff0c;VMware ESXi以其卓越的性能和稳定性&#xff0c;成为了众多企业构建虚拟化环境的首选。然而&#xff0c;随着远程办公和跨…

《昇思25天学习打卡营第19天|基于MobileNetv2的垃圾分类》

基于MobileNetv2的垃圾分类 本文档主要介绍垃圾分类代码开发的方法。通过读取本地图像数据作为输入&#xff0c;对图像中的垃圾物体进行检测&#xff0c;并且将检测结果图片保存到文件中。 1、实验目的 了解熟悉垃圾分类应用代码的编写&#xff08;Python语言&#xff09;&a…

机器学习 | 回归算法原理——多项式回归

Hi&#xff0c;大家好&#xff0c;我是半亩花海。接着上次的最速下降法&#xff08;梯度下降法&#xff09;继续更新《白话机器学习的数学》这本书的学习笔记&#xff0c;在此分享多项式回归这一回归算法原理。本章的回归算法原理基于《基于广告费预测点击量》项目&#xff0c;…

html+css+js前端作业 王者荣耀官网5个页面带js

htmlcssjs前端作业 王者荣耀官网5个页面带js 下载地址 https://download.csdn.net/download/qq_42431718/89574989 目录1 目录2 目录3 项目视频 王者荣耀5个页面&#xff08;带js&#xff09; 页面1 页面2 页面3 页面4 页面5

分布式Apollo配置中心搭建实战

文章目录 环境要求第一步、软件下载第二步、创建数据库参考文档 最近新项目启动&#xff0c;采用Apollo作为分布式的配置中心&#xff0c;在本地搭建huanj 实现原理图如下所示。 环境要求 Java版本要求&#xff1a;JDK1.8 MySql版本要求&#xff1a;5.6.5 Apollo版本要求&…

机器学习(二十):偏差和方差问题

一、判断偏差和方差 以多项式回归为例&#xff0c;红点为训练集数据&#xff0c;绿点为交叉验证数据。 下图的模型&#xff0c;训练集误差大&#xff0c;交叉验证集误差大&#xff0c;这代表偏差很大 下图的模型&#xff0c;训练集误差小&#xff0c;交叉验证集误差小&#x…

SpringBoot上传超大文件导致OOM,完美问题解决办法

问题描述 报错: Caused by: java.lang.OutOfMemoryError at java.io.ByteArrayOutputStream.hugeCapacity(ByteArrayOutputStream.java:123) ~[?:1.8.0_381] at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:117) ~[?:1.8.0_381] at java.…

Windows下载、安装、部署Redis服务的详细流程

本文介绍在Windows电脑中&#xff0c;下载、安装、部署并运行Redis数据库服务的方法。 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源、高性能的键值存储系统&#xff0c;最初由Salvatore Sanfilippo在2009年发布&#xff0c;并由Redis Labs维护。Redis因其…

【word转pdf】【最新版本jar】Java使用aspose-words实现word文档转pdf

【aspose-words-22.12-jdk17.jar】word文档转pdf 前置工作1、下载依赖2、安装依赖到本地仓库 项目1、配置pom.xml2、配置许可码文件&#xff08;不配置会有水印&#xff09;3、工具类4、效果 踩坑1、pdf乱码2、word中带有图片转换 前置工作 1、下载依赖 通过百度网盘分享的文…

Docker Desktop安装

0 Preface/Foreward 0.1 参考文档 Overview of Docker Desktop | Docker Docs &#xff08;Docker Desktop使用手册&#xff09; 0.1.1 Docker Dashboard Before going any further, we want to highlight the Docker Dashboard, which gives you a quick view of the cont…

vue3+element-plus 实现动态菜单和动态路由的渲染

在 Vue.js 中&#xff0c;使用 Vue Router 管理路由数据&#xff0c;并将其用于渲染 el-menu&#xff08;Element UI 的菜单组件&#xff09;通常涉及以下几个步骤&#xff1a; 定义路由元数据&#xff1a; 在你的路由配置中&#xff0c;为每个路由项添加 meta 字段&#xff0c…

RAG vs 微调:大模型知识的进化之路

2024年&#xff0c;大模型应用落地迎来全面提速。越来越多的企业在加大对大模型的投入&#xff0c;抢抓变革机遇&#xff0c;加速应用落地。大模型应用落地绕不开的两个关键词“RAG”和“微调”。那么什么是RAG&#xff1f;什么是大模型微调&#xff1f;大模型项目建设中RAG和微…

redis的使用场景和持久化方式

redis的使用场景 热点数据的缓存。热点&#xff1a;频繁读取的数据。限时任务的操作&#xff1a;短信验证码。完成session共享的问题完成分布式锁。 redis的持久化方式 什么是持久化&#xff1a;把内存中的数据存储到磁盘的过程&#xff0c;同时也可以把磁盘中的数据加载到内存…