qtpyqtqicon

Use Qicon disabled mode for off state


I have a bunch of checkable QToolbuttons, and I'd like the icons to be 'greyed out' in the unchecked state. I can accomplish this by setting different files for the on/off states in the QIcon. like this:

    tb = QToolButton()
    tb.setCheckable(True)
    ico = QIcon()
    ico.addFile('color.jpg', QSize(16, 16), QIcon.Normal, QIcon.On)
    ico.addFile('grey.jpg', QSize(16, 16), QIcon.Normal, QIcon.Off)
    tb.setIcon(ico)

But since a QIcon can create a 'greyed out' version of itself that is used in disabled mode, I'd prefer to use the disabled mode icon over creating the grey version of all the icons myself. Is this possible?


Solution

  • You can get the grayed icon with QIcon.pixmap() and using the Disabled state, then set it again for the desired mode.

    Since you want it for the Off state (the default) you have to first set the pixmap for the On state, get the grayed out pixmap and then set it with the other state:

        original = QtGui.QPixmap('icon.png')
        icon = QtGui.QIcon()
        icon.addPixmap(original, QtGui.QIcon.Normal, QtGui.QIcon.On)
        grayed = icon.pixmap(original.size(), QtGui.QIcon.Disabled, QtGui.QIcon.On)
        icon.addPixmap(grayed, QtGui.QIcon.Normal, QtGui.QIcon.Off)
    

    Note that while the common behavior of Qt is to gray out images, it is not guaranteed that it will happen on all platforms and styles.

    Since we're talking about icons, we can assume that they are very small, so we can use a helper function to get a grayed out pixmap (while still respecting the alpha channel):

    def getGrayed(src):
        if isinstance(src, QtGui.QPixmap):
            src = src.toImage()
        dest = QtGui.QImage(src.size(), QtGui.QImage.Format_ARGB32)
        widthRange = range(src.width())
        for y in range(src.height()):
            for x in widthRange:
                pixel = src.pixelColor(x, y)
                alpha = pixel.alpha()
                if alpha < 255:
                    alpha //= 3
                gray = QtGui.qGray(src.pixel(x, y))
                pixel.setRgb(gray, gray, gray, alpha)
                dest.setPixelColor(x, y, pixel)
        return QtGui.QPixmap.fromImage(dest)
    

    Then, do something similar to the above:

        original = QtGui.QPixmap('iconalpha.png')
        icon = QtGui.QIcon(getGrayed(original))
        icon.addPixmap(original, QtGui.QIcon.Normal, QtGui.QIcon.On)
    

    Obviously, this can be very demanding if there are many source icons and their size is somehow "big" (256x256 or more).
    If you're worried about performance, the above getGrayed() function can be converted to a simple script that automatically creates grayed out icons.

    Note that if that feature is required a lot of times in your code, you might consider creating your own QIconEngine subclass and create a custom static function to get the preferred icon (with modes already set) based on your needs.