c++qtqt5qtablewidgetqpalette

Mimic QApplication::palette() based color style behavior


It is very simple: I want to mimic the change in color of an item being disabled without disabling it.

Having QTableWidgetItem and QStandardItem items, I am using code like this

item->setForeground( enabled ? QApplication::palette().color( QPalette::Text ) : QApplication::palette().color( QPalette::Disabled, QPalette::Text ) );

right now. However, if the user calls QApplication::setPalette( ... ) using a new palette, the item has to be manually refreshed. I would much rather set a ColorGroup and Role, so Qt knows how to refresh. Is it possible to do that?


Solution

  • To be automatic you must overwrite the initStyleOption() method of QStyledItemDelegate and associate the fake enable with a new role:

    #include <QtWidgets>
    
    enum FakeRoles {
        FakeEnableRole = Qt::UserRole + 1000
    };
    
    class ForegroundDelegate: public QStyledItemDelegate
    {
    public:
        using QStyledItemDelegate::QStyledItemDelegate;
    protected:
        void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override{
            QStyledItemDelegate::initStyleOption(option, index);
            QVariant val = index.data(FakeRoles::FakeEnableRole);
            if(val.canConvert<bool>()){
                bool enabled = val.value<bool>();
                option->palette.setBrush(QPalette::Text,
                                         QApplication::palette().color(enabled ? QPalette::Active:
                                                                                 QPalette::Disabled, QPalette::Text));
            }
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        QTableWidget w(4, 4);
        ForegroundDelegate *delegate = new ForegroundDelegate(&w);
        w.setItemDelegate(delegate);
        for(int i=0; i< w.rowCount(); ++i)
            for (int j=0; j< w.columnCount(); ++j) {
                QTableWidgetItem *it = new QTableWidgetItem(QString("%1-%2").arg(i).arg(j));
                w.setItem(i, j, it);
                bool enabled =  QRandomGenerator::global()->bounded(0, 2) == 0;
                it->setData(FakeRoles::FakeEnableRole, enabled);
            }
        w.show();
        QTimer::singleShot(1000, [](){
            QPalette pal = QApplication::palette();
            pal.setColor(QPalette::Active, QPalette::Text, QColor("salmon"));
            pal.setColor(QPalette::Disabled, QPalette::Text, QColor("cyan"));
            QApplication::setPalette(pal);
        });
        return a.exec();
    }