How to change the icon's 'on' state color?

Viewed 562

I am unable to change the icon's 'on' state color in Qt. I have the following test code:

header file:

#pragma once

#include <QtWidgets/QMainWindow>
#include <QApplication>
#include <QPushButton>
#include <QPainter>
#include <QIcon>
#include <QPixmap>
#include <QStyleFactory>
#include <QIconEngine>
#include "ui_mainwindow.h"

class MainWindow: public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = Q_NULLPTR);

private:
    Ui::MainWindowClass ui;
};

implementation file:

#include "mainwindow.h"

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    qApp->setStyle(QStyleFactory::create("Fusion"));
    ui.setupUi(this);
    QWidgetList allWidgets = qApp->allWidgets();
    for (QWidget* wid : allWidgets) {
        QString str = wid->metaObject()->className();
        if (str == "QPushButton") {
            auto btn = dynamic_cast<QPushButton*>(wid);
            if (!btn->icon().isNull()) {
                QIcon btnIcon = btn->icon();
                QPixmap pixOff = btnIcon.pixmap(QSize(1024, 1024));
                QPixmap pixOn = btnIcon.pixmap(QSize(1024, 1024));
                QPixmap pixDisOff = btnIcon.pixmap(QSize(1024, 1024));
                QPixmap pixDisOn = btnIcon.pixmap(QSize(1024, 1024));

                QPainter paintOff(&pixOff);
                paintOff.setCompositionMode(QPainter::CompositionMode_SourceIn);
                paintOff.fillRect(pixOff.rect(), Qt::green);

                QPainter paintOn(&pixOn);
                paintOn.setCompositionMode(QPainter::CompositionMode_SourceIn);
                paintOn.fillRect(pixOn.rect(), Qt::red);

                QPainter paintDisOff(&pixDisOff);
                paintDisOff.setCompositionMode(QPainter::CompositionMode_SourceIn);
                paintDisOff.fillRect(pixDisOff.rect(), Qt::yellow);

                QPainter paintDisOn(&pixDisOn);
                paintDisOn.setCompositionMode(QPainter::CompositionMode_SourceIn);
                paintDisOn.fillRect(pixDisOn.rect(), Qt::blue);

                btnIcon.addPixmap(pixOff, QIcon::Normal, QIcon::Off);
                btnIcon.addPixmap(pixDisOff, QIcon::Disabled, QIcon::Off);
                btnIcon.addPixmap(pixOff, QIcon::Active, QIcon::Off);
                btnIcon.addPixmap(pixOff, QIcon::Selected, QIcon::Off);
                btnIcon.addPixmap(pixOn, QIcon::Normal, QIcon::On);
                btnIcon.addPixmap(pixDisOn, QIcon::Disabled, QIcon::On);
                btnIcon.addPixmap(pixOn, QIcon::Active, QIcon::On);
                btnIcon.addPixmap(pixOn, QIcon::Selected, QIcon::On);

                btn->setIcon(btnIcon);
            }
        }
    }
}

In my .ui file I add a few QPushButton and apply pixmaps as their icons:

Form_File

From left to right: Disabled Button, Checkable Button, Non-Checkable Button.

These buttons are placed in a checkable QGroupBox so that I can enable/disable them simultaneously.

When I run my code this is how it appears (the color for disabled is yellow so it is not much visible):

Run_1

Here the color for the middle QPushButton should be Qt::red since it is in checked (i.e. QIcon::On) state, but it is not red.

When I uncheck the groupbox, all the buttons becomes disabled and the icons change to QIcon::Disabled, QIcon::Off:

Run_2

The QIcon::Disabled, QIcon::On color is Qt::blue, and the middle button is in checked and disabled state, which means it should be blue but it is not.

The icons never change color to QIcon::Normal, QIcon::On or any other QIcon::On state. This means that the QIcon::Off state color is being applied correctly, but the QIcon::On state color is not being applied. Any ideas on how to solve this issue?

1 Answers

Preparing a minimal and reproducible example is always the right approach to solving the problem. Here is one that I have written for you and it is working:

#include <QApplication>
#include <QBoxLayout>
#include <QPushButton>
#include <QPainter>

class MainWindow : public QWidget
{
public:
    MainWindow(QWidget *parent = nullptr) : QWidget(parent)
    {
        auto *l = new QVBoxLayout(this);
        auto *button = new QPushButton(tr("Click Me"), this);

        QPixmap pixOff(":/pix/images/save.png");
        QPixmap pixOn(pixOff);

        QPainter painter;

        painter.begin(&pixOn);
        painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
        painter.fillRect(pixOn.rect(), Qt::red);
        painter.end();

        painter.begin(&pixOff);
        painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
        painter.fillRect(pixOff.rect(), Qt::green);
        painter.end();

        QIcon icon;

        icon.addPixmap(pixOff, QIcon::Normal, QIcon::Off);
        icon.addPixmap(pixOn, QIcon::Normal, QIcon::On);

        button->setIcon(icon);
        button->setCheckable(true);
        button->setChecked(true);

        l->addWidget(button);
        l->addStretch();

        resize(200, 100);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    w.show();

    return a.exec();
}

Note: The example uses a 16x16 png-image from the resources. You should substitute it with your own image.

The example produces the following result:

Checked state of a button Unchecked state of a button

Related