Reputation: 2251
I'm building a PyQt5 application, that I'd like to have a dark theme for. Previously I've worked with Android development where there was a dark theme that I could set for a whole application
Is there a dark theme built into Qt (that applies to all widgets in an application, and that is cross-platform)?
Upvotes: 48
Views: 103296
Reputation: 1003
In Qt 6.5 (PyQt6), there is a proper built-in way to get the system light/dark theme.
If all you want is for your widgets to respect the system settings, you can set your application style to 'fusion', and let Qt do the rest. Beware that this might make stuff look horrible if you have stylesheets or are using custom colors.
with QApplication(sys.argv) as qapp:
qapp.setApplicationName("My Awesome App")
qapp.setStyle('fusion')
w = MainUIWindow()
w.show()
sys.exit(qapp.exec())
If you want to catch the change from light to dark mode so you can update the stylesheet/custom color, you can connect to the QApplication.styleHints().colorSchemeChanged
signal, which will give you information about the new Qt.ColorScheme
(either Light
, Dark
or Unknown
).
For more information, and some other suggestions on how to have a bit more control over the process, have a look at this answer and the related article on dark mode for windows 11
Upvotes: 0
Reputation: 2493
pip3 install pyqtdarktheme
https://pyqtdarktheme.readthedocs.io/en/stable/how_to_use.html
https://pypi.org/project/pyqtdarktheme/
pyqtdarktheme
make life esaier.
qdarktheme.setup_theme("auto")
It can follow OS dark-mode dynamically.
Upvotes: 3
Reputation: 357
I suggest you qt-material package which has beautiful dark themes. It is easy to use, just install it as Python package and add these lines:
from qt_material import apply_stylesheet
...
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
# setup stylesheet
apply_stylesheet(app, theme='dark_teal.xml')
Documentation is here : https://pypi.org/project/qt-material/
Upvotes: 3
Reputation: 5003
There's no dark theme built into Qt. But you can quite easily create one yourself with the following code:
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QPalette, QColor
app = QApplication([])
# Force the style to be the same on all OSs:
app.setStyle("Fusion")
# Now use a palette to switch to dark colors:
palette = QPalette()
palette.setColor(QPalette.Window, QColor(53, 53, 53))
palette.setColor(QPalette.WindowText, Qt.white)
palette.setColor(QPalette.Base, QColor(25, 25, 25))
palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53))
palette.setColor(QPalette.ToolTipBase, Qt.black)
palette.setColor(QPalette.ToolTipText, Qt.white)
palette.setColor(QPalette.Text, Qt.white)
palette.setColor(QPalette.Button, QColor(53, 53, 53))
palette.setColor(QPalette.ButtonText, Qt.white)
palette.setColor(QPalette.BrightText, Qt.red)
palette.setColor(QPalette.Link, QColor(42, 130, 218))
palette.setColor(QPalette.Highlight, QColor(42, 130, 218))
palette.setColor(QPalette.HighlightedText, Qt.black)
app.setPalette(palette)
The nice thing about this is that it introduces no external dependencies. If you're interested what the above changes look like, I created an example PyQt5 app with a dark theme. Here is a screenshot:
Upvotes: 38
Reputation: 879
I was trying to apply this to my fbs based app and found the below easily allowed me to style the app by applying it to the AppContext
class AppContext(ApplicationContext):
def run(self):
self.main_window.show()
return self.app.exec_()
@cached_property
def main_window(self):
return MainWindow(self)
if theme_selection == 'Dark':
QApplication.setStyle("Fusion")
#
# # Now use a palette to switch to dark colors:
dark_palette = QPalette()
dark_palette.setColor(QPalette.Window, QColor(53, 53, 53))
dark_palette.setColor(QPalette.WindowText, Qt.white)
dark_palette.setColor(QPalette.Base, QColor(35, 35, 35))
dark_palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53))
dark_palette.setColor(QPalette.ToolTipBase, QColor(25, 25, 25))
dark_palette.setColor(QPalette.ToolTipText, Qt.white)
dark_palette.setColor(QPalette.Text, Qt.white)
dark_palette.setColor(QPalette.Button, QColor(53, 53, 53))
dark_palette.setColor(QPalette.ButtonText, Qt.white)
dark_palette.setColor(QPalette.BrightText, Qt.red)
dark_palette.setColor(QPalette.Link, QColor(42, 130, 218))
dark_palette.setColor(QPalette.Highlight, QColor(42, 130, 218))
dark_palette.setColor(QPalette.HighlightedText, QColor(35, 35, 35))
dark_palette.setColor(QPalette.Active, QPalette.Button, QColor(53, 53, 53))
dark_palette.setColor(QPalette.Disabled, QPalette.ButtonText, Qt.darkGray)
dark_palette.setColor(QPalette.Disabled, QPalette.WindowText, Qt.darkGray)
dark_palette.setColor(QPalette.Disabled, QPalette.Text, Qt.darkGray)
dark_palette.setColor(QPalette.Disabled, QPalette.Light, QColor(53, 53, 53))
QApplication.setPalette(dark_palette)
elif theme_selection == 'Light':
QApplication.setStyle("")
pass
else:
pass
You can use Qsettings to save a preference for which mode like this and restore on start.
if settings.contains("theme_selection"):
# there is the key in QSettings
print('Checking for theme preference in config')
theme_selection = settings.value('theme_selection')
print('Found theme_selection in config:' + theme_selection)
else:
if not is_mac():
print('theme_selection not found in config. Using default Darkmode')
settings.setValue('theme_selection', 'Dark')
theme_selection = settings.value('theme_selection')
elif is_mac():
print('theme_selection not found in config. Using default Lightmode')
settings.setValue('theme_selection', 'Light')
theme_selection = settings.value('theme_selection')
pass
Looks amazing could not comment on Michael Herrmann's post to say thanks but did upvote it.
Middle part is xterm.js so that is why its still white for now as its not a QT styled thing.
Upvotes: 9
Reputation: 14634
No, but you may use my fairly comprehensive stylesheets that should look excellent on most platforms (it's inspired by KDE's Breeze Theme, which is a dark theme that is quite elegant). This was (hard) forked from the excellent QDarkStylesheet, which I felt had theme issues in numerous areas, so I modified it extensively for my own needs and added a light theme.
A sample of the theme is here. To use it in PyQt5, simply add the following lines to a project:
import sys
from PyQt5.QtCore import QFile, QTextStream
from PyQt5.QtWidgets import QApplication
import breeze_resources
app = QApplication(sys.argv)
file = QFile(":/dark.qss")
file.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(file)
app.setStyleSheet(stream.readAll())
In response to a comment, the easiest way to adjust the stylesheet to use either the light or the dark stylesheet dynamically is to wrap it in a function. You may then use the function as a slot to a Qt signal (warning: I primarily develop using C++, so there may be small errors in my code for the signal/slot mechanism).
def toggle_stylesheet(path):
'''
Toggle the stylesheet to use the desired path in the Qt resource
system (prefixed by `:/`) or generically (a path to a file on
system).
:path: A full path to a resource or file on system
'''
# get the QApplication instance, or crash if not set
app = QApplication.instance()
if app is None:
raise RuntimeError("No Qt Application found.")
file = QFile(path)
file.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(file)
app.setStyleSheet(stream.readAll())
Now we can add generic application logic that can use this function in a signal/slot mechanism (using a lambda as a convenient wrapper, if needed, to provide the path to the stylesheet toggler):
# add logic for setting up application
app = QApplication(sys.argv)
# more logic for creating top-level widgets, application logic ...
parent = ...
light_btn = QPushButton("Toggle light.", parent)
light_btn.clicked.connect(lambda: toggle_stylesheet(":/light.qss"))
dark_btn = QPushButton("Toggle dark.", parent)
dark_btn.clicked.connect(lambda: toggle_stylesheet(":/dark.qss"))
# add to the layout, do other stuff
# ...
# end the Qt application
sys.exit(app.exec_())
This allows users to dynamically change the theme of an application developed with PyQt5 (or using analogous logic in C++, Qt5) to either a light or dark theme.
Disclaimer: Obviously I am the maintainer.
Upvotes: 76
Reputation: 9014
Founded in my bookmarks. I don't remember the original source.
QApplication::setStyle(QStyleFactory::create("Fusion"));
QPalette p;
p = qApp->palette();
p.setColor(QPalette::Window, QColor(53,53,53));
p.setColor(QPalette::Button, QColor(53,53,53));
p.setColor(QPalette::Highlight, QColor(142,45,197));
p.setColor(QPalette::ButtonText, QColor(255,255,255));
qApp->setPalette(p);
P.S. it may be adjusted with QSS if necessary.
Upvotes: 3