Qt 小部件的深色主题?

Dark theme for Qt widgets?

背景

我正在构建一个 PyQt5 应用程序,我想要一个深色主题。之前我曾参与 Android 开发,其中有一个我可以为整个应用程序设置的深色主题

问题

Qt中是否内置了深色主题(适用于应用程序中的所有小部件,并且是跨平台的)?

没有,但你可以使用我相当全面的 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,我觉得它在很多方面都有主题问题,所以我根据自己的需要对其进行了大量修改,并添加了一个浅色主题。

简单使用

这里是主题样本。要在 PyQt5 中使用它,只需将以下行添加到项目中:

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())

动态样式表切换

针对评论,调整样式表以动态使用浅色或深色样式表的最简单方法是将其包装在一个函数中。然后您可以将该函数用作 Qt 信号的槽(警告:我主要使用 C++ 进行开发,因此我的代码中可能存在 signal/slot 机制的小错误)。

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())

现在我们可以添加可以在 signal/slot 机制中使用此函数的通用应用程序逻辑(如果需要,使用 lambda 作为方便的包装器以提供样式表切换器的路径):

# 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_())

这允许用户将使用 PyQt5(或使用 C++、Qt5 中的类似逻辑)开发的应用程序的主题动态更改为浅色或深色主题。

免责声明:显然我是维护者

在我的书签中创建。我不记得原始出处了。

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。如有必要,可以使用 QSS 进行调整。

Qt 中没有内置深色主题。但是您可以很容易地使用以下代码自己创建一个:

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)

这样做的好处是它不引入任何外部依赖项。如果您对上述更改感兴趣,我创建了一个示例 PyQt5 app with a dark theme。这是屏幕截图:

我试图将它应用到我的 fbs based app 并发现下面的内容很容易让我通过将它应用到 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

您可以使用 Qsettings 保存这种模式的首选项并在启动时恢复。

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

看起来很棒无法对 Michael Herrmann 的 post 发表评论表示感谢,但还是投了赞成票。

之前:

之后:

中间部分是 xterm.js 这就是为什么它现在仍然是白色的,因为它不是 QT 样式的东西。