Changing Q_PROPERTY in pseudo state of a widget stylesheet does not notify



  • Hi,

    I customized QLineEdit by deriving from it. Then added an action and set an icon. The icon is set via a propery in the stylesheet.
    For the read-only pseudo state of the line edit, another icon must be selected. The stylesheet defines this by having a different value for the icon property at the read-only state.

    The icon property has a notify function that signals the IconChanged function.
    ClearIconChanged is called once at initialization but not when the widget is set to read-only later.

    For testing I defined in the stylesheet a green background color for the read-only state. This works, the background color changes when toggling read-only.

    Class:

    class QMyLineEdit : public QLineEdit
    {
        Q_OBJECT
        Q_PROPERTY( QString action_icon MEMBER m_strIcon NOTIFY IconChanged )
    
    public:
        explicit QMyLineEdit( QWidget* parent )
    		: QLineEdit( parent )
    		, m_pAction( nullptr )
    	{
    		m_pAction = new QAction( this );
    		connect( m_pClearAction, &QAction::triggered, this, &QMyLineEdit::MyAction );
    		addAction( m_pAction, QLineEdit::TrailingPosition );
    		connect( this, &QMyLineEdit::IconChanged, this, &QMyLineEdit::UpdateIcon );
    	}
    
    private:
        QAction* m_pAction;
        QString  m_strIcon;
    
    signals:
        void IconChanged();
    
    private slots:
        void UpdateIcon()
    	{
    		QIcon ClearIcon( m_strClearIcon );
    		m_pAction->setIcon( ClearIcon );
    	}
    	
        void MyAction()
    	{
    		/* ... */
    	}  
    };
    

    Stylesheet

    .QMyLineEdit {
        qproperty-action_icon: url(:/Widgets/action.png);
    }
    
    .QMyLineEdit:read-only {
        background-color: green;
        qproperty-action_icon: url(:/Widgets/action_readonly.png);
    }
    

    Now my questions.

    Are changing properties in a pseudo state supported?
    What is the common way to get such behavior?


  • Qt Champions 2016

    @Arie
    You have to raise the signal on your own.

    void UpdateIcon()
    {
        QIcon ClearIcon( m_strClearIcon );
        m_pAction->setIcon( ClearIcon );
        emit IconChanged(); //< Did you forget this?
    }
    

    Kind regards.



  • I believed NOTIFY means that Qt emits the signal when the property was changed.

    Now I changed the property definition to

    Q_PROPERTY( QString action_icon READ GetActionIcon WRITE SetActionIcon )
    

    so I can debug when its read and written.

    The breakpoints were hit on initialization, the property was read once before it was set and later it was set with the default (non-pseudo state value). They were not hit when the state changed.


  • Qt Champions 2016

    @Arie
    If you use MEMBER you specify the READ, WRITE and NOTIFY and the moc will generate those for you. If you don't use MEMBER you specify READ, WRITE and NOTIFY and implement them yourself.



  • @kshegunov
    I think my last version of Q_PROPERTY definition is right. If somehow the property changes, it must call the SetActionIcon function.

    But why is SetActionIcon function not called when toggling the read-only pseudo state of QMyLineEdit?


  • Qt Champions 2016

    @Arie
    Maybe there's some confusion. You either do this:

    Q_PROPERTY( QString action_icon MEMBER m_icon READ GetActionIcon WRITE SetActionIcon NOTIFY actionChanged)
    

    and when SetActionIcon is called the actionChanged will be emitted.

    Or you do it like this:

    class QMyLineEdit : public QLineEdit
    {
        Q_PROPERTY( QString action_icon READ GetActionIcon WRITE SetActionIcon NOTIFY actionChanged)
        // ...
    };
    
    QString QMyLineEdit::GetActionIcon()
    {
        return m_icon;
    }
    
    void QMyLineEdit::SetActionIcon(const QString & icon)
    {
        m_icon = icon;
        emit actionChanged();
    }
    

    In any case emitting actionChanged() will not trigger SetActionIcon, because it's to notify others that the property has changed, not the other way around.

    Kind regards.



  • @kshegunov
    I think too there is some confusion.
    This is the updated version of the class. QPROPERTY now only takes READ and WRITE functions, NOTIFY is left out.

    class QMyLineEdit : public QLineEdit
    {
        Q_OBJECT
        Q_PROPERTY( QString action_icon READ GetIcon WRITE SetIcon )
    
    public:
        explicit QMyLineEdit( QWidget* parent )
    		: m_pAction( nullptr )
    	{
    		m_pAction = new QAction( this );
    		connect( m_pAction, &QAction::triggered, this, &QMyLineEdit::MyAction );
    		addAction( m_pAction, QLineEdit::TrailingPosition );
    	}
    
    private:
        QAction* m_pAction;
        QString  m_strIcon;
    
        const QString& GetIcon() const
        {	/* Breakpoint hit at initialization, before SetIcon */
            return m_strClearIcon;
        }
        
        void SetIcon( const QString& strIcon )
    	{	/* Breakpoint hit at initialization but not when read-only was
    		 * toggled via QLineEdit::setReadOnly() */
    		m_strIcon = strIcon;
    		QIcon Icon( m_strIcon );
    		m_pAction->setIcon( Icon );
    	}
        
        void MyAction(){ /* ... */ } 
    };
    

    The stylesheet part remained same.

    .QMyLineEdit {
        qproperty-action_icon: url(:/Widgets/action.png);
    }
    
    .QMyLineEdit:read-only {
        background-color: green;
        qproperty-action_icon: url(:/Widgets/action_readonly.png);
    }
    

    In short my issue: Toggling read-only with setReadOnly( bool ) toggles the background color but not my action's icon.



  • Any other idea why the WRITE function is not called at the widget’s pseudo state change when the stylesheet has different qproperty values defined for the states?


Log in to reply
 

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