I've got a small example of the GUI I'm working on in Qt6, that has a problem switching palette colors (to switch from dark to light theme). When I apply my changes to QPalette to change the text color, they only work when the window is inactive. Weirdly, if I remove the font-family specification from the stylesheet then the color change works properly. This all works fine in Qt5 without any messing around.
- On load, the GUI looks fine
- After clicking the "Change Theme" button, it looks fine except that the text color setting that I change using Palette does not work (it's still black)
- If I click on my desktop or a different window to make my GUI inactive, it then shows the correct text color (red)
Light - Working, Dark - Broken, Dark - Working
Any workaround suggestions (that make color and font both always work correctly) are welcome, but I'd love to know what I'm actually doing wrong here, and why it used to work in Qt5 and doesn't in Qt6! Thanks!
from PyQt6 import QtWidgets
from PyQt6.QtGui import QPalette, QColor, QFont
APP = QtWidgets.QApplication([])
class UiMain(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setObjectName("MainWindow")
central_widget = QtWidgets.QWidget(self)
self.setCentralWidget(central_widget)
tabs = QtWidgets.QTabWidget(central_widget)
vertical_layout_26 = QtWidgets.QVBoxLayout(central_widget)
vertical_layout_26.addWidget(tabs)
search_tab = QtWidgets.QWidget()
tabs.addTab(search_tab, "")
tabs.setTabText(tabs.indexOf(search_tab), "Search")
filter_group_box = QtWidgets.QGroupBox(search_tab)
filter_group_box.setTitle("Filters")
self.theme_btn = QtWidgets.QPushButton()
self.theme_btn.setText("Change Theme")
searchbar_layout = QtWidgets.QHBoxLayout(search_tab)
searchbar_layout.addWidget(QtWidgets.QLabel("asdf"))
searchbar_layout.addWidget(filter_group_box)
searchbar_layout.addWidget(self.theme_btn)
class View(UiMain):
def __init__(self):
super().__init__()
self.theme_btn.clicked.connect(self.change_theme) # noqa
# Create Palettes
self.light_palette = QPalette()
self.dark_palette = QPalette()
self.dark_palette.setColor(QPalette.ColorRole.WindowText, QColor("red"))
# # This didn't help
# self.dark_palette.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.WindowText, QColor("red"))
# Create Stylesheets
self.style_light = """
* {font-family: 'Noto Sans';} /* REMOVING THIS LINE AVOIDS THE ISSUE, BUT THEN FONTS ARE WRONG INITIALLY */
QMainWindow {background-color: white;}
"""
self.style_dark = """
* {font-family: 'Noto Sans';}
QMainWindow {background-color: gray;}
"""
# Set initial theme
self.dark = False
APP.setPalette(self.light_palette)
APP.setStyleSheet(self.style_light)
self.show()
def change_theme(self):
"""Allow user to switch between dark and light theme"""
if self.dark:
self.dark = False
APP.setPalette(self.light_palette)
APP.setStyleSheet(self.style_light)
else:
self.dark = True
APP.setPalette(self.dark_palette)
APP.setStyleSheet(self.style_dark)
if __name__ == '__main__':
gui = View()
APP.exec()
I ran into this as well using PySide6 (occurs both on Windows and Linux).
In my case, the issue was that changing the palette using QApplication.setPalette after I had done anything with stylesheets resulted in the stylesheet not being properly applied to existing windows / objects or their children. Deleting the window and creating a new one worked as intended.
The issue (in my case) can be seen using something like the following. The application's palette would show my text color from my palette, but the window's palette shows the default black text color.
I do not know if this is a bug or not, but I was able to work around it without creating a new window instance by manually (and recursively) applying the palette to my existing window and its children using something like the following function
This should be called after changing the theme. It likely needs to be called on each open window (unless it is a child of another open window).
I would generally consider this sort of thing bad form, but it is the only thing I have found (so far) that works.