2

My application written with Qt 5.13 uses a QToolBar. To place icons on it, I have this line in my source:

const QIcon openIcon = QIcon::fromTheme("document-open", QIcon(":/images/open.png"));

This works well and the application appearance changes when dark mode is activated. The icons are processed automatically to look inverted, but that doesn't work well, they look terribly.

Is there a way to provide icons that Qt would use for dark mode? Alternatively, is there a way to stop Qt from inverting my icons as they would work really good in dark mode as well?

z80crew
  • 1,150
  • 1
  • 11
  • 20

2 Answers2

1

One way to resolve the issue described is to introduce a listener for dark mode change, and then change the icon accordingly in your QToolBar. As I see from QToolBar documentation, the straightforward way to do so would be call QToolBar::clear(), and then add all your actions together again.

Now the part about detecting dark mode changes. This part might be a bit tricky, but it is doable. Basically, you should introduce native code in Objective C++ (so, you would be able to use namespaces, headers, and so on, i.e. stuff from C++), and then add Objective C code that adds listener for dark mode changes. The name of the parameter you might want to add listener to is "AppleInterfaceThemeChangedNotification".

Finally, more direct thoughts to your problem which are not guaranteed to work (approach with detecting dark mode changes would definitely work, I think), but might be worth to try:

  1. Have you tried adding the pixmap of your PNG icon to QIcon in all states? You can see it here: https://doc.qt.io/qt-5/qicon.html#addPixmap
  2. Not sure if this would work, but maybe setting flag of being a mask would do something? https://doc.qt.io/qt-5/qicon.html#setIsMask
  3. Have you tried adding widgets to QToolBar instead of actions: https://doc.qt.io/qt-5/qtoolbar.html#addWidget? Maybe adding custom widget would not make your icons looks horrible despite the mode they are showing? of course, keep in mind that in this specific case you might have to create your own widgets.
1

Bundle two sets of icons, and switch between them when the palette changes.

void MainWindow::changeEvent(QEvent *event)
{
#ifdef Q_OS_MACOS
    // These aren't "examples". They're literally the actual values.
    constexpr int OSX_LIGHT_MODE = 236;
    constexpr int OSX_DARK_MODE = 50;

    QStringLiteral LIGHT_THEME{"breeze"};
    QStringLiteral DARK_THEME{"breeze-dark"};

    if (event->type() == QEvent::PaletteChange) {
        auto bg = palette().color(QPalette::Active, QPalette::Window);
        // Calling setThemeName changes every visible icon, instantly.
        if (bg.lightness() == OSX_LIGHT_MODE) {
            QIcon::setThemeName(LIGHT_THEME);
        } else {
            QIcon::setThemeName(DARK_THEME);
        }
    }
#else
    Q_UNUSED(event)
#endif
}

As for how to bundle the icons: I'm not going to get into that, but there's a good guide here:

A Guide to Using Icon Themes in Qt on All Platforms

user240515
  • 3,056
  • 1
  • 27
  • 34