2 回答
TA贡献2019条经验 获得超9个赞
感谢这里的另一个答案,我有一个完整的解决方案来解决我原来的问题。
看起来 Qt 只是简单地硬编码这些图标而不考虑主题,但这很容易修复。
首先,我们使用相对亮度来决定颜色是否明亮,
def is_dark(qt_colour):
r, g, b = qt_colour.red(), qt_colour.green(), qt_colour.blue()
luminance = (0.2126*r + 0.7152*g + 0.0722*b)/256
return luminance < 0.5
在其源代码树中找到。我们将这些图标放在img/子目录/子文件夹中。
然后,我们获取小部件的背景颜色,
bg_colour = self.items.palette().color(QtGui.QPalette.Background)
根据该颜色,我们将 CSS 设置为使用浅色或深色图标集:
if is_dark(bg_colour):
self.items.setStyleSheet(
"""
QDockWidget
{
titlebar-close-icon: url(img/widget-close-light.svg);
titlebar-normal-icon: url(img/widget-undock-light.svg);
}
"""
)
else:
self.items.setStyleSheet(
"""
QDockWidget
{
titlebar-close-icon: url(img/widget-close.svg);
titlebar-normal-icon: url(img/widget-undock.svg);
}
"""
)
这会在浅色和深色主题中产生正确的图标!

现在完整的代码如下所示:
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
def is_dark(qt_colour):
r, g, b = qt_colour.red(), qt_colour.green(), qt_colour.blue()
luminance = (0.2126*r + 0.7152*g + 0.0722*b)/256
return luminance < 0.5
class dockdemo(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(dockdemo, self).__init__(parent)
self.items = QtWidgets.QDockWidget("Dockable", self)
self.listWidget = QtWidgets.QListWidget()
self.listWidget.addItem("item1")
self.listWidget.addItem("item2")
self.listWidget.addItem("item3")
self.items.setWidget(self.listWidget)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.items)
bg_colour = self.items.palette().color(QtGui.QPalette.Background)
if is_dark(bg_colour):
self.items.setStyleSheet(
"""
QDockWidget
{
titlebar-close-icon: url(img/widget-close-light.svg);
titlebar-normal-icon: url(img/widget-undock-light.svg);
}
"""
)
else:
self.items.setStyleSheet(
"""
QDockWidget
{
titlebar-close-icon: url(img/widget-close.svg);
titlebar-normal-icon: url(img/widget-undock.svg);
}
"""
)
self.setWindowTitle("Dock demo")
def main():
app = QtWidgets.QApplication(sys.argv)
ex = dockdemo()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
TA贡献1719条经验 获得超6个赞
不幸的是,Linux 默认的 Qt Fusion 样式停靠图标被硬编码为 XPM 格式的图像QFusionStyle(也是QCommonStyle其中的后备)。而且它们从不着色以匹配主题。许多“标准”图标都是这样,但许多是彩色/不透明的,因此背景并没有太大的区别。
要覆盖它们,您需要使用 CSS 或自定义QProxyStyle.
您可以从链接到的示例中看到它是如何在 CSS 中完成的。
QDockWidget
{
titlebar-close-icon: url(close.svg);
titlebar-normal-icon: url(restore.svg);
}
自定义 QStyle 涉及更多...
class AppStyle : public QProxyStyle
{
public:
using QProxyStyle::QProxyStyle;
QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override
{
switch (standardIcon) {
case SP_TitleBarNormalButton:
return QIcon("restore.svg");
case SP_TitleBarCloseButton:
case SP_DockWidgetCloseButton:
return QIcon("close.svg");
default:
return baseStyle()->standardIcon(standardIcon, option, widget);
}
}
QPixmap standardPixmap(StandardPixmap stdPixmap, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override
{
switch (stdPixmap) {
case SP_TitleBarNormalButton:
case SP_TitleBarCloseButton:
case SP_DockWidgetCloseButton:
return standardIcon(stdPixmap, option, widget).pixmap(option->rect.size());
default:
return baseStyle()->standardPixmap(stdPixmap, option, widget);
}
}
};
在这两种情况下,您都需要知道以某种方式使用的主题(例如,它是黑暗的)。您将为每个主题使用不同的(或动态的)CSS,或者您的自定义QProxyStyle将返回正确的基本颜色图标。例如,在 C++ 中,您甚至可以确定当前的调色板背景是否为暗(低颜色值),然后基于此返回不同的图标。
PS 是的,它可能被认为是一个“错误”或缺陷,Qt 没有为黑暗系统主题“自动”处理这个问题——无论桌面主题如何,尝试将应用程序皮肤设置为黑暗时也很烦人。但是c'est la vie。
PPS 哎呀,刚刚意识到我为 Python 问题提供了一个 C++ 示例......我不使用 Python 和 Qt,所以恐怕这是我能做的最好的。
添加回答
举报
