Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How can I correctly apply a change of the global color scheme (light/dark)?

How can I correctly apply a change of the global color scheme (light/dark)?

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 5 Posters 1.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    l3u_
    wrote on 1 Dec 2024, 11:23 last edited by l3u_ 12 Jan 2024, 11:24
    #1

    Hi all,

    I have an application that chooses some colors and icons according to the used color scheme (light/dark). I check the base and windowText colors to detect the used scheme.

    Now I wanted to be able to update the colors dynamically, run-time, without having to restart the application when a scheme change is done. I subclassed QApplication to catch the change, like this:

    bool Application::event(QEvent *event)
    {
        if (event->type() == QEvent::ApplicationPaletteChange) {
            updateColorMode();
            Q_EMIT paletteChanged();
        }
        return QApplication::event(event);
    }
    
    void Application::updateColorMode()
    {
        // Detect if we use a dark theme
        const QPalette palette;
        const bool isDarkMode = palette.base().color().lightness()
                                < palette.windowText().color().lightness();
        setProperty("DARK_MODE", isDarkMode);
    }
    

    Changing the color scheme is correctly processed. I thought I now only would have to connect to my paletteChanged signal and update the colors/icons/etc. accordingly.

    However, I noticed that the color change is not propagated correctly all over my application. Using KDE Plasma and Qt 6.7.3 or Qt 5.15.14, my main window looks like this when started in light mode:

    Bildschirmfoto_20241201_120253.png

    After switching to dark mode, the new colors are only partially applied, i.e. the QDockWidgets are not updated:

    Bildschirmfoto_20241201_120320.png

    I also tried to setAttribute(Qt::WA_WindowPropagation); in my main window class, but the result is the same.

    Interestingly, when I switch back to light mode, the dock widgets get the dark colors, but still, the colors are not correct:

    Bildschirmfoto_20241201_120338.png

    What do I have to do so that the colors are applied correctly? When I close and restart the application, all colors are set correctly, according to the global style.

    Thanks for all help!

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SamiV123
      wrote on 1 Dec 2024, 11:52 last edited by SamiV123 12 Jan 2024, 11:57
      #2

      Good question, I've also pondered the same.

      Figuring out all the styling related stuff is complicated. We have:

      • Qt style engine
      • QSS styling
      • QPalette

      I've never really gathered how it all works together, I understand that the QStyle is basically the implementation to paint the widgets and so on. Not sure how the Palette and QSS mix together however. Rocket science where there should not be any rocket science.

      Anyway Personally I've tried to something like this

      https://github.com/ensisoft/detonator/blob/dev/editor/app/utility.cpp#L291

      It mostly works.

      1 Reply Last reply
      0
      • L Offline
        L Offline
        l3u_
        wrote on 1 Dec 2024, 12:20 last edited by
        #3

        The KDE apps seem to apply the color scheme change quite correctly … maybe there's some hint in KXmlGuiWindow or such …

        1 Reply Last reply
        0
        • A Offline
          A Offline
          artwaw
          wrote on 1 Dec 2024, 16:03 last edited by
          #4

          I use this property to detect and follow OS change to light/dark. https://doc.qt.io/qt-6/qstylehints.html#colorScheme-prop

          Please note restrictions listed.

          For more information please re-read.

          Kind Regards,
          Artur

          1 Reply Last reply
          0
          • L Offline
            L Offline
            l3u_
            wrote on 1 Dec 2024, 18:04 last edited by
            #5

            Detecting the change is not the problem – the problem is that the new scheme is not applied everywhere.

            Seems like setting a custom style sheet prevents the respective widget from updating itself automatically (e.g. for my above example, I set a style sheet for the dock widgets to make their titles a bit larger).

            I haven't figured out yet what I have to do to trigger the style update …

            1 Reply Last reply
            0
            • S Offline
              S Offline
              SGaist
              Lifetime Qt Champion
              wrote on 1 Dec 2024, 20:20 last edited by
              #6

              Hi,

              Style sheets have their own style and you are responsible for handling this use case by hand by updating your style sheet.

              Depending on what you are doing with your stylesheet, you might want to implement a proxy style that does the changes you want on top of what the underlying does.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              0
              • L Offline
                L Offline
                l3u_
                wrote on 1 Dec 2024, 21:12 last edited by
                #7

                Thanks for this hint!

                Sticking to the above example, I e.g. set

                dock->setStyleSheet(QStringLiteral("QDockWidget { font-weight: bold; font-size: %1pt; }").arg(
                                                   (int) double(dock->font().pointSize()) * 1.2));
                

                to all dock widgets to make their titles larger. I didn't find any approach to achieve this using something else (QFont etc.), and the style sheets approach worked.

                Would one be able to do that using such a proxy style you speak of? Or could I somehow manually set the new application-wide palette and then re-apply my style sheet? If I restart the program, the look is as expected, so applying the style sheets for the dark scheme does work as well as it does for the light one.

                1 Reply Last reply
                0
                • I Offline
                  I Offline
                  IgKh
                  wrote on 1 Dec 2024, 21:22 last edited by
                  #8

                  @l3u_ I grappled with this problem for a while, but eventually reached a satisfying state across Windows, macOS, KDE and Gnome. Though - I didn't use style sheets.

                  There are two points to this, that might be problems in your implementation.

                  The first is that the default handling of the ApplicationPaletteChange event in the application object is to propagate it to all top-level windows of the application, where each window actually resolves and updates its' palette, and then further propagates it to all of the widgets on it as PaletteChange events.

                  The implication of this is that ideally you'd want to do any additional touch-ups after all of that has happened. However in your application class you determine the current scheme and emit paletteChanged before the default QApplication handling happens, so whatever is happening in connected slots is likely too soon.

                  The second point is that for some platform integrations, changing the system-wide dark mode is not only a palette change, it could actually also be a style change. One of such platforms is exactly KDE Plasma - the light and dark variants of the Breeze theme are actually different QStyle implementations, and if you use the same Qt installation as the one KDE itself runs against you are actually using Plasma's platform theme plugin and styles even if you are a pure Qt app (hard to notice that sometimes, "Breeze" and "Fusion" are quite similar visually). This means that you should also be sensitive to the ThemeChange event. There is also a ApplicationPaletteChange event around typically, but the order doesn't seem to be deterministic in my experience so I just applied custom theming on both.

                  The later point might be the problem spot with style sheets, as each stylesheet actually creates a proxy style behind the scenes for you. I'd probably try to re-apply stylesheets after one of the above events happened, but I'm not sure about it.

                  1 Reply Last reply
                  0
                  • L Offline
                    L Offline
                    l3u_
                    wrote on 1 Dec 2024, 21:30 last edited by
                    #9

                    Thanks for the explanation! Actually, I don't do anything with that paletteChanged signal, I just put it there because I thought I would use it to update e.g. icons on buttons and such. But I didn't come so far because I noticed that most of my program wasn't changed after the color scheme change.

                    So if setting a style sheet creates a proxy style … would simply applying it again update it, using the current (new) style?!

                    I 1 Reply Last reply 1 Dec 2024, 21:41
                    0
                    • L l3u_
                      1 Dec 2024, 21:30

                      Thanks for the explanation! Actually, I don't do anything with that paletteChanged signal, I just put it there because I thought I would use it to update e.g. icons on buttons and such. But I didn't come so far because I noticed that most of my program wasn't changed after the color scheme change.

                      So if setting a style sheet creates a proxy style … would simply applying it again update it, using the current (new) style?!

                      I Offline
                      I Offline
                      IgKh
                      wrote on 1 Dec 2024, 21:41 last edited by
                      #10

                      @l3u_ said in How can I correctly apply a change of the global color scheme (light/dark)?:

                      So if setting a style sheet creates a proxy style … would simply applying it again update it, using the current (new) style?!

                      It should, yes, but as said I have no experience with it.

                      1 Reply Last reply
                      0
                      • L Offline
                        L Offline
                        l3u_
                        wrote on 1 Dec 2024, 21:44 last edited by
                        #11

                        Hey, simply adding a

                        setStyleSheet(styleSheet());
                        

                        in the QApplication subclass's if (event->type() == QEvent::ApplicationPaletteChange) { clause almost does the trick :-) Only the icons and colors set depending on the initial style remain. The rest is already updated with this. Apparently, this causes all the styled widgets to update themselves.

                        Let's see if I can get the rest to work also …

                        1 Reply Last reply
                        0

                        1/11

                        1 Dec 2024, 11:23

                        • Login

                        • Login or register to search.
                        1 out of 11
                        • First post
                          1/11
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved