I need to change styles depending on the actions taking place in the program. An analogue of JS on an HTML page, where you can add, remove classes from CSS, only in PyQt.
I tried doing something like this:
if strength < 33:
self.reliability.setObjectName('rel-0')
elif strength < 66:
self.reliability.setObjectName('rel-1')
else:
self.reliability.setObjectName('rel-2')
Having previously written these selectors in the style file:
#rel-0, #rel-1, #rel-2 {
border: 2px solid #453e3e;
border-radius: 5px;
text-align: center;
background-color: #453e3e;
color: rgba(69, 62, 62, 0);
}
#rel-0::chunk {
background-color: #ed0909;
}
#rel-1::chunk {
background-color: #e3c010;
}
#rel-2::chunk {
background-color: #44d111;
}
But, apparently, when the ObjectName changes, the elements do not update the styles that are inherent in these identifiers. I also tried doing repaint()
and update()
. But apparently they don't "see" the change in styles either.
PS: Do I really have to do setStylesheet() every time?
Yes, you almost always need to recompute the style sheet.
Remember that, while conceptually similar to CSS in implementation and behavior, Qt style sheets do not work exactly like them and, most importantly, do not consider dynamic state changes applied programmatically, except for those strictly related to the pseudo states.
As long as the style sheet "change" is not related to the box model, it might be enough to "unpolish" and "polish" the widget style:
style = someWidget.style()
style.unpolish(someWidget)
style.polish(someWidget)
widget.update() # not required, but might be safer
Unfortunately, that isn't enough most of the times, so it could be necessary to force a stylesheet recomputation.
If the QSS is set to the widget, you can just recall setStyleSheet()
with the same content:
someWidget.setStyleSheet(someWidget.styleSheet())
If the widget has no stylesheet set, and it just inherits it from the parent(s), then do the above with the closest styled widget parent.
Note that this might be a bit problematic if you only use a generic application-wide stylesheet, since it would cause the style to compute anything for any widget. In that case, you could try a simple workaround: set a blank stylesheet and reset it again:
someWidget.setStyleSheet(' ')
someWidget.setStyleSheet('')
Note that, while not technically "wrong" per se, changing the object name isn't a good choice, and that's because the purpose of object names is to be able to dynamically find objects using findChild()
or findChildren()
.
The more appropriate way to do the above is by using Qt properties instead (with setProperty()
), as explained in the documentation.