为啥带有边框和背景图像样式的 QWidget 的行为与 QLabel、QDialog、...不同?

Posted

技术标签:

【中文标题】为啥带有边框和背景图像样式的 QWidget 的行为与 QLabel、QDialog、...不同?【英文标题】:Why is QWidget with border and background image styling behaving different to QLabel, QDialog, ...?为什么带有边框和背景图像样式的 QWidget 的行为与 QLabel、QDialog、...不同? 【发布时间】:2014-08-30 11:06:13 【问题描述】:

我使用 Qt4.8 Python 绑定 PySide(Windows 上 Python 3.3 上的版本 1.2.2),我看到 QWidget 的行为不同于 QWidgetderived 小部件,如 QDialogQLabelQMainWindow使用样式表进行样式设置时。

我特别观察到属性WA_StyledBackground 必须设置为显示边框或背景图像,而背景颜色是独立设置的。与其他小部件相比,此属性没有影响,始终显示边框或背景图像。也可以覆盖paintEvent 方法。

示例代码:

from PySide import QtGui, QtCore

class MyWidget(QtGui.QWidget):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def paintEvent(self, event):
        opt = QtGui.QStyleOption()
        opt.initFrom(self)
        painter = QtGui.QStylePainter(self)
        painter.drawPrimitive(QtGui.QStyle.PE_Widget, opt)

def display(w):
    print(w.__class__.__name__)
    w.setWindowTitle(w.__class__.__name__)
    print(' WA_StyledBackground is '.format(w.testAttribute(QtCore.Qt.WA_StyledBackground)))
    print(' autoFillBackground is '.format(w.autoFillBackground()))
    w.setStyleSheet('border: 4px inset #515c84; border-radius: 9px; background-color: blue; background-image: url(test.png);')
    w.resize(400, 400)
    w.show()

app = QtGui.QApplication([])

w1 = QtGui.QMainWindow(flags=QtCore.Qt.Window)
display(w1) # works

w2 = QtGui.QDialog(f=QtCore.Qt.Window)
display(w2) # works

w3 = QtGui.QWidget(f=QtCore.Qt.Window)
w3.setAttribute(QtCore.Qt.WA_StyledBackground)
display(w3) # works only with the previous line uncommented

w4 = QtGui.QLabel('Text', f=QtCore.Qt.Window)
display(w4) # works

w5 = MyWidget(f=QtCore.Qt.Window)
display(w5) # works

app.exec_()

该主题已在 *** 上进行了部分讨论。 Borders and background of QWidget aren't set by stylesheet 上接受的答案建议覆盖paintEvent,How to set QWidget background color? 接受的答案建议设置setAutoFillBackground,以防有人使用调色板,PySide: QWidget does not draw background color 建议只设置上述WA_StyledBackground。缺少的是QWidget 和派生小部件之间差异的原因。

我觉得这些差异有点令人困惑:

为什么QWidget 的行为与QLabel、...等派生小部件的行为不同? 为什么QWidget在自然状态下不显示边框或背景图片,却显示背景颜色? 以上述方式设置属性WA_StyledBackground 和覆盖paintEvent 有区别吗?首选哪种方法?

【问题讨论】:

【参考方案1】:

tl;dr - 使用QFrame

我不会试图猜测这个设计决策的原因,但一般来说QWidget 被认为是无边界的。如果您希望您的小部件具有漂亮的样式边框,那么您可能应该使用QFrame,它本质上只是具有您正在寻找的边框样式功能的QWidget

您会注意到很多小部件(例如您提到的QLabel)实际上继承自QFrame,而不是直接继承自QWidget

关于WA_StyledBackground 属性,我无法发表权威性发言。

【讨论】:

我真的不需要 QFrame,因为我不需要那里提供的特殊框架,工作样式表就足够了。我想我只是在寻找正确支持样式表的最小小部件。 QFrame 可能是一种可能性。 如果要使用样式表来设置边框的样式,需要使用QFrame 一旦我在 QFrame 上设置了包含边框指令的样式表,QFrame 的任何自定义边框都会被取消,并且 QWidget 在行为上没有区别。我认为 QFrame 是没用的,除非有人想要它的特殊边框。

以上是关于为啥带有边框和背景图像样式的 QWidget 的行为与 QLabel、QDialog、...不同?的主要内容,如果未能解决你的问题,请参考以下文章

QGraphicsItem 边框样式

UIBarButtonItem 带有图像和文本以及边框?

QWidget - 从 C++ 代码设置边框

带有像素图的透明 QLabel

如何在卡片中正确拟合带有模糊的背景图像?

背景与边框