1

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?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
DrPepperJo
  • 632
  • 1
  • 5
  • 19

1 Answers1

1

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();
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • This was exactly what I was looking for, thank you very much! – DrPepperJo Apr 11 '19 at 21:17
  • So while this worked fine for the QTableWidget example, it seems to overwrite all kinds of style options other than the text, when used with QComboBox. It even seems to mess with the text of the item in some cases. Any idea what I could be doing wrong here? – DrPepperJo Apr 11 '19 at 22:06
  • 1
    @DrPepperJo Without a [mcve] I could not point you out, I'm also assuming that the view uses a QStyledItemDelegate as a delegate, and in the case of QListView, QTableView and QTreeView use it. It is possible that in other cases such as the QComboBox simply use a QItemDelegate that has another style so when placing QStyledItemDelegate you are changing the default style of the QComboBox. – eyllanesc Apr 11 '19 at 22:10
  • 1
    @DrPepperJo Or it may be that your implementation has another error. Your current question is very focused: QTableWidget and that is the right thing to do because here we are looking for precise questions, so in the end I recommend you to ask a new question with an MCVE – eyllanesc Apr 11 '19 at 22:10