Setting QObject properties through Qt CSS not fully working



  • Hello, all.

    I have the following sample code:

    #include <QApplication>
    #include <QLabel>
    #include <QTimer>
    
    int main( int argc, char* argv[] )
    {
        QApplication a( argc, argv );
        QLabel label;
        label.setStyleSheet(
                    "QLabel {\n"
                    "    border: 2px solid green;\n"
                    "    qproperty-pixmap: url(:/Green.png);\n"
                    "}\n"
                    "\n"
                    "QLabel:disabled {\n"
                    "    border: 2px solid gray;\n"
                    "    qproperty-pixmap: url(:/Gray.png);\n"
                    "}" );
    
        QTimer t;
        QTimer::connect( & t,
                         & QTimer::timeout,
                         [ & label ]()
                         {
                             label.setEnabled( ! label.isEnabled() );
                         } );
        label.show();
        t.start( 1500 );
    
        return a.exec();
    }
    

    The stylesheet is successfully applied for both the border standard CSS property and the QLabel's custom "pixmap" property one and for both states. In my actual application setting the value of a custom property through CSS using the "qproperty-" syntax works but what fails is to give the custom property at hand a different value for another state of the QObject-based instance at hand. Tested whether there is a difference between setting the CSS directly to the QObject-based instance at hand or to the QApplication's stylesheet and found there's none. Removed the whole CSS of my application and left only that of the given QObject-based instance at hand and again the QObject's instance property was set only with the value provided for its default state but not for its disabled state for example. The QObject-based instance is again QLabel and again I want to set its "pixmap" property.

    Can't provide a more concrete and deep example, but just want to know whether anyone has stumbled upon such problem in his/her real-life application and if so did he/she found any solution. Can't see why setting a QObject's custom property through CSS for more than one state of the QObject-based instance could fail in one and succeed in another application.


  • Moderators

    @napajejenunedk0 said in Setting QObject properties through Qt CSS not fully working:

    QLabel:disabled {\n"
    " border: 2px solid gray;\n"
    " qproperty-pixmap: url(:/Gray.png);\n"
    "}"

    properties are not reapplied on pseudo state changes. See QTBUG-2982, as you can see it is very old, and i wouldn't expect it to be fixed any time soon.

    What happens when you do this:

    QTimer::connect( & t,
                         & QTimer::timeout,
                         [ & label ]()
                         {
                             label.setEnabled( ! label.isEnabled() );
                             label.style()->polish(&label);
                         } );
    


  • What happens when you do this: ...

    Nothing. What I know is that repolishing of a QWidget-based class instance is needed only in case its stylesheet depends on values of dynamic object properties, not in case of using CSS or Qt CSS-specific integrated pseudo states. Already tried repolishing the QLabel but nothing helped.

    properties are not reapplied on pseudo state changes. See QTBUG-2982, as you can see it is very old, and i wouldn't expect it to be fixed any time soon.

    Using Qt 5.5.1 MSVC 12 (VS 2013) 32-bit and looking both at the test project, where it works, and another real-world one, where it doesn't it is actually partially reproducible. As mentioned in my original post, it is strange that removing the whole stylesheet of the actual application (not the test one) and leaving only that of the QLabel at hand doesn't make any difference. I was thinking of removing all object names if they are in some way staying in the way of the correct application of the stylesheet. Another reason could be the actual project's UI complexity.



  • @raven-worx, replaced the QLabel with QPushButton, since I want to control its icon as well through CSS (as it is the case in the Qt bug you've cited above) and saw that trying to set different icon (qproperty-icon) according to its :checked pseudo state results in applying only one of the provided icons. Unpolishing and polishing the QPushButton while using the pseudo state has no effect. Moving to dynamic properties or more properly said to the dynamic property equivalent of the given pseudo state - :checked to [checked="true"] plus repolishing the button upon a change in its checked state resulted in the desired behavior. For sure this semi-automaticity is not the best programming practice. Setting the topic to solved despite the usage of a workaround.


  • Moderators

    @napajejenunedk0
    yes, QSS by far is not perfect and has many internal bugs.



  • @raven-worx said in Setting QObject properties through Qt CSS not fully working:

    @napajejenunedk0
    yes, QSS by far is not perfect and has many internal bugs.

    This statement is a bit scary, given that I have recently changed all the existing "in-line" code (i.e. native Qt widget calls) over to using stylesheets everywhere... :(


  • Moderators

    @JonB
    Sorry, but thats how it is.
    It of course depends on how extensively you are using QSS. In general it does it's job well, but there are some annoying special cases i already encountered over the years.
    And since QSS mostly fails silently they are hard to debug.



  • @raven-worx
    Still scary!! :)
    I am now using QSS everywhere, like I would use just CSS for all my HTML/CSS styling.

    And since QSS mostly fails silently they are hard to debug.

    Couldn't agree more! It seems to use qDebug() for any problems, and doesn't even return error codes. Already faced this, for the record (others might wish to copy) as a consequence when reading my application stylesheets the code I use is along the following lines:

    def readStylesheets():
        hdlr = errfunctions.addQtMessageDialogHandler()
        try:
            QtWidgets.QApplication.instance().setStyleSheet(css)
        finally:
            errfunctions.removeQtMessageDialogHandler(hdlr)
    
    def addQtMessageDialogHandler() -> LoggingDialogHandler:
        # Add a LoggingDialogHandler to when qtMessageHandler() (which uses qtLogger) is called
        hdlr = LoggingDialogHandler()
        qtLogger.addHandler(hdlr)
        return hdlr
    
    def removeQtMessageDialogHandler(hdlr: LoggingDialogHandler):
        # Remove a LoggingDialogHandler previously added via addQtMessageDialogHandler()
        qtLogger.removeHandler(hdlr)
    
    def qtMessageHandler(type: QtCore.QtMsgType, context: QtCore.QMessageLogContext, msg: str):
        # Message handler for Qt qDebug() etc.
        # see https://evileg.com/en/post/154/,
        # https://stackoverflow.com/questions/35894171/redirect-qdebug-output-to-file-with-pyqt5,
        # http://thispageintentionally.blogspot.co.uk/2014/03/trapping-qt-log-messages.html
        ...
    
    
    # install qtMessageHandler() to handle qDebug() etc.
    QtCore.qInstallMessageHandler(qtMessageHandler)
    
    

    i.e. the gist here is I have a global qtMessageHandler() function defined --- which is what qDebug() etc. all call --- and installed via QtCore.qInstallMessageHandler(), so I can see all debug errors/warnings. And when I'm about to read a QSS stylesheet, I wrap the reading code so that it throws up an actual "error dialog" (or whatever you want) if any qDebug() is executed by the Qt reading code, as the only way to clearly see if there has been any kind of error.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.