ApplicationPaletteChange event not sent to all widgets
-
I am working on adding dark-mode support to a Qt application, with the option to switch between dark and light mode at runtime using the following API
qApp->setPalette(isDark ? dark : light);I have observed that some widgets (eg
QLabel) still retain their old colors after this call. However, if I pass theclassNameparameter insetPalettecall as "QLabel", then it works as expected.Do I have to set the palette for every widget class explicitly to make this work?
As per the documentation, this doesn't seem necessary
If className is left 0, the change affects all widgets, thus overriding any previously set class specific palettes.
-
The widget that was preventing further propagation of
QEvent::PaletteChangeevents had a custom palette set. Removing that fixed the issue. @Chris-Kawa Thanks for pointing me in the right direction! -
Works for me. Could be a problem with your specific Qt version or platform plugin. Which ones you're on?
Also make sure you haven't locally overridden the palette for those specific widgets and that you're not using e.g. stylesheets with them. -
I am on Qt 5.15/macOS. It is also working for me in a hello world application, but not in my app.
Also make sure you haven't locally overridden the palette for those specific widgets
This is actually a problem in the codebase, but I believe I have already commented such overrides.
Also, if I explicitly add palette with className, I start getting the change notification but the resolved palette is still incorrect.
-
I am on Qt 5.15/macOS. It is also working for me in a hello world application, but not in my app.
Also make sure you haven't locally overridden the palette for those specific widgets
This is actually a problem in the codebase, but I believe I have already commented such overrides.
Also, if I explicitly add palette with className, I start getting the change notification but the resolved palette is still incorrect.
@schrute said:
It is also working for me in a hello world application, but not in my app
This would suggest that you're overriding it somewhere. An easy test would be to pick one of those problematic widgets and just before you set the palette reset that widget's palette to make sure it is not overridden i.e.
someWidget->setPalette(qApp->palette()); // make sure widget is using global palette qApp->setPalette(isDark ? dark : light); // change global paletteIf it works for that widget like that then you have confirmation that it gets overridden somewhere and you'll need to debug it to see where, for example install an event filter on one of those events and break when palette changes.
You can also step into the paint event of that label to see which style it's using. Maybe a stylesheet is applied somewhere and it switches to stylesheet style ignoring the palette.
-
I tried setting the palette of a problematic widget just before changing the global palette, but still facing the same issue.
Maybe a stylesheet is applied somewhere and it switches to stylesheet style ignoring the palette.
I called
stylesheet()inside the paint event of a problematic widget and it returned an empty string. Do I need to look for stylesheets in the parent widgets as well? -
I tried setting the palette of a problematic widget just before changing the global palette, but still facing the same issue.
Maybe a stylesheet is applied somewhere and it switches to stylesheet style ignoring the palette.
I called
stylesheet()inside the paint event of a problematic widget and it returned an empty string. Do I need to look for stylesheets in the parent widgets as well?@schrute Stylesheets are cascading, meaning they can be set anywhere up in the chain of parents or on the application object. It's easier to just set a breakpoint in the paint event handler and step into it to see if it goes into QStylesheetStyle class or the mac style plugin.
-
@Chris-Kawa As you suggested, I set a breakpoint in the label's
paintEventand stepped into Qt's source code. It doesn't seem to be using stylesheets, the following check insideQLabel::paintEventgets skippedif (QStyleSheetStyle* cssStyle = qt_styleSheet(style)) cssStyle->styleSheetPalette(this, &opt, &opt.palette);and eventually the label is drawn using
QFusionStyle::drawItemText. -
On debugging further it appears that
QEvent::ApplicationPaletteChangeis only sent to window widgets (if className is set tonullptr). It is the responsibility of the top-level widget to resolve the palette and sendQEvent::PaletteChangeto its child widgets. Somehow all the widgets in my app beyond a certain widget don't get this event. -
The widget that was preventing further propagation of
QEvent::PaletteChangeevents had a custom palette set. Removing that fixed the issue. @Chris-Kawa Thanks for pointing me in the right direction! -
S schrute has marked this topic as solved on