python - PyQt5 如何将不同的 QStyles 应用于不同的小部件?
问题描述
我正在尝试使用 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_())
解决方案
文档中报告了在小部件上设置 QStyle (而不是在整个应用程序上设置)的一个重要方面:QWidget.setStyle()
设置小部件的样式对现有或未来的子小部件没有影响。
所以,发生的事情是您只在 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 样式。
虽然上面的代码可以满足您的期望,但在所有子 QWidgets 上安装事件过滤器并不是一件好事,特别是如果您只需要更改样式(这通常应该只做一次,可能在程序开始时)。考虑到有关使用不同样式的警告,我强烈建议您完全按照建议执行此操作:仅用于演示目的。
推荐阅读
- c# - 间歇性地将文件上传到谷歌驱动器失败
- python - 如何为句子列表创建窗口/块?
- javascript - 在 react-select 的 input 元素前添加一个图标
- java - 读取或获取 Excel 工作表中的所有列标题
- react-native - 如何在 react-native 中创建 pdf
- regex - 字母数字和一些特殊字符的正则表达式
- android - 从资源 xml 获取清单值
- c# - 将用户控件控件转换为样式
- c++ - C++11 枚举类命名空间块
- asp.net - 如何将请求从服务器端(asp.net web api / mvc)发送到 xamarin 表单应用程序?