Search code examples
c++qtqt5qstyleditemdelegate

image with 3 possibility of value


I would like to personalize the 3rd columns to contain QCheckBox widgets. I would like those QCheckBox widgets to be customized with three icons: 1.png (Default state) | 2.png (Selected state) | 3.png (Disabled state). So I could do this using a custom delegate with the following implementation:

#include "mydelegate.h"
#include <QCheckBox>
#include <QPainter>
#include <QKeyEvent>
#include <QtDebug>
#include <QApplication>
#include <QStyleOptionViewItem>


MyDelegate::MyDelegate(QObject* parent) :
QStyledItemDelegate(parent)
{
// 1.png
_icon.addPixmap(QPixmap("1.png"), QIcon::Active, QIcon::On);
// 2.png
_icon.addPixmap(QPixmap("2.png"), QIcon::Selected, QIcon::On);
// 3.png
_icon.addPixmap(QPixmap("3.png"), QIcon::Disabled, QIcon::On);
}

void MyDelegate::paint(QPainter* painter, const QStyleOptionViewItem& 
option, const QModelIndex& index) const
{
if (index.column() != 2)
    QStyledItemDelegate::paint(painter, option, index);
else
{
    bool value = index.model()->data(index, 
Qt::UserRole).toBool();
    QStyleOptionButton buttonVis;
    buttonVis.rect = option.rect;
    buttonVis.iconSize = QSize(50, 50);
    buttonVis.icon = _icon;
    buttonVis.features |= QStyleOptionButton::Flat;
    buttonVis.state |= value ? QStyle::State_Enabled : QStyle::State_None;
    QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonVis, painter);
}
}

bool MyDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, 
const QStyleOptionViewItem& option, const QModelIndex& index)
{
if (event->type() == QEvent::MouseButtonRelease)
{
    bool value = model->data(index, Qt::UserRole).toBool();
    model->setData(index, !value, Qt::UserRole);
}
return true;
}

The problem that it's work for 1.png and 3.png and not for the 2.png. i want that it will work for the three icons


Solution

  • It is not necessary to implement the paint(...) or use editorEvent(...) methods, it is only necessary to override the initStyleOption(...) method by enabling the option of the icon.

    In the following example the item (2, 2) is selected, the item (4, 2) is disabled and the other items are enabled but not selected showing 3 types of icons:

    #include <QtWidgets>
    
    class MyDelegate: public QStyledItemDelegate
    {
    public:
        MyDelegate(QObject *parent=nullptr):
            QStyledItemDelegate(parent)
        {
            m_icon.addPixmap(QPixmap("1.png"), QIcon::Active, QIcon::On);
            m_icon.addPixmap(QPixmap("2.png"), QIcon::Selected, QIcon::On);
            m_icon.addPixmap(QPixmap("3.png"), QIcon::Disabled, QIcon::On);
        }
        void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override{
            QStyledItemDelegate::initStyleOption(option, index);
            if (index.column() == 2){
                option->features |= QStyleOptionViewItem::HasDecoration;
                option->icon = m_icon;
                option->decorationSize = QSize(50, 50);
            }
        }
    private:
        QIcon m_icon;
    };
    
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        QTableWidget w(10, 4);
        MyDelegate *delegate = new MyDelegate(&w);
        w.setItemDelegate(delegate);
        QTableWidgetItem *item = new QTableWidgetItem;
        item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
        w.setItem(4, 2, item);
        w.show();
        return app.exec();
    }
    

    enter image description here

    Update: The OP is using an inadequate terminology since it refers to the status of a widget (normal, selected, disabled), instead it must indicate the states unchecked, partially checked and checked.

    #include <QtWidgets>
    
    class MyDelegate: public QStyledItemDelegate
    {
    public:
        MyDelegate(QObject *parent=nullptr):
            QStyledItemDelegate(parent)
        {
            uncheckedIcon = QIcon("1.png");
            partiallyCheckedIcon = QIcon("2.png");
            checkedIcon = QIcon("3.png");
        }
        void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override{
            QStyledItemDelegate::initStyleOption(option, index);
            if (index.column() == 2){
                QIcon m_icon;
                QVariant value = index.data(Qt::UserRole);
                Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
                if(state == Qt::Unchecked)
                    option->icon = uncheckedIcon;
                else if (state == Qt::PartiallyChecked)
                    option->icon = partiallyCheckedIcon;
                else
                    option->icon = checkedIcon;
                option->features |= QStyleOptionViewItem::HasDecoration;
                option->decorationSize = QSize(50, 50);
            }
        }
        bool editorEvent(QEvent* event, QAbstractItemModel* model,
                         const QStyleOptionViewItem& option, const QModelIndex& index) override
        {
            bool r = QStyledItemDelegate::editorEvent(event, model, option, index);
            if(index.column() != 2)
                return r;
            if ((event->type() == QEvent::MouseButtonRelease)
                    || (event->type() == QEvent::MouseButtonDblClick)
                    || (event->type() == QEvent::MouseButtonPress)) {
                if ((event->type() == QEvent::MouseButtonPress)
                        || (event->type() == QEvent::MouseButtonDblClick))
                    return true;
                QVariant value = index.data(Qt::UserRole);
                Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
                state = static_cast<Qt::CheckState>((state + 1) % 3);
                return model->setData(index, state, Qt::UserRole);
            }
            return r;
        }
    private:
        QIcon uncheckedIcon;
        QIcon partiallyCheckedIcon;
        QIcon checkedIcon;
    };
    
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        QTableWidget w(10, 4);
        MyDelegate *delegate = new MyDelegate(&w);
        w.setItemDelegate(delegate);
        w.resize(640, 480);
        w.show();
        return app.exec();
    }
    

    enter image description here