【Qt】自定义QComboBox实现下拉选项添加删除按钮,回车添加选项


前言

记录下Qt的自定义QComboBox下拉选项添加删除按钮功能。


提示:以下是本篇文章正文内容,下面案例可供参考

1.效果展示

请添加图片描述
请添加图片描述

2.comboview.h

代码如下(示例):

#ifndef COMBOVIEW_H
#define COMBOVIEW_H

#include <QDebug>
#include <QStyle>
#include <QLayout>
#include <QLineEdit>
#include <QComboBox>
#include <QListView>
#include <QScrollBar>
#include <QListWidget>
#include <QPushButton>
#include <QMouseEvent>
#include <QStyledItemDelegate>
#include <QStyleOptionViewItem>

class ComboView : public QListWidget
{
    Q_OBJECT
public:
    explicit ComboView(QWidget * parent=nullptr);
    QRect visualRect(const QModelIndex &index) const override;
};

class ComboItem : public QWidget
{
    Q_OBJECT
public:
    explicit ComboItem(const QString &text,QWidget *parent = nullptr);
    QString text() const;
signals:
    void itemClicked(const QString &text);
private:
    QString textValue;
    QPushButton *btn;
};

class ComboDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    explicit ComboDelegate(QObject *parent=nullptr);
    void paint(QPainter *painter, const QStyleOptionViewItem &option,
               const QModelIndex &index) const override;
};

class MyComboBox : public QComboBox
{
    Q_OBJECT
public:
    explicit MyComboBox(QWidget *parent = nullptr);
    //设置下拉选项
    void setRemovableItems(const QStringList &items);
    //显示弹框
    void showPopup() override;
    void hidePopup() override;
    void MyAddItem(const QString &text);
    void addCurruntText(QString text);
    void addKeyEnterText();
signals:
    void itemChange();
protected:
    void keyReleaseEvent(QKeyEvent *event);
private:
    QListWidget *itemList;
};

#endif // COMBOVIEW_H


3.comboview.cpp

代码如下(示例):

#include "comboview.h"

ComboView::ComboView(QWidget *parent)
    : QListWidget(parent)
{

}

QRect ComboView::visualRect(const QModelIndex &index) const
{
    QRect rect = QListWidget::visualRect(index);
    int width = this->width();
    if(verticalScrollBar()->isVisible()){
        width -= verticalScrollBar()->width();
    }
    rect.setWidth(width);
    return rect;
}

ComboItem::ComboItem(const QString &text, QWidget *parent)
    : QWidget(parent),
      textValue(text)
{
    btn = new QPushButton(this);
    btn->setFixedSize(18,18);
    btn->setStyleSheet("QPushButton{background-color: transparent; border: none;border-image: url(style/icons/delete.png);}"
                       "QPushButton:hover{border-image: url(style/icons/delete_hover.png);}");
    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->addStretch();
    layout->addWidget(btn);
    layout->setContentsMargins(5,0,5,0);
    layout->setSpacing(0);
    this->setLayout(layout);
    connect(btn,&QPushButton::clicked,[this]{
        emit itemClicked(textValue);
    });
}

QString ComboItem::text() const
{
    return textValue;
}

ComboDelegate::ComboDelegate(QObject *parent)
    : QStyledItemDelegate(parent)
{

}

void ComboDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItem opt(option);
    //去掉焦点带来的虚线框
    opt.state &= ~QStyle::State_HasFocus;
    initStyleOption(&opt, index);
    QStyledItemDelegate::paint(painter, opt, index);
}

MyComboBox::MyComboBox(QWidget *parent)
    : QComboBox(parent),
      itemList(new ComboView(this))
{
//    itemList->setTextElideMode(Qt::ElideNone);
    setModel(itemList->model());
    setView(itemList);
    setEditable(true);
    setItemDelegate(new ComboDelegate(this));
    setMaxVisibleItems(5);
}

void MyComboBox::setRemovableItems(const QStringList &items)
{
    //combox的additem insertitem不是虚函数
    //实现里时调用的model->insertRow,但是懒得再去重写listmodel-view,就新增一个接口
    itemList->clear();
    if(items.isEmpty())
        return;
    for(int i = 0;i < items.count();i++){
        MyAddItem(items.at(i));
    }
}

void MyComboBox::MyAddItem(const QString &text)
{
    QListWidgetItem* widget_item = new QListWidgetItem(itemList);
    ComboItem *item = new ComboItem(text,itemList);
    widget_item->setData(Qt::DisplayRole,text);
    itemList->setItemWidget(widget_item, item);
    connect(item,&ComboItem::itemClicked,this,[this,item,widget_item](){
        //take移除item后没有刷新弹框大小,干脆隐藏掉先
        hidePopup();
        itemList->takeItem(itemList->row(widget_item));
        delete widget_item;
        if(itemList->count() <= 5){
            for (int i = 0; i < itemList->count(); i++){
                QWidget *nwidget = itemList->itemWidget(itemList->item(i));
                QHBoxLayout *layout = (QHBoxLayout *)nwidget->layout();
                layout->setContentsMargins(5,0,5,0);
                nwidget->setLayout(layout);
            }
        }
        emit itemChange();
    });
    if(itemList->count() > 5){
        for (int i = 0; i < itemList->count(); i++){
            QWidget *nwidget = itemList->itemWidget(itemList->item(i));
            QHBoxLayout *layout = (QHBoxLayout *)nwidget->layout();
            layout->setContentsMargins(5,0,15,0);
            nwidget->setLayout(layout);
        }
    }
}

void MyComboBox::addCurruntText(QString text)
{
    for (int i = 0; i < count(); ++i) {
        ComboItem *m_widget = qobject_cast<ComboItem *>(itemList->itemWidget(itemList->item(i)));
        if(!m_widget) removeItem(i);
    }
    for (int i = 0; i < count(); ++i) {
        if(itemText(i) == text) return;
    }
    MyAddItem(text);
    setCurrentIndex(this->count()-1);
}

void MyComboBox::addKeyEnterText()
{
    QString text = currentText();
    addCurruntText(text);
}

void MyComboBox::keyReleaseEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Enter|| event->key() == Qt::Key_Return){
        addKeyEnterText();
    }
    else {
        QComboBox::keyPressEvent(event);
    }
}

void MyComboBox::showPopup()
{
    QComboBox::showPopup();
}

void MyComboBox::hidePopup()
{
    QStyle * const style = this->style();
    QStyleOptionComboBox opt;
    initStyleOption(&opt);
    view()->scrollTo(view()->currentIndex(),
                     style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)
                     ? QAbstractItemView::PositionAtCenter
                     : QAbstractItemView::EnsureVisible);
    QComboBox::hidePopup();
}



总结

参考了网上的资料,自己修改了一些自己需要的功能,记录一下以后可能还会用到,也方便其他人需要的参考一下。

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值