+ PYSIDE STYLESHEET AND CUSTOM PAINTING
How to use stylesheets with custom drawing in PySide2
I am working on a custom widget to create a collapsable frame, like the one used in the Maya attribute editor. In this widget I have a label and an arrow to indicate the expanded/collapsed state of the widget. I wanted to learn how to implement a stylesheet to be able to set a few visual properties of the widget. Some of the properties comes for free like the background-color, border-radius, font-size and color etc. But I also wanted to be able to set the color of the arrow. The image below is an example of a simplified version of the widget.
In the article “Qt Style Sheets and Custom Painting Example” from the Qt docs if found a C++ example of how to do this. After some further googling and some trial and error I got it to work with PySide2.
Below is a simplified example of the widgets.
class DotLabel(QtWidgets.QFrame):
def __init__(self, name, height=20, parent=None):
super(DotLabel, self).__init__(parent)
self._dot_color = QtGui.QColor(0, 0, 0)
self._name = name
self._height = height
self.setFixedHeight(height)
def get_dot_color(self):
return self._dot_color
def set_dot_color(self, color):
self._dot_color = color
def paintEvent(self, e):
qp = QtGui.QPainter(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing)
rect = QtCore.QRect(self._height, 0, self.width(), self._height)
qp.drawText(rect, QtCore.Qt.AlignVCenter, self._name)
qp.setBrush(self.get_dot_color())
qp.setPen(QtCore.Qt.NoPen)
qp.drawEllipse(QtCore.QPoint(self._height*.5, self._height*.5), self._height*.20, self._height*.20)
qp.end()
dotColor = QtCore.Property(QtGui.QColor, get_dot_color, set_dot_color)
And in the “main” widget.
class TestWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(TestWidget, self).__init__(parent)
self.setGeometry(100,240,400,200)
vbox = QtWidgets.QVBoxLayout(self)
# add widgets
for i in range(3):
dot = DotLabel('Petfactory {}'.format(i), 20+i*20)
dot.setObjectName('dot_{}'.format(i))
vbox.addWidget(dot)
# apply stylesheet
s_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'stylesheet.qss')
with open(s_path, 'r') as f:
self.setStyleSheet(f.read())
Example from the style sheet:
DotLabel {
font-family: "Futura";
}
DotLabel#dot_0 {
border-radius: 2px;
border: 1px solid rgb(253, 151, 32);
color: rgb(253, 151, 32);
font-size: 12px;
qproperty-dotColor: rgb(253, 151, 32);
}
DotLabel#dot_1 {
border-radius: 4px;
color: rgb(166, 226, 46);
font-size: 24px;
qproperty-dotColor: rgb(166, 226, 46);
background-color: rgb(90,90,90);
}
DotLabel#dot_2 {
border-radius: 6px;
color: rgb(102, 217, 239);
font-size: 40px;
qproperty-dotColor: rgb(102, 217, 239);
background-color: rgb(90,90,90);
}
While in the research phase I came across a nice post by Dhruv Govil not exactly related, more on dynamic properties and stylesheets. There is also this article from the Qt docs
If you have some feedback or ideas on how to improve this workflow please let me know.