[PYSIDE] Alternative to StyleSheets?

Hey,
So I’ve searched a bit of the internets to find an alternative to StyleSheets but have come back pretty empty handed. Was hoping you gents may lend a hand.

In my code I’ve setup some default styles for my Button Class:

style = (
    "QToolButton{background-color: rgb(68,68,68); color: white;"
    "border:1px solid black;border-radius:2px;} "
    "QToolButton:hover{background-color: rgb(54, 255, 0); "
    "color: black; solid black 1px:}")

However, later in my code I need to change some elements without affecting the others. For instance change the font color or background color. I know there’s ways with modifying the button’s palette but not getting the syntax right.
Is there a cleaner way of setting up the same effect with a widget than using the stylesheet above?

There is a mechanism for styling Classes of Widgets, or Widgets with a specific name. Check out the “Selector Types” Section on this page:

http://doc.qt.io/qt-4.8/stylesheet-syntax.html

Thanks for the tip.

I think I got what I was really after. I ended up overriding my leave and enter events for my button class.

def leaveEvent(self, event):
    palette = QtGui.QPalette(self.palette())
    palette.setColor(QtGui.QPalette.Background, QtGui.QColor(68, 68, 68))
    palette.setColor(QtGui.QPalette.ButtonText, QtGui.QColor(self.textColor))
    self.setPalette(palette)

def enterEvent(self, event):
    palette = QtGui.QPalette(self.palette())
    palette.setColor(QtGui.QPalette.Background, QtGui.QColor(54, 255, 0))
    palette.setColor(QtGui.QPalette.ButtonText, QtGui.QColor("black"))
    self.setPalette(palette)

It seems like a minor thing, but you could probably make it slightly more responsive by creating all the palettes you’ll need (palette of palettes?) in a class init and then just picking between them in the callback.

[QUOTE=btribble;28799]It seems like a minor thing, but you could probably make it slightly more responsive by creating all the palettes you’ll need (palette of palettes?) in a class init and then just picking between them in the callback.[/QUOTE]

Thanks, I’ll give it a go.

[QUOTE=snolan;28802]Thanks, I’ll give it a go.[/QUOTE]

Also, it will help prevent memory thrashing a bit. I’ve had a few difficult to reproduce cases where QT was apparently out of widget handles (or something similar).

I’ve been using setProperty for these kind of styling things, acts like css class selectors.

.py


self.label = Label('Request')
self.label.setProperty('class', 'Request')

.qss


Label[class="Request"]
{
    background-color: rgba(60,140,60,255);
    border-bottom: 1px solid rgba(40,130,40,255);
    border-top: 1px solid rgba(40,130,40,255);
}

Awesome! Thanks for the example!

[QUOTE=svenneve;28818]I’ve been using setProperty for these kind of styling things, acts like css class selectors.

.py


self.label = Label('Request')
self.label.setProperty('class', 'Request')

.qss


Label[class="Request"]
{
    background-color: rgba(60,140,60,255);
    border-bottom: 1px solid rgba(40,130,40,255);
    border-top: 1px solid rgba(40,130,40,255);
}

[/QUOTE]

[QUOTE=svenneve;28818]I’ve been using setProperty for these kind of styling things, acts like css class selectors.

.py


self.label = Label('Request')
self.label.setProperty('class', 'Request')

.qss


Label[class="Request"]
{
    background-color: rgba(60,140,60,255);
    border-bottom: 1px solid rgba(40,130,40,255);
    border-top: 1px solid rgba(40,130,40,255);
}

[/QUOTE]

Does this work as expected? i thought the docs said you have to then update the widget to pick up the property change?

Works in my app so far, i assign the properties during creation, and the qss file is loaded before the main window is shown.

Can you change the property during runtime and have the styles update automatically?

[QUOTE=svenneve;28818]I’ve been using setProperty for these kind of styling things, acts like css class selectors.

.py


self.label = Label('Request')
self.label.setProperty('class', 'Request')

.qss


Label[class="Request"]
{
    background-color: rgba(60,140,60,255);
    border-bottom: 1px solid rgba(40,130,40,255);
    border-top: 1px solid rgba(40,130,40,255);
}

[/QUOTE]

If you’re going to use properties in this fashion you may as well just use setObjectName(‘Request’) instead of a custom property. These will be accesible in the stylesheet via # symbol.


label#Request{
    ...
}

Properties are best used with changing states. For example…


# Initialize some process
my_widget.setProperty('processing', True)
my_widget.style().unpolish(my_widget)
my_widget.style().polish(my_widget)
my_widget.update()

# After process finishes
my_widget.setProperty('processing', True)
my_widget.style().unpolish(my_widget)
my_widget.style().polish(my_widget)
my_widget.update()

The unpolish > polish > update needs to be run each time you change the processing property to ensure it gets the appropriate attributes from your stylesheet. Here is what the stylesheet could look like.


[processing='true']{
    color: red;
}
[processing='false']{
    color: green;
}

It’d be best to remove the polishing boiler plate via a custom description. Here is a full example:


from PySide import QtGui
import sys
import signal

STYLE = '''
QLabel{
    font: 48pt;
}
[processing='true']{
    color: red;
}
[processing='false']{
    color: green;
}
'''


class StyledProperty(object):

    def __init__(self, name):
        self.name = name

    def __get__(self, inst, typ):
        if inst:
            return inst.property(self.name)
        return

    def __set__(self, inst, value):
        inst.setProperty(self.name, value)
        inst.style().unpolish(inst)
        inst.style().polish(inst)
        inst.update()


class MyLabel(QtGui.QLabel):
    processing = StyledProperty('processing')

    def __init__(self, *args, **kwargs):
        super(MyLabel, self).__init__(*args, **kwargs)
        self.processing = False

    def mousePressEvent(self, event):
        self.processing = not self.processing


if __name__ == '__main__':
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    app = QtGui.QApplication(sys.argv)
    app.setStyleSheet(STYLE)
    label = MyLabel('Hello')
    label.show()
    sys.exit(app.exec_())


as far as I know there is a way with set properties to actual inherit some live recall function in PySide.

Our senior TD was explaining this to me, You can set a property to your layout items and just use your resource file as a starting and when your even occurs the inheritance will allow you to change that feature on a live basis instead of the css way.

It’s kind of hard for me to explain and I will try to get him to show me some code and explain more.

Also keep in mind that stylesheets are not exactly fast. This is not a problem in most cases when you are having both limited amounts of widgets and few changes. We have a case with a lot of dynamically created buttons. Profiling shows that setStylesheet is quite a bottleneck in such a case. I went to using palettes (tho i typically leave it with the defaults for hovering etc.) With Plastique i find the hovering works well for me and you can set the color via highlight colors.

Cheers,
Thorsten