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

news2024/12/23 15:02:02

         在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_OBJECT

public:
    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));
    else
        setFlags(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;
    else
        menuOption.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;
    else
        menuOption.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.coloradmin.cn/o/1936881.html

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

相关文章

144. 字典序最小的 01 字符串(卡码网周赛第二十六期(23年阿里淘天笔试真题))

题目链接 144. 字典序最小的 01 字符串&#xff08;卡码网周赛第二十六期&#xff08;23年阿里淘天笔试真题&#xff09;&#xff09; 题目描述 小红有一个 01 字符串&#xff0c;她可以进行最多 k 次提作&#xff0c;每次操作可以交换相邻的两个字符&#xff0c;问可以得到的…

C++的STL简介

0.STL简介 C的STL&#xff08;Standard Template Library&#xff0c;标准模板库&#xff09;是C标准库的一部分&#xff0c;它提供了一套通用的类和函数模板&#xff0c;用于处理数据结构和算法。STL的主要组件包括&#xff1a; 容器分配器算法迭代器适配器仿函数 容器 容…

制造运营管理系统(MOM系统),企业实现先进制造的关键一步

随着全球制造业的快速发展&#xff0c;企业对于生产效率和成本控制的要求日益增高。在这个背景下&#xff0c;制造运营管理系统&#xff08;MOM系统&#xff09;成为了企业提升竞争力的关键工具。盘古信息作为业内领先的智能制造解决方案提供商&#xff0c;其MOM系统更是以其卓…

作为爬虫工程师,在封装API时如何做得更好

在数据驱动的时代&#xff0c;爬虫工程师的角色日益重要。他们不仅是数据的收集者&#xff0c;更是数据的桥梁构建者&#xff0c;通过编写高效、稳定的爬虫程序&#xff0c;将互联网上的海量信息转化为有价值的数据集。而在这一过程中&#xff0c;API&#xff08;应用程序接口&…

最小二乘求待定位点的位置(三维环境)|MATLAB

前言 之前发过三点法求待测点位置的程序讲解&#xff0c;哪个是二维的&#xff0c;见&#xff1a;基于伪逆的三点法距离求位置&#xff0c;MATLAB源代码&#xff08;MATLAB函数&#xff09; 这里给出三维情况下的函数和测试代码。对于函数&#xff0c;输入已知锚点的位置、待…

唐山养老院哪家好---守护晚年幸福,用服务引领老年人高品质养老生活

随着社会的快速发展和人口老龄化趋势的加剧&#xff0c;老年人对养老机构的需求日益增长&#xff0c;选择养老机构作为养老方式已成为许多老年人的必然选择。随着年龄的增长&#xff0c;生理功能的退化和疾病风险的增加&#xff0c;使得老年人更加需要专业的医疗照护和日常生活…

无人机的发展前景大吗?

随着科技的飞速发展&#xff0c;无人机&#xff08;Unmanned Aerial Vehicle, UAV&#xff09;作为一种新兴的航空器&#xff0c;已逐渐从军事领域渗透到民用领域。无人机的应用广泛&#xff0c;包括但不限于航拍、物流配送、环境监测、农业植保、应急救援等多个领域。本文旨在…

神经网络之卷积神经网络

目录 一、卷积神经网络概述&#xff1a;1.卷积层&#xff1a;1.1卷积核与神经元&#xff1a;1.2卷积层作用&#xff1a;1.3多通道概念&#xff1a; 2.池化层&#xff1a;2.1池化层作用&#xff1a; 3.隐藏层与卷积层、池化层关系&#xff1a; 一、卷积神经网络概述&#xff1a;…

Nginx部署前端项目尝试 - windows版

前端还是要学一点服务器端的东西&#xff0c;才能更好的理解一些知识 1、项目打包 生成dist 2、下载nginx解压&#xff0c;start nginx 启动 浏览器输入 localhost 显示如下页面表示启动成功 3、配置nginx server {listen 8080;# ip 不要加http 前后不要加 /server_name…

LeetCode做题记录(第二天)169. 多数元素

题目&#xff1a;169. 多数元素 标签&#xff1a;数组 哈希表 分治 计数 排序 题目信息&#xff1a; 思路一&#xff1a; 在题目中出现了计数&#xff0c;那我们就可以直接考虑考虑使用哈希表 unordered_map 即遍历的时候记录每个数的出现次数&#xff0c;当出现次数大于n/…

无法启动此程序,因为计算机丢失api-ms-win-core-path-l1-1-0.dll的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Qt实现仿微信在线聊天工具(服务器、客户端)V1_ 04

上一篇实现了客户端与服务器的通信,这一篇继续实现相关功能 本章内容 服务器与数据库的连接通信格式的规范登录信息的验证 1.数据库的建立 这里连接的是Mysql8.0数据库,如果想要简单点可以直接用sqlite3数据库,调用逻辑基本差不多,数据库语法也基本一致。 在服务器工程里…

puzzle(0611)《组合+图论》追捕问题

目录 一&#xff0c;追及问题 1&#xff0c;警察和小偷 2&#xff0c;旋转的4个硬币 3&#xff0c;抓狐狸 二&#xff0c;围堵问题 三&#xff0c;追及围堵 一&#xff0c;追及问题 1&#xff0c;警察和小偷 如下图&#xff0c;警察先走&#xff0c;警察和小偷轮流一人…

ubuntu 更新源

前言 实现一键替换在线源 一键更新源 ubuntu 全球镜像站以下支持现有ubuntu 20&#xff0c;22&#xff0c;24 echo "Delete the default source" rm -rf /etc/apt/sources.listecho "Build a new source" cat <<EOF>>/etc/apt/sources.li…

MQTT学习笔记-概念

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;消息队列遥测传输 MQTT特点 MQTT协议是为大量计算能力有限&#xff0c;且工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议&#xff0c;它具有以下主要的几项特性&#xff1a; 1、使用发布…

Nginx优化、防盗链

目录 Nginx优化 隐藏版本信息 网站缓存 日志切割 超时时间 更改进程数 网页压缩 防盗链 在使用源码软件包安装过Nginx服务&#xff0c;具体步骤看上一篇文章 功能模块位置 在Nginx的解压目录下的auto目录内的options文件可以查看Nginx可以安装的功能模块 [rootlocal…

复旦微核心板:基于复旦微FMQL45T900 全国产化核心板

近期开发的一款搭载复旦微FMQL45T900的全国产核心板。FMQL45T900这款是一款高度集成的国产化芯片&#xff0c;它在一个单芯片中融合了多种功能&#xff0c;特别强调的是它的国产化特性&#xff0c;即其设计、制造和知识产权完全属于中国。 处理器性能&#xff1a; 处理器架构&a…

jenkins 插件版本冲突

一、Jenkins安装git parameter 插件重启后报错与临时解决方案 cd /root/.jenkins cp config.xml config.xml.bak vim config.xml <authorizationStrategy class"hudson.security.FullControlOnceLoggedInAuthorizationStrategy"><denyAnonymousReadAcces…

鸿蒙OS开发工具 DevEco Studio(4.0)安装教程

1.旧版本下载地址【HarmonyOS】HUAWEI DevEco Studio 下载地址汇总_deveco studio历史版本-CSDN博客 2.解压安装包&#xff0c;双击安装程序 3.打开后点击Next 4.点击“Browse...”选择路径&#xff0c;然后点击“Next” 5.勾选&#xff0c;点击“Next” 6.默认&#xff0c;直…

【JavaEE进阶】——Spring AOP

目录 &#x1f6a9;Spring AOP概述 &#x1f6a9;Spring AOP快速⼊⻔ &#x1f393;引入AOP依赖 &#x1f393;编写AOP程序 &#x1f6a9;Spring AOP 详解 &#x1f393;Spring AOP核⼼概念 &#x1f393;通知类型 &#x1f393;PointCut &#x1f393;切⾯优先级 Ord…