【问题标题】:PyQt5 How to apply different QStyles to different widgets?PyQt5 如何将不同的 QStyles 应用于不同的小部件?
【发布时间】:2021-02-10 22:14:15
【问题描述】:

我正在尝试制作多个样式与 QStyleFactory 提供的内置样式不同的小部件,但是当我运行我的代码时,它们看起来都一样。我该如何解决这个问题?

from PyQt5 import QtWidgets, QtCore, QtGui
import sys

class Demo(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.container = QtWidgets.QWidget()
        self.setCentralWidget(self.container)
        self.layout = QtWidgets.QVBoxLayout()
        self.container.setLayout(self.layout)
        self.btn = QtWidgets.QPushButton("button")
        self.lw = QtWidgets.QListWidget()
        self.lw.addItems(["one", "two", "three"])
        self.layout.addWidget(self.btn)
        self.layout.addWidget(self.lw)
        self.resize(400, 150)
        self.show()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    widgets = []
    for style_name in QtWidgets.QStyleFactory.keys():
        demo = Demo()
        demo.setWindowTitle(style_name)
        style = QtWidgets.QStyleFactory.create(style_name)
        demo.setStyle(style)
        widgets.append(demo)

    sys.exit(app.exec_())

【问题讨论】:

    标签: python pyqt5 qtstylesheets qstyle


    【解决方案1】:

    QWidget.setStyle() 文档中报告了在 widgets 上设置 QStyle(而不是在整个应用程序上设置)的一个重要方面:

    设置小部件的样式对现有或未来的小部件没有影响。

    所以,发生的事情是您在 QMainWindow 上设置样式,而孩子们将始终使用 QApplication 样式。

    可以尝试做的是手动设置现有子项的样式:

        for style_name in QtWidgets.QStyleFactory.keys():
            demo = Demo()
            demo.setWindowTitle(style_name)
            style = QtWidgets.QStyleFactory.create(style_name)
            demo.setStyle(style)
            for child in demo.findChildren(QtWidgets.QWidget):
                child.setStyle(style)
            widgets.append(demo)
    

    无论如何,上述方法有一个缺点:设置样式后创建的任何新子级仍将继承 QApplication 样式。避免这种情况的唯一方法是通过(递归地)在父级上安装事件过滤器来监视childEvent(),并相应地设置样式;请注意,您还需要注意 StyleChange 事件。

    class ChildEventWatcher(QtCore.QObject):
        def __init__(self, parentWidget):
            super().__init__()
            self.parentWidget = parentWidget
            self.parentWidget.installEventFilter(self)
    
        def eventFilter(self, source, event):
            if event.type() == QtCore.QEvent.ChildAdded and isinstance(event.child(), QtWidgets.QWidget):
                event.child().installEventFilter(self)
                event.child().setStyle(self.parentWidget.style())
                for child in event.child().findChildren(QtWidgets.QWidget):
                    child.installEventFilter(self)
                    child.setStyle(self.parentWidget.style())
            elif event.type() == QtCore.QEvent.StyleChange and source == self.parentWidget:
                for child in self.parentWidget.findChildren(QtWidgets.QWidget):
                    child.setStyle(self.parentWidget.style())
            return super().eventFilter(source, event)
    
    
    class Demo(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            # this *must* be created before adding *any* child
            self.childEventWatcher = ChildEventWatcher(self)
    
            # ...
    

    还要记住文档警告的另一个重要方面:

    警告:此功能对于演示目的特别有用,您希望展示 Qt 的样式功能。真正的应用程序应该避免它,而是使用一种一致的 GUI 样式。

    虽然上面的代码可以满足您的期望,但在 all 子 QWidgets 上安装事件过滤器并不是一件好事,尤其是当您只需要更改样式时(即是通常应该只做一次的事情,可能在程序开始时)。考虑到有关使用不同样式的警告,我强烈建议您完全按照建议执行此操作:用于演示目的。

    【讨论】:

      【解决方案2】:

      您可以在应用程序上设置它。

      from PyQt5 import QtWidgets, QtCore, QtGui
      import sys
      
      
      class Demo(QtWidgets.QMainWindow):
          def __init__(self, parent=None):
              super().__init__(parent)
      
              self.container = QtWidgets.QWidget()
              self.setCentralWidget(self.container)
              self.layout = QtWidgets.QVBoxLayout()
              self.container.setLayout(self.layout)
              self.btn = QtWidgets.QPushButton("button")
              self.lw = QtWidgets.QListWidget()
              self.lw.addItems(["one", "two", "three"])
              self.layout.addWidget(self.btn)
              self.layout.addWidget(self.lw)
              self.resize(400, 150)
              self.show()
      
      if __name__ == '__main__':
          app = QtWidgets.QApplication(sys.argv)
          win = Demo()
          
          app.setStyle(QtWidgets.QStyleFactory.create("Windows")) # Set style theme on app
          sys.exit(app.exec_())
      

      【讨论】:

      • 这与 OP 想要的完全相反:在 不同 小部件上使用 不同 样式。
      猜你喜欢
      • 2012-08-15
      • 2020-12-08
      • 2020-09-17
      • 1970-01-01
      • 2021-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-02
      相关资源
      最近更新 更多