【问题标题】:Using PyQt5/Pyside2 to set a repeating SVG pattern as main window/Qwidget background使用 PyQt5/Pyside2 将重复的 SVG 模式设置为主窗口/Qwidget 背景
【发布时间】:2018-12-24 15:45:41
【问题描述】:

我已经通过http://www.heropatterns.com/ 生成了 SVG css 代码,我正在尝试将它用作我的主窗口/Qwidget 的背景。我希望背景随着窗口变大或缩小而调整大小。我尝试调用 Form.setStyleSheet() 并将生成的 css 作为参数传入,但我只得到了模式中两种颜色中的一种(背景颜色)。将 SVG 显示为主 QWidget 窗口的背景并查看完整模式的正确方法是什么?我知道QSvgRenderer 存在,但是,我不确定一旦我创建了 QSvgRenderer 对象,我从那里开始使 SVG 成为可调整大小的背景。有人告诉我在样式表中使用background-repeat: repeat; 属性,但是这并没有改变任何东西。

这是我编写的最小、完整且可验证的示例:

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Form)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.horizontalLayout_2.addLayout(self.horizontalLayout)
        self.retranslateUi(Form)
        Form.setStyleSheet("""background-repeat: repeat; background-color: #000000;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'%3E%3Cg fill-rule='evenodd'%3E%3Cg id='hexagons' fill='%23b0b0b0' fill-opacity='0.4' fill-rule='nonzero'%3E%3Cpath d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");""")
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        Form.setWindowTitle(QtWidgets.QApplication.translate("Form", "Form", None, -1))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

表单当前的外观:

表单的外观:

SVG 模式的 XML 表示

<svg xmlns="http://www.w3.org/2000/svg" width="28" height="49" viewBox="0 0 28 49"><g fill-rule="evenodd"><g id="hexagons" fill="#000" fill-rule="nonzero"><path d="M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z"/></g></g></svg>

更改按钮背景的示例:

from PySide2 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Form)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.horizontalLayout_2.addLayout(self.horizontalLayout)

        self.Start_Stop_button = QtWidgets.QPushButton(Form)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.Start_Stop_button.sizePolicy().hasHeightForWidth())
        self.Start_Stop_button.setSizePolicy(sizePolicy)
        self.Start_Stop_button.setMinimumSize(QtCore.QSize(0, 0))
        self.Start_Stop_button.setBaseSize(QtCore.QSize(0, 0))
        self.Start_Stop_button.setIconSize(QtCore.QSize(16, 16))
        self.Start_Stop_button.setFlat(False)
        self.Start_Stop_button.setObjectName("Start_Stop_button")
        contents = b"<svg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'><g fill-rule='evenodd'><g id='hexagons' fill='#b0b0b0' fill-opacity='0.4' fill-rule='nonzero'><path d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/></g></g></svg>"
        file = QtCore.QTemporaryFile(Form)
        if file.open():
            file.write(contents)
            file.flush()
            Form.setStyleSheet("""background-color: #000000;
                                  background-image: url(%s);""" % file.fileName())

        #Form.show()
        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        Form.setWindowTitle(QtWidgets.QApplication.translate("Form", "Form", None, -1))
        self.Start_Stop_button.setText(QtWidgets.QApplication.translate("Form", "Start", None, -1))

class Widget(QtWidgets.QWidget, Ui_Form):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self.setupUi(self)

    def paintEvent(self, event):
        opt = QtWidgets.QStyleOption()
        opt.init(self)
        painter = QtGui.QPainter(self)
        self.style().drawPrimitive(QtWidgets.QStyle.PE_Widget, opt, painter, self)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

