Qt实现多选下拉框

本文介绍了一种实现多选下拉框的方法,通过继承QComboBox并重写相关函数,结合QListView和QStandardItemModel实现。详细介绍了代码实现过程,包括样式设置、事件过滤器以及添加、删除选项等功能。同时提供了源码下载链接。
摘要由CSDN通过智能技术生成

一、效果展示

二、实现思路

写一个类MultiSelectComboBox继承QComboBox,要实现多选则可以设置QComboBox的View,通过view的item设置可以多选,然后重写QComboBox的showPopup、hidePopup、eventFilter,控制下列表框点框的弹出有关闭。

三、代码实现

multiselectcombobox.h

#ifndef MULTISELECTCOMBOBOX_H
#define MULTISELECTCOMBOBOX_H

#include <QWidget>
#include <QListView>
#include <QStandardItemModel>
#include <QComboBox>
class MultiSelectComboBox : public QComboBox
{
    Q_OBJECT

public:
    MultiSelectComboBox(QWidget *parent = nullptr);
    ~MultiSelectComboBox() override;
    void addItem(const QString &text, const QVariant &userData = QVariant());
    void addItem(const QIcon &icon, const QString &text, const QVariant &userData = QVariant());
    void addItems(const QStringList &texts);
    QStringList currentText();
    QList<int> currentIndex();
protected:
    bool eventFilter(QObject *watched, QEvent *event) override;
    void showPopup() override;
    void hidePopup() override;
private:
    bool isPermitHidePopup;
    QListView* selectItemView;
    QStandardItemModel* selectModel;
    QListView* popupView;
    QStandardItemModel* popupModel;
    void selectItemViewPress(QPoint pos);


};

#endif // MULTISELECTCOMBOBOX_H

multiselectcombobox.cpp

#include "multiselectcombobox.h"
#include <QStandardItem>
#include <QHBoxLayout>
#include <QEvent>
#include <QMouseEvent>
MultiSelectComboBox::MultiSelectComboBox(QWidget *parent)
    : QComboBox(parent)
{
    //去掉下拉箭头
    setStyleSheet("QComboBox::drop-down{border-style:none;}");
    //设置可编辑
    setEditable(true);
    //selectItemView盖住QComboBox
    selectItemView=new QListView(this);
    selectItemView->setMinimumHeight(30);
    //QListView{outline: none;} 去掉项虚线框                     设置正常状态和选中为状态item的背景色相同
    selectItemView->setStyleSheet("QListView{outline: none;} QListView::item {background:#BDD7FD;} QListView::item:hover {background: #BDD7FD;}");
    selectItemView->setIconSize(QSize(12,12));
    //设置各项的间隔
    selectItemView->setSpacing(3);
    //设置为不触发,不然点击可修改项内容
    selectItemView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    //设置会调整
    selectItemView->setResizeMode(QListView::Adjust);
    //设置为自动换行
    selectItemView->setWrapping(true);
    //设置浮动方向
    selectItemView->setFlow(QListView::LeftToRight);
    //水平滚动条设置不不显示
    selectItemView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    //选择模式设置为不显示
    selectItemView->setSelectionMode(QAbstractItemView::NoSelection);

    selectModel=new QStandardItemModel();
    selectItemView->setModel(selectModel);

    QHBoxLayout* lineLayout=new QHBoxLayout(this);
    lineLayout->setMargin(0);
    lineLayout->setSpacing(0);
    lineLayout->addWidget(selectItemView);

    //安装事件过滤器,处理点击x删除
    selectItemView->viewport()->installEventFilter(this);
    popupView=new QListView();
    popupModel=new QStandardItemModel();
    popupView->setModel(popupModel);
    setView(popupView);
    setModel(popupModel);
    installEventFilter(this);
    //激活下拉列表某行的信号处理函数
    connect(this, QOverload<int>::of(&QComboBox::activated),
         [=](int index){
        bool hasExist=false;
        QStandardItem* clickItem=popupModel->item(index);
        QString text=clickItem->text();
        //判断项是否已经选过,选过则删除选中项
        for(int row=0;row<selectModel->rowCount();row++)
        {
            QStandardItem* item=selectModel->item(row);
            if(item->text()==text)
            {
                selectModel->removeRow(row);
                hasExist=true;
                break;
            }
        }
        if(!hasExist)
        {
            //没选过则添加,并改变选项的状态
            clickItem->setCheckState(Qt::Checked);
            QStandardItem* item=new QStandardItem(QIcon("://del.png"),text);
            selectModel->appendRow(item);
        }
        else
        {
            //选中过点击改为未选中状态
            clickItem->setCheckState(Qt::Unchecked);
        }
    });
    //frame为弹出下拉列表框
    QFrame* frame=this->findChild<QFrame*>();
    if(frame)
    {
        frame->installEventFilter(this);
    }
   installEventFilter(this);

}

