C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > Qt 多选功能的组合复选框

Qt实现带多选功能的组合复选框

作者:流星雨爱编程

本文介绍了一个基于Qt的带复选框多选功能的掩码组合框QMaskComboBox的实现,使用QListWidget+QCheckBox实现多选下拉列表功能,感兴趣的可以了解一下

1.整体功能解析

实现效果如下:

带复选框多选功能的掩码组合框 QMaskComboBox,继承自 QComboBox,核心特性:

2.核心模块拆解

2.1.头文件结构(QMaskComboBox.h)

class QMaskComboBox : public QComboBox
{
    Q_OBJECT
public:
    using mask_vector = QVector<std::pair<uint64_t, QString>>;

    explicit QMaskComboBox(QWidget* parent = nullptr);
    explicit QMaskComboBox(const mask_vector& maskList, uint64_t val = 0, QWidget* parent = nullptr);

    const mask_vector& mask() const;
    void setMask(const mask_vector& val);
    void setMask(const mask_vector& val, uint64_t select);

    uint64_t selectMask() const noexcept;
    void setSelectMask(uint64_t val);

    void hidePopup() override;
    bool eventFilter(QObject* watched, QEvent* evt) override;

Q_SIGNALS:
    void selectMaskPopup(qulonglong);

private:
    void refresh();
private slots:
    void onStateChanged(uint64_t bits, int state);

private:
    QListWidget* m_pListWidget;
    mask_vector m_mask;
    uint64_t m_selectMask;
};

2.2.关键实现解析

1.构造函数与事件过滤

QMaskComboBox::QMaskComboBox(QWidget* parent)
    : QComboBox(parent)
    , m_pListWidget(nullptr)
    , m_selectMask(0)
{
    setEditable(true);
    lineEdit()->installEventFilter(this);
}

bool QMaskComboBox::eventFilter(QObject* watched, QEvent* evt)
{
    if (watched == lineEdit() && evt->type() == QEvent::MouseButtonPress)
    {
        showPopup();
        return true;
    }
    return QComboBox::eventFilter(watched, evt);
}

2.refresh() 函数(核心逻辑)

void QMaskComboBox::refresh()
{
    clear();
    delete model();
    delete view();

    lineEdit()->setReadOnly(true);
    m_pListWidget = new QListWidget(this);
    m_pListWidget->setObjectName("listView");

    QString selectData;
    QString tipData;

    for (auto& kv : m_mask)
    {
        uint64_t bits = kv.first;
        QString desc = kv.second;

        QListWidgetItem* pItem = new QListWidgetItem(m_pListWidget);
        pItem->setData(Qt::UserRole, QVariant::fromValue(bits));

        QCheckBox* pCheckBox = new QCheckBox(this);
        pCheckBox->setText(desc);
        bool checked = (bits & m_selectMask) == bits;
        pCheckBox->setChecked(checked);

        if (checked)
        {
            if (!selectData.isEmpty())
            {
                selectData.append(";");
                tipData.append("\n");
            }
            selectData.append(kv.second);
            tipData.append(kv.second);
        }

        connect(pCheckBox, &QCheckBox::stateChanged, 
                [this, bits](int state) { onStateChanged(bits, state); });

        m_pListWidget->addItem(pItem);
        m_pListWidget->setItemWidget(pItem, pCheckBox);
    }

    setModel(m_pListWidget->model());
    setView(m_pListWidget);

    if (!selectData.isEmpty())
    {
        lineEdit()->setText(selectData);
        lineEdit()->setToolTip(tipData);
    }
    else
    {
        lineEdit()->clear();
    }
}

3.onStateChanged 槽函数

void QMaskComboBox::onStateChanged(uint64_t bits, int state)
{
    if (state)
        m_selectMask |= bits;
    else
        m_selectMask &= ~bits;

    QString selectData;
    QString tipData;

    int nCount = m_pListWidget->count();
    for (int i = 0; i < nCount; ++i)
    {
        QListWidgetItem* pItem = m_pListWidget->item(i);
        QWidget* pWidget = m_pListWidget->itemWidget(pItem);
        QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(pWidget);

        const auto& kv = m_mask[i];
        bool checked = (kv.first & m_selectMask) == kv.first;
        pCheckBox->setChecked(checked);

        if (checked)
        {
            if (!selectData.isEmpty())
            {
                selectData.append(";");
                tipData.append("\n");
            }
            selectData.append(kv.second);
            tipData.append(kv.second);
        }
    }

    if (!selectData.isEmpty())
    {
        lineEdit()->setText(selectData);
        lineEdit()->setToolTip(tipData);
    }
    else
    {
        lineEdit()->clear();
    }
}

4.hidePopup() 重写

void QMaskComboBox::hidePopup()
{
    emit selectMaskPopup(m_selectMask);
    QComboBox::hidePopup();
}

下拉框隐藏时,发射 selectMaskPopup 信号,通知外部当前掩码值

3.完整代码示例

// QMaskComboBox.h
#ifndef QMASKCOMBOBOX_H
#define QMASKCOMBOBOX_H

#include <QComboBox>
#include <QListWidget>
#include <QCheckBox>

