Использование PyQt5/Pyside2 для установки повторяющегося шаблона SVG в качестве основного окна / фона Qwidget
Я сгенерировал код SVG CSS через http://www.heropatterns.com/ и пытаюсь использовать его в качестве фона для моего главного окна /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_())
Как выглядит форма в настоящее время:
Как должна выглядеть форма:
XML представление шаблона SVG
<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_())
1 ответ
QSS не поддерживает этот тип URL, обходной путь - сохранить содержимое во временный файл, который удаляется при закрытии приложения, для этого мы используем QTeoraryFile.
С другой стороны URL имеет следующий формат: data:image/svg+xml,<CONTENT>
это контент, который вы должны использовать.
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
должно быть реализовано paintEvent
с помощью QStyle
но для этого мы должны создать виджет класса, так как класс 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())