MultiSelectComboBox::~MultiSelectComboBox()
{

}
//所有添加项的方法都选调用父类方式再设置可以check
void MultiSelectComboBox::addItem(const QString &text, const QVariant &userData)
{
    QComboBox::addItem(text,userData);
    popupModel->item(findText(text))->setCheckable(true);

}

void MultiSelectComboBox::addItem(const QIcon &icon, const QString &text, const QVariant &userData)
{
    QComboBox::addItem(icon,text,userData);
    popupModel->item(findText(text))->setCheckable(true);
}

void MultiSelectComboBox::addItems(const QStringList &texts)
{
    QComboBox::addItems(texts);
    for(int row=0;row<popupModel->rowCount();row++)
    {
        popupModel->item(row)->setCheckable(true);
    }
}

//返回所有选中项的内容,用QStringList存储
QStringList MultiSelectComboBox::currentText()
{
    QStringList items;
    for(int row=0;row<popupModel->rowCount();row++)
    {
        QStandardItem* item=popupModel->item(row);
        if(item->checkState()==Qt::Checked)
        {
            items<<item->text();
        }
    }
    return items;
}
//返回所有选中项的索引,用QList<int>存储
QList<int> MultiSelectComboBox::currentIndex()
{
    QList<int> indexs;
    for(int row=0;row<popupModel->rowCount();row++)
    {
        QStandardItem* item=popupModel->item(row);
        if(item->checkState()==Qt::Checked)
        {
            indexs<<row;
        }
    }
    return indexs;
}

bool MultiSelectComboBox::eventFilter(QObject *watched, QEvent *event)
{
    QFrame* frame=this->findChild<QFrame*>();
    if(frame&&frame==watched)
    {

        if(event->type()==QEvent::MouseButtonPress)
        {
            QMouseEvent* mouseEvent=static_cast<QMouseEvent*>(event);
            QPoint globalPos=mouseEvent->globalPos();
            QRect rect(frame->mapToGlobal(QPoint(0,0)),QSize(frame->width(),frame->height()));
            QRect rect1(selectItemView->viewport()->mapToGlobal(QPoint(0,0)),QSize(selectItemView->viewport()->width(),selectItemView->viewport()->height()));
            //不在下拉列表框和显示选项项的viewport范围内的按下则允许关闭
            if(!rect.contains(globalPos)&&!rect1.contains(globalPos))
            {
                isPermitHidePopup=true;

            }
            else
            {
                selectItemViewPress(selectItemView->viewport()->mapFromGlobal(globalPos));
            }

        }

    }

    if(watched==selectItemView->viewport())
    {
        //处理selectItemView->viewport的鼠标按下事件
        if(event->type()==QEvent::MouseButtonPress)
        {
            QMouseEvent* mouseEvent=static_cast<QMouseEvent*>(event);
            selectItemViewPress(mouseEvent->pos());
        }
    }
    //屏蔽滑轮事件
    if(watched==this)
    {
        if(event->type()==QEvent::Wheel)
        {
            return true;
        }

    }

    return QComboBox::eventFilter(watched,event);
}

void MultiSelectComboBox::showPopup()
{
    QComboBox::showPopup();
    isPermitHidePopup=false;
}

void MultiSelectComboBox::hidePopup()
{
    if(isPermitHidePopup)
    {
        QComboBox::hidePopup();
    }
}

void MultiSelectComboBox::selectItemViewPress(QPoint pos)
{
    QModelIndex index=selectItemView->indexAt(pos);
    //有效,则该坐标有选中项
    if(index.isValid())
    {
        QRect rect=selectItemView->visualRect(index);
        QSize iconSize=selectItemView->iconSize();
        //x图标的区域
        QRect iconRect=QRect(rect.left(),rect.top(),iconSize.width(),iconSize.height());
        //鼠标在x图标的区域内
        if(iconRect.contains(pos))
        {
            QStandardItem* item=selectModel->itemFromIndex(index);
            //修改状态为未选中
            popupModel->item(findText(item->text()))->setCheckState(Qt::Unchecked);
            //删除项
            selectModel->removeRow(index.row());

        }

    }
    showPopup();

}



四、源码下载

源码点击下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

i2program

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

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

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

打赏作者

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

抵扣说明:

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

余额充值