class QMaskComboBox : public QComboBox
{
    Q_OBJECT
public:
    using mask_vector = QVector<std::pair<uint64_t, QString>>;

    explicit QMaskComboBox(QWidget* parent = nullptr);
    explicit QMaskComboBox(const mask_vector& maskList, uint64_t val = 0, QWidget* parent = nullptr);

    const mask_vector& mask() const;
    void setMask(const mask_vector& val);
    void setMask(const mask_vector& val, uint64_t select);

    uint64_t selectMask() const noexcept;
    void setSelectMask(uint64_t val);

    void hidePopup() override;
    bool eventFilter(QObject* watched, QEvent* evt) override;

Q_SIGNALS:
    void selectMaskPopup(qulonglong);

private:
    void refresh();
    void updateText();

private slots:
    void onStateChanged(int state);

private:
    mask_vector m_mask;
    uint64_t m_selectMask = 0;
    QListWidget* m_pListWidget = nullptr;
};

#endif // QMASKCOMBOBOX_H
// QMaskComboBox.cpp
#include "QMaskComboBox.h"

QMaskComboBox::QMaskComboBox(QWidget* parent)
    : QComboBox(parent)
{
    setEditable(true);
    lineEdit()->setReadOnly(true);
    lineEdit()->installEventFilter(this);
}

QMaskComboBox::QMaskComboBox(const mask_vector& maskList, uint64_t val, QWidget* parent)
    : QMaskComboBox(parent)
{
    m_mask = maskList;
    m_selectMask = val;
    refresh();
}

const QMaskComboBox::mask_vector& QMaskComboBox::mask() const
{
    return m_mask;
}

void QMaskComboBox::setMask(const mask_vector& val)
{
    m_mask = val;
    refresh();
}

void QMaskComboBox::setMask(const mask_vector& val, uint64_t select)
{
    m_mask = val;
    m_selectMask = select;
    refresh();
}

uint64_t QMaskComboBox::selectMask() const noexcept
{
    return m_selectMask;
}

void QMaskComboBox::setSelectMask(uint64_t val)
{
    m_selectMask = val;
    updateText();
    refresh();
}

bool QMaskComboBox::eventFilter(QObject* watched, QEvent* evt)
{
    if (watched == lineEdit() && evt->type() == QEvent::MouseButtonPress)
    {
        showPopup();
        return true;
    }
    return QComboBox::eventFilter(watched, evt);
}

void QMaskComboBox::hidePopup()
{
    emit selectMaskPopup(m_selectMask);
    QComboBox::hidePopup();
}

void QMaskComboBox::refresh()
{
    // 清理旧的 view 和 model
    if (m_pListWidget)
    {
        delete m_pListWidget;
        m_pListWidget = nullptr;
    }

    clear();
    setModel(nullptr);
    setView(nullptr);

    m_pListWidget = new QListWidget(this);
    m_pListWidget->setObjectName("listView");

    for (auto& kv : m_mask)
    {
        uint64_t bits = kv.first;
        QString desc = kv.second;

        QListWidgetItem* pItem = new QListWidgetItem(m_pListWidget);
        QCheckBox* pCheckBox = new QCheckBox(desc, m_pListWidget);
        pCheckBox->setProperty("maskBits", bits);
        bool checked = (bits & m_selectMask) == bits;
        pCheckBox->setChecked(checked);

        connect(pCheckBox, &QCheckBox::stateChanged, this, &QMaskComboBox::onStateChanged);

        m_pListWidget->setItemWidget(pItem, pCheckBox);
    }

    setModel(m_pListWidget->model());
    setView(m_pListWidget);
    updateText();
}

void QMaskComboBox::updateText()
{
    QString selectData;
    QString tipData;

    for (auto& kv : m_mask)
    {
        if ((kv.first & m_selectMask) == kv.first)
        {
            if (!selectData.isEmpty())
            {
                selectData.append(";");
                tipData.append("\n");
            }
            selectData.append(kv.second);
            tipData.append(kv.second);
        }
    }

    if (!selectData.isEmpty())
    {
        lineEdit()->setText(selectData);
        lineEdit()->setToolTip(tipData);
    }
    else
    {
        lineEdit()->clear();
        lineEdit()->setToolTip("");
    }
}

void QMaskComboBox::onStateChanged(int state)
{
    QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
    if (!pCheckBox) return;

    uint64_t bits = pCheckBox->property("maskBits").toULongLong();
    if (state)
        m_selectMask |= bits;
    else
        m_selectMask &= ~bits;

    updateText();
}

4.使用示例

// 定义掩码选项
QMaskComboBox::mask_vector masks = {
    {0x01, "选项A"},
    {0x02, "选项B"},
    {0x04, "选项C"},
    {0x08, "选项D"}
};

// 创建控件并设置选项
QMaskComboBox* combo = new QMaskComboBox(this);
combo->setMask(masks, 0x01 | 0x04); // 默认选中选项A和C

// 监听掩码变化
connect(combo, &QMaskComboBox::selectMaskPopup, this, [](qulonglong mask) {
    qDebug() << "当前选中掩码:" << mask;
});

到此这篇关于Qt实现带多选功能的组合复选框的文章就介绍到这了,更多相关Qt 多选功能的组合复选框内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文