QComboBox实现每个item都可删除

发布于:2025-02-27 ⋅ 阅读:(18) ⋅ 点赞:(0)

1. 前言

        前段时间一直研究如何实现QComboBox的每个item都可以删除, 也就是在每个item的最右侧都有一个Icon, 点击这个Icon就可以删除当前item. 网上也有很多代码, 但都不太符合我的要求, 要么代码太多, 要么实现的不对, 还有让我花钱买的, 还有让我关注的, 所以一直都没有太大进展. 后面我转变思路, 用qml实现了类似的功能, 然后让ChatGPT根据qml帮我实现, 效果还不错.

2. 环境

        qt6.5.3
        win11专业版

3. qml代码

// pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Dialogs
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Controls.Basic

ApplicationWindow {
    id: appWindow
    title: "qb"
    visible: true
    width: 320
    height: 900
    maximumWidth: 320
    maximumHeight: 900
    minimumWidth: 320
    minimumHeight: 900

    Component.onCompleted: {
        for (var i = 0; i < 5; i++) {
            var obj = {"itemName":i}
            appComboModel.append(obj)
        }
    }

    ComboBox {
        id: appCombo
        width: 100
        height: 30
        font.pixelSize: 12
        model: ListModel {
            id: appComboModel
        }
        textRole: "itemName"

        delegate: ItemDelegate {
            width: appCombo.width
            height: appCombo.height
            highlighted: appCombo.highlightedIndex === index

            // 输入框
            Text {
                text: itemName
                width: parent.width
                height: parent.height
                font.pixelSize: 12
                verticalAlignment: Text.AlignVCenter
                rightPadding: parent.height // 为右侧图标留出空间

                // 绘制右侧图标
                Rectangle {
                    width: parent.height
                    height: parent.height
                    anchors.right: parent.right
                    anchors.verticalCenter: parent.verticalCenter
                    color: "transparent"

                    Image {
                        source: "qrc:/img/clear.png"
                        anchors.centerIn: parent
                        width: parent.width
                        height: parent.height
                    }

                    // 捕获右侧点击事件
                    MouseArea {
                        anchors.fill: parent
                        cursorShape: Qt.PointingHandCursor
                        onClicked: {
                            appCombo.model.remove(index)
                        }
                    }
                }
            }
        }
    }
}

4. QComboBox代码

        其实告诉ChatGPT实现ItemDelegate即可, 代码如下:

#ifndef COMBOCLEAR_H
#define COMBOCLEAR_H

#include <QComboBox>
#include <QPainter>
#include <QMouseEvent>
#include <QStyledItemDelegate>
#include <QIcon>

class ClearItemDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    explicit ClearItemDelegate(QObject *parent = nullptr)
        : QStyledItemDelegate(parent), clearIcon(":/img/clear.png") {}

    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
    {
        // 默认绘制文本
        QStyledItemDelegate::paint(painter, option, index);

        // 计算清除按钮的区域(高 DPI 兼容)
        int iconSize = option.rect.height();
        QRect iconRect(option.rect.right() - iconSize, option.rect.top(), iconSize, iconSize);

        // 画背景
        painter->fillRect(iconRect, QColor(220, 220, 220)); // 灰色背景

        // 画边框
        painter->setPen(QPen(Qt::black, 1)); // 黑色边框
        painter->drawRect(iconRect);

        // 画删除图标
        clearIcon.paint(painter, iconRect);
    }

    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            int iconSize = option.rect.height();
            QRect iconRect(option.rect.right() - iconSize, option.rect.top(), iconSize, iconSize);

            if (iconRect.contains(mouseEvent->pos()))
            {
                // 触发删除信号
                emit clearItem(index);
                return true;
            }
        }
        return QStyledItemDelegate::editorEvent(event, model, option, index);
    }

signals:
    void clearItem(const QModelIndex &index);

private:
    QIcon clearIcon;
};

class ComboClear : public QComboBox
{
    Q_OBJECT
public:
    explicit ComboClear(QWidget *parent = nullptr) : QComboBox(parent)
    {
        ClearItemDelegate *delegate = new ClearItemDelegate(this);
        setItemDelegate(delegate);

        // 连接信号槽,删除点击的 item
        connect(delegate, &ClearItemDelegate::clearItem, this, &ComboClear::onClearItem);
    }

private slots:
    void onClearItem(const QModelIndex &index)
    {
        if (!index.isValid())
            return;

        // 获取被删除项的文本
        QString deletedText = model()->data(index, Qt::DisplayRole).toString();

        // 删除 model 里的项
        int row = index.row();
        model()->removeRow(row);

        // 选中上一个如果有的话
        if (model()->rowCount() > 0)
        {
            setCurrentIndex(qMax(0, row - 1));
        }

        // 触发信号,通知外部
        emit clearItemText(deletedText);
    }

signals:
    void clearItemText(const QString &text);
};

#endif // COMBOCLEAR_H


 

5. 结束

        毕竟不是专业做Qt, 如有问题请指教, 不胜感激.