Qt实现自定义多选下拉列表

本文详细介绍了如何通过继承QComboBox实现一个多选下拉列表,包括添加数据、设置高度、显示文本、用户数据管理以及选择数据的操作。并提供了示例代码和设计思路。

前言

本文记录了一种通过继承 QComboBox 实现下拉列表多选功能的方法。效果如下图所示:
在这里插入图片描述

1、 功能描述

普通的下拉列表只支持选择一个选项,在软件开发过程中,经常会遇到下拉列表支持选择多个选项的需求,下面的代码实现了下拉列表多选功能,支持设置弹窗的高度,支持添加显示文本和用户数据,支持设置默认选中项目,支持获取选中数据。

2、代码实现

2.1 头文件
#ifndef LLCOMBOBOX_H
#define LLCOMBOBOX_H

#include <QComboBox>

class QListWidgetItem;
class LLComboBoxPrivate;
class LLComboBox : public QComboBox
{
    Q_OBJECT
public:
    explicit LLComboBox(QWidget* parent = NULL);

    /**
     * @brief addDataItem 添加数据
     * @param text
     * @param userData
     */
    void addDataItem(const QString &text, const QVariant &userData = QVariant());

    /**
     * @brief setSelectedData 设置选中的数据
     * @param selectedData
     */
    void setSelectedData(const QStringList &selectedData);

    /**
     * @brief setPopupViewHeight 设置下拉列表弹窗的高度,默认值100
     * @param height
     */
    void setPopupViewHeight(int height);

    /**
     * @brief selectedDataText 获取选择的数据
     * @return
     */
    QStringList selectedDataText();

    /**
     * @brief selectedUserData 获取选择数据对应的用户数据
     * @return
     */
    QList<QVariant> selectedUserData();

private slots:
    void slot_itemChanged(QListWidgetItem *item);
private:

    LLComboBoxPrivate *m_pd;
};

#endif // LLCOMBOBOX_H

2.2 源码文件
#include <QListWidget>
#include <QCheckBox>
#include <QList>
#include <QLineEdit>
#include <QDebug>

#include "llcombobox.h"

class LLComboBoxPrivate
{
public:

    QStringList selectedDataList;
    QListWidget *pListWidget;
};

LLComboBox::LLComboBox(QWidget *parent)
    : QComboBox(parent)
    , m_pd(new LLComboBoxPrivate)
{
    m_pd->pListWidget = new QListWidget;
    m_pd->pListWidget->setFixedHeight(100);
    connect(m_pd->pListWidget, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(slot_itemChanged(QListWidgetItem *)));
    setView(m_pd->pListWidget);
    //设置Editable为true,lineEdit() 函数才不返回空
    setEditable(true);
}

void LLComboBox::addDataItem(const QString &text, const QVariant &userData)
{
    m_pd->pListWidget->blockSignals(true);
    QListWidgetItem *pItem = new QListWidgetItem(text, m_pd->pListWidget);
    pItem->setData(Qt::UserRole, userData);
    pItem->setCheckState(Qt::Unchecked);
    //设置QListWidgetItem 可交互且可以选中和取消选中
    pItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
    QComboBox::addItem(text);
    QComboBox::setCurrentText("");
    m_pd->pListWidget->blockSignals(false);
}

void LLComboBox::setSelectedData(const QStringList &selectedData)
{
    m_pd->selectedDataList.clear();
    m_pd->selectedDataList += selectedData;

    QString text = "";
    for (int var = 0; var < m_pd->selectedDataList.size(); ++var)
    {
        m_pd->pListWidget->blockSignals(true);
        QListWidgetItem *pItem = m_pd->pListWidget->item(var);
        pItem->setCheckState(Qt::Checked);
        m_pd->pListWidget->blockSignals(false);

        text.append(m_pd->selectedDataList[var]);
        if(var < m_pd->selectedDataList.size() - 1)
        {
            text.append(",");
        }
    }

    lineEdit()->setText(text);
}

QStringList LLComboBox::selectedDataText()
{
    return m_pd->selectedDataList;
}

QList<QVariant> LLComboBox::selectedUserData()
{
    QList<QVariant> dataList;
    for (int var = 0; var < m_pd->selectedDataList.size(); ++var)
    {
        QListWidgetItem *pItem = m_pd->pListWidget->item(var);
        if(pItem->checkState() == Qt::Checked)
        {
            dataList.append(pItem->data(Qt::UserRole));
        }
    }

    return dataList;
}