【问题讨论】:

    标签: python svg pyqt5 qtstylesheets pyside2


    【解决方案1】:

    QSS 不支持这种类型的 url,解决方法是将内容保存在一个临时文件中,当应用程序关闭时该文件会被删除,为此我们使用 QTemporaryFile。

    另一方面,url 具有以下格式:data:image/svg+xml,&lt;CONTENT&gt;,这是您应该使用的内容。

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class Ui_Form(object):
        def setupUi(self, Form):
            Form.setObjectName("Form")
            Form.resize(400, 300)
            self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Form)
            self.horizontalLayout_2.setObjectName("horizontalLayout_2")
            self.horizontalLayout = QtWidgets.QHBoxLayout()
            self.horizontalLayout.setObjectName("horizontalLayout")
            self.horizontalLayout_2.addLayout(self.horizontalLayout)
            self.retranslateUi(Form)
    
            contents = b"<svg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'><g fill-rule='evenodd'><g id='hexagons' fill='#b0b0b0' fill-opacity='0.4' fill-rule='nonzero'><path d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/></g></g></svg>"
            file = QtCore.QTemporaryFile(Form)
            if file.open():
                file.write(contents)
                file.flush()
                Form.setStyleSheet("""background-color: #000000;
                                      background-image: url(%s);""" % file.fileName())
            QtCore.QMetaObject.connectSlotsByName(Form)
    
        def retranslateUi(self, Form):
            Form.setWindowTitle(QtWidgets.QApplication.translate("Form", "Form", None, -1))
    
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        Form = QtWidgets.QWidget()
        ui = Ui_Form()
        ui.setupUi(Form)
        Form.show()
        sys.exit(app.exec_())
    


    似乎PySide2有点特别,看起来更像Qt,因为这个问题在C++中等待它而不是在Python中。对于支持QSS 的小部件,应该使用QStyle 实现paintEvent,但为此我们必须创建类小部件,因为类Ui_Form 不是小部件,它只是一个用于填充小部件的类。下面我展示了可行的代码。

    from PySide2 import QtCore, QtGui, QtWidgets
    
    class Ui_Form(object):
        def setupUi(self, Form):
            Form.setObjectName("Form")
            Form.resize(400, 300)
            self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Form)
            self.horizontalLayout_2.setObjectName("horizontalLayout_2")
            self.horizontalLayout = QtWidgets.QHBoxLayout()
            self.horizontalLayout.setObjectName("horizontalLayout")
            self.horizontalLayout_2.addLayout(self.horizontalLayout)
            self.retranslateUi(Form)
    
            contents = b"<svg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'><g fill-rule='evenodd'><g id='hexagons' fill='#b0b0b0' fill-opacity='0.4' fill-rule='nonzero'><path d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/></g></g></svg>"
            file = QtCore.QTemporaryFile(Form)
            if file.open():
                file.write(contents)
                file.flush()
                Form.setStyleSheet("""background-color: #000000;
                                      background-image: url(%s);""" % file.fileName())
    
            QtCore.QMetaObject.connectSlotsByName(Form)
    
        def retranslateUi(self, Form):
            Form.setWindowTitle(QtWidgets.QApplication.translate("Form", "Form", None, -1))
    
    
    class Widget(QtWidgets.QWidget, Ui_Form):
        def __init__(self, parent=None):
            super(Widget, self).__init__(parent)
            self.setupUi(self)
    
        def paintEvent(self, event):
            opt = QtWidgets.QStyleOption()
            opt.init(self)
            painter = QtGui.QPainter(self)
            self.style().drawPrimitive(QtWidgets.QStyle.PE_Widget, opt, painter, self)
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        w = Widget()
        w.show()
        sys.exit(app.exec_())
    

    加:

    QSS 具有应用以下链接中指示的样式的规则:

    在您的情况下,它仅适用于当前小部件,您必须使用 objectName:

    Form.setStyleSheet("""QWidget#Form{background-color: #000000;
                          background-image: url(%s);}""" % file.fileName())
    

    【讨论】:

    • 我使用了与您提供的完全相同的代码,但我仍然只获取背景,没有前景。我使用的是 Pyside2 而不是 PyQt5,但我看不出这会有什么不同,因为它以前从未有过。我已经用 SVG 的原始 XML 表示形式更新了原始帖子。是否有一种方法可以使用可能与 Pyside2 一起使用的原始提供的 XML 来显示 SVG 并且不是一种解决方法?
    • @Mrcitrusboots 好吧,我得到了你指出的同样的东西,所以你应该以一种智能的方式使用标签,不要假设在 PyQt5 中工作的所有东西都在 PySide2 中工作,请使用正确的标记。
    • 你介意打破这条线:self.style().drawPrimitive(QtWidgets.QStyle.PE_Widget, opt, painter, self) 吗?
    • @Mrcitrusboots 为什么?
    • 我不确定为什么需要每个参数,我认为最好了解您自己的程序中使用的逻辑。
    猜你喜欢
    • 2018-04-23
    • 2021-05-12
    • 1970-01-01
    • 2014-04-07
    • 2021-11-29
    • 2014-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多