0

I am trying to build a pyside6 application with a light mode and a dark mode. That means that my icons also need to be light and dark mode.

Now I was hoping to set the color of the QIcon SVGs inside my qss stylesheet with e.g.

#menu_button {
  color: white;
}

I had the hope that fill="currentColor" inside the svg would make it possible for the icon to inherit the color property from the QSS, but it seems that this is not the case.

Is there a good way to dynamically switch the color of svg icons? I would like to have a setting with "Light Mode" and "Dark Mode" or something like this that each loads a custom color set from their stylesheets.

4
  • Does this work with QT? I mean this seems to be a Mozilla documentation Commented May 19 at 8:44
  • Thanks, but it does not seem to work for QT itself. I mean QT is not a browser. Commented May 19 at 9:19
  • 1
    To anybody trying to answer this, even in comments: these are not standard style sheets, they are Qt style sheets, they are only based on the CSS specifications, they don't follow it completely. The OP is not having issues with a standard web browser engine, so please don't try to reply unless you know what Qt stylesheets are and how they actually work. Commented May 19 at 13:24
  • 1
    @max If you're asking if there's a way to do this through QSS, no, there isn't: the icon loader engine is not aware of any aspects set on the style sheet (and the icon is set from the style). The only possibility you have is to use different icon paths based on the current color scheme. Commented May 19 at 13:26

1 Answer 1

1

Simply put, this is not possible, at least not just by setting the color of the widget.

The reason resides on the fact that QIcon doesn't represent an image or a file: it actually is an abstraction layer that is queried by widgets when they need to display a pixmap at a desired size.

Every icon has its own icon engine, responsible of actually drawing the pixmap when required), and when loading icons from a file the related icon engine is used.

For instance, when loading an SVG file, QIcon internally creates an instance of a QIconEngine subclass that is able to read SVG files and render their contents when required.

When icons are drawn (for instance in a button), the Qt style normally calls the pixmap() function of the icon, which internally calls the pixmap(), which has the following argument signature:

QIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)

As you can see, there is absolutely no reference about the context in which the icon is drawn (such as the text color), so there is no way to change the icon rendering just by trying to change the palette, as that context is never passed on.

QIcon and QIconEngine have a paint() function, which passes a QPainter reference, so, in theory it would be possible to at least try to get the current pen/brush colors from the painter, but there is absolutely no guarantee that those would be set with the appropriate foreground color; also, that function is only called from some classes and under specific circumstances: even the internal QStyleSheetStyle still uses pixmap() for button icons.

Considering the above, what you ask is not directly possible: if you want to use different color schemes, you need to have different icon sets for each one of them.

There is a way to simplify the way those different icon sets are chosen, though, which is to use a little known feature of QDir, the setSearchPaths() function.

The procedure is the following:

  1. create the two icon sets, while keeping the same file names, and put them in two different directories (this also works for Qt resources);
  2. call setSearchPaths() with an appropriate prefix and the target folder for the current color scheme, for instance:
hints = QApplication.styleHints()
if hints.colorScheme() == Qt.ColorScheme.Dark:
    path = '<path-to-light-icons>'
else:
    path = '<path-to-dark-icons>'
QDir.setSearchPaths('icons', [path])
  1. then, whenever you need to set an icon, you can use the above prefix:
someButton.setIcon(QIcon('icons:someIcon.svg'))

Note that calling setSearchPaths() doesn't work dynamically: it won't automatically change the icon once called, which means that:

  • it should be called before any QIcon is created and used (usually at the program startup);
  • if you want to change color scheme at runtime, you need to find a way to automatize the icon reload; for instance, you could store the generic icon name, connect to the colorSchemeChanged signal and call setIcon() again with the same path, including the prefix used above;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.