void LLComboBox::slot_itemChanged(QListWidgetItem *item)
{
    qDebug() << QString("text=") << item->text();
    if(m_pd->selectedDataList.contains(item->text()))
    {
        m_pd->selectedDataList.removeOne(item->text());
    }
    else
    {
        m_pd->selectedDataList.append(item->text());
    }

    QString text = "";
    for (int var = 0; var < m_pd->selectedDataList.size(); ++var)
    {
        text.append(m_pd->selectedDataList[var]);
        if(var < m_pd->selectedDataList.size() - 1)
        {
            text.append(",");
        }
    }

    lineEdit()->setText(text);
}

2.3 设计思路

本控件继承自QComboBox,重新设置了QComboBox的弹出列表为 QListWidget 的实例pListWidget。当添加下拉列表元素时先创建一个QListWidgetItem,并通过setFlags 函数设置为可交互且用户可点击,通过setCheckState函数设置默认为非选中状态。需要注意的是必须调用 QComboBox::addItem(); 方法向QComboBox 添加数据,弹窗才能正常显示。

通过QListWidget 的 itemChanged(QListWidgetItem *)信号来判断一个选项是否选中,因此在添加数据前要先阻塞pListWidget的信号发送,添加结束后再开启信号发送。可以看到添加数据的代码是写在blockSignals();之间的。

	m_pd->pListWidget->blockSignals(true);
    //添加多选列表数据
    m_pd->pListWidget->blockSignals(false);

QComboBox默认只显示一个选中的选项,为了显示选择的多个选项数据,这里设置QComboBox为可编辑,这样lineEdit()函数将返回编辑框指针,我们将多选的数据拼接起来设置到lineEdit中。如果不设置QComboBox为可编辑,lineEdit()函数将返回空指针。

3、示例

在测试工程中,找一个UI,拖一个QComboBox组件到布局中,并将其提升为LLComboBox,如下图所示

在这里插入图片描述

在对应的cpp文件中,加入下面的测试代码

void TableWidgetTest::initComboBox()
{
    QStringList dataList;
    dataList << QString("语文") << QString("数学") << QString("英语") << QString("物理")
             << QString("化学") << QString("政治") << QString("体育") << QString("音乐");
    for (int var = 0; var < dataList.size(); ++var)
    {
        ui->comboBox->addDataItem(dataList[var]);
    }

    QStringList seledataList;
    seledataList << QString("语文") << QString("数学");
    ui->comboBox->setSelectedData(seledataList);
}

编译运行程序,查看效果。

4、总结

以上就是本文的所有内容了,欢迎留言讨论,源码下载地址 多选下拉列表下载地址

### Qt QComboBox 实现功能 在Qt中,默认情况下 `QComboBox` 并不支持功能。为了实现这一特性,通常的做法是自定义一个继承于 `QWidget` 或其他合适基类的小部件来模拟组合框的行为并提供能力。 一种常见的方法是在弹出窗口内放置个可勾项,并通过按钮或其他交互方式确认择项。下面是一个简单的例子展示如何创建一个的组合框: ```cpp #include <QCheckBox> #include <QVBoxLayout> #include <QPushButton> #include <QDialogButtonBox> #include <QListWidget> class MultiSelectComboBox : public QWidget { Q_OBJECT public: explicit MultiSelectComboBox(QWidget *parent = nullptr); private slots: void onItemClicked(QListWidgetItem*); signals: void selectionChanged(); private: QListWidget* listWidget; }; MultiSelectComboBox::MultiSelectComboBox(QWidget *parent) : QWidget(parent), listWidget(new QListWidget(this)) { QVBoxLayout* layout = new QVBoxLayout(this); QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, [=]() { emit selectionChanged(); }); connect(listWidget, &QListWidget::itemClicked, this, &MultiSelectComboBox::onItemClicked); layout->addWidget(listWidget); layout->addWidget(buttonBox); } void MultiSelectComboBox::onItemClicked(QListWidgetItem* item) { auto checkbox = dynamic_cast<QCheckBox*>(listWidget->itemWidget(item)); if (checkbox != nullptr && !checkbox->isChecked()) { checkbox->setChecked(true); } else if(checkbox != nullptr){ checkbox->setChecked(false); } } ``` 此代码片段展示了如何构建一个基本框架用于处理逻辑[^1]。请注意这只是一个起点;实际应用可能还需要考虑更细节如样式调整、数据绑定等。 对于更复杂的需求,可以探索第三方库或插件,这些工具往往已经实现了更加完善的功能集和支持更好的用户体验。
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凝望星辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值