为了账号安全,请及时绑定邮箱和手机立即绑定

如何确保停靠的 Qt 窗口具有带有深色平台主题的可见控件?

如何确保停靠的 Qt 窗口具有带有深色平台主题的可见控件?

Helenr 2022-05-24 16:37:39
考虑以下 PyQt 程序,import sysfrom PyQt5 import QtCore, QtWidgetsclass 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)        self.setWindowTitle("Dock demo")def main():    app = QtWidgets.QApplication(sys.argv)    ex = dockdemo()    ex.show()    sys.exit(app.exec_())if __name__ == '__main__':    main()这可以正常工作并生成一个简单的停靠窗口:但是,这不符合我的 GTK2 黑暗平台主题。如果我通过设置强制Qt这样做QT_QPA_PLATFORMTHEME=gtk2,我会得到这个:停靠窗口的控件几乎与背景颜色相同,因此很难看到。C++ 中的 GNU Octave 在平台主题中正确显示了它自己的停靠小部件控件:Octave 的停靠小部件在不使用系统主题时也会显示正确的控件。我怀疑这可能是由于它在这里设置的一些 CSS,但我不知道具体是什么:http ://hg.savannah.gnu.org/hgweb/octave/file/6d0585c8ee11/libgui/src/octave-dock -widget.cc#l123难道我做错了什么?感觉就像一个错误,Qt 没有正确设置停靠窗口控件的颜色,除非你做一些额外的事情(以及额外的可能是什么,我还不知道)。
查看完整描述

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

                }

                """

            )

这会在浅色和深色主题中产生正确的图标!

//img1.sycdn.imooc.com//628c99af0001f97705160242.jpg

现在完整的代码如下所示:


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


查看完整回答
反对 回复 2022-05-24
?
慕侠2389804

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,所以恐怕这是我能做的最好的。


查看完整回答
反对 回复 2022-05-24
  • 2 回答
  • 0 关注
  • 308 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号