pythonwindowsqtpysideqpalette

How to change current color group for QPalette


I'm trying to change the current color group fora QPalette, but it seems that the setCurrentColorGroup method of QPalette simply does not work.

I'm running this code:

app = QtGui.QApplication(sys.argv)

button = QPushButton()
svgWidget = QSvgWidget(resources_paths.getPathToIconFile("_playableLabels/42-labelPlay-disabled-c.svg"))

button.setLayout(QHBoxLayout())
button.layout().addWidget(svgWidget)

button.setFixedSize(QSize(300, 300))

print button.palette().currentColorGroup()
button.setEnabled(False)
print button.palette().currentColorGroup()
button.palette().setCurrentColorGroup(QPalette.ColorGroup.Normal)
print button.palette().currentColorGroup()
button.show()
print button.palette().currentColorGroup()

app.exec_()

This is the output I get:

PySide.QtGui.QPalette.ColorGroup.Normal
PySide.QtGui.QPalette.ColorGroup.Disabled
PySide.QtGui.QPalette.ColorGroup.Disabled
PySide.QtGui.QPalette.ColorGroup.Disabled

Process finished with exit code -1

So... It seems that setCurrentColorGroup does exactly nothing. Any ideas on how could I change the current color group?

Thanks in advance!

(BTW, I'm running PySide 1.2.4 with Qt 4.8 on a Windows 7 system)


Solution

  • It seems that you are trying to change the way icons are rendered, rather than the way widgets are painted, so the palette is not the right API to use. Instead, you should use a QIcon, which allows different images to be used for various modes and states.

    To use the same image for both Normal and Disabled modes, you would use code like this:

    icon = QtGui.QIcon()
    icon.addPixmap(QtGui.QPixmap('image.svg'), QtGui.QIcon.Normal)
    icon.addPixmap(QtGui.QPixmap('image.svg'), QtGui.QIcon.Disabled)
    button = QtGui.QPushButton()
    button.setIcon(icon)
    

    However, you should take careful note of this warning from the Qt docs:

    Custom icon engines are free to ignore additionally added pixmaps.

    So there is no guarantee that this will work with all widget styles on all platforms.

    UPDATE:

    If the above method doesn't work, it probably means the widget style is controlling how disabled icons are rendered. The relevant QStyle API is generatedIconPixmap, which returns a copy of the pixmap modified according to the icon mode and style options. It seems that this method may sometimes also take the palette into account (somewhat contrary to what I stated above) - but when I tested this, it did not have any affect. I reset the palette like this:

    palette = self.button.palette()
    palette.setCurrentColorGroup(QtGui.QPalette.Normal)
    palette.setColorGroup(QtGui.QPalette.Disabled,
        palette.windowText(), palette.button(),
        palette.light(), palette.dark(), palette.mid(),
        palette.text(), palette.brightText(),
        palette.base(), palette.window(),
        )
    button.setPalette(palette)
    

    which made the colours look normal when the button was disabled - but the icon was still greyed out. Still, you might want to try it in case things work differently on your platform (don't be surprised if they don't).

    It seems that the correct way to control the disabling of icons is to create a QProxyStyle and override the generatedIconPixmap method. Unfortunately, this class is not available in PyQt4, but I have tested it in PyQt5, and it works. So the only working solution I have at the moment is to upgrade to PyQt5, and use QProxyStyle. Here is a demo script that shows how to implement it:

    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class ProxyStyle(QtWidgets.QProxyStyle):
        def generatedIconPixmap(self, mode, pixmap, option):
            if mode == QtGui.QIcon.Disabled:
                mode = QtGui.QIcon.Normal
            return super(ProxyStyle, self).generatedIconPixmap(
                mode, pixmap, option)
    
    class Window(QtWidgets.QWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.button = QtWidgets.QPushButton(self)
            self.button.setIcon(QtGui.QIcon('image.svg'))
            self.button2 = QtWidgets.QPushButton('Test', self)
            self.button2.setCheckable(True)
            self.button2.clicked.connect(self.button.setDisabled)    
            layout = QtWidgets.QVBoxLayout(self)
            layout.addWidget(self.button)
            layout.addWidget(self.button2)
    
    if __name__ == '__main__':
    
        app = QtWidgets.QApplication(sys.argv)
        app.setStyle(ProxyStyle())
        window = Window()
        window.setGeometry(600, 100, 300, 200)
        window.show()
        sys.exit(app.exec_())