首页 > 解决方案 > Qt 动态属性 - 如果不是父级,则适用于小部件?

问题描述

我正在尝试在普通 QWidget 上实现按钮行为,并尝试使用它setProperty()来动态更改样式表中的值。当我使用它的方法显示小部件时,它似乎工作得很好,show()但是一旦它是父级它就不再工作了,我不明白发生了什么?(不,我不想从 QPushButton 继承,小部件会有很大不同,谢谢。)

有一个例子:

from PySide2 import QtCore, QtGui, QtWidgets


class Example(QtWidgets.QWidget):
    
    STYLESHEET = \
    """
    QWidget[pressed=true] 
    {
        background-color: yellow;
    }
    
    QWidget[pressed=false] 
    {
        background-color: red;
    }
    """
    
    pressed = QtCore.Signal()
    
    def __init__(self, parent=None):
        super(Example, self).__init__(parent=parent)
        
        self._buildUi()

        self.setStyleSheet(self.STYLESHEET)

        self.setProperty('pressed', False)
        
    def _buildUi(self):
        self.layout = QtWidgets.QVBoxLayout(self)
        
        self.label = QtWidgets.QLabel('toto')
        self.layout.addWidget(self.label)

    def mousePressEvent(self, e):
        self.pressed.emit()
        self.setProperty('pressed', True)
        self.setStyle(self.style())
                
        super(Example, self).mousePressEvent(e)

    def mouseReleaseEvent(self, e):
        self.setProperty('pressed', False)
        self.setStyle(self.style())
        
        super(Example, self).mouseReleaseEvent(e)
        
        
class Window(QtWidgets.QWidget):
    
    def __init__(self):
        super(Window, self).__init__()
        
        self.mainLayout = QtWidgets.QVBoxLayout(self)
                
        self.test = Example(self)
        self.mainLayout.addWidget(self.test)


if __name__ == '__main__':
    # w = Example()  # Work
    w = Window()  # Don't Work
    w.show()

如果您在if __name__ == '__main__':条件中切换注释行,您将能够看到同一个小部件的两个结果。

我试过了:

PS:我在 Autodesk Maya 中运行此代码,因此 QApplication 实例已经存在,因为它是 Maya 本身。

你们知道发生了什么吗?

标签: pythonqtmayapyside2

解决方案


独立小部件之所以有效,是因为 Qt仅对顶层窗口使用基本样式表属性(背景和边框) ,假设顶层窗口与样式表中指定的类相同。

当 QWidget 有父对象时,它不会自行绘制任何内容。
正如文档所解释的:

如果您从 QWidget 子类化,则需要为您的自定义 QWidget 提供一个paintEvent

因此,在 PyQt/PySide 术语中:

class Example(QtWidgets.QWidget):
    # ...
    def paintEvent(self, event):
        opt = QtWidgets.QStyleOption()
        opt.initFrom(self)
        qp = QtGui.QPainter(self)
        self.style().drawPrimitive(
            QtWidgets.QStyle.PE_Widget, opt, qp, self)

推荐阅读