Qt dynamic properties

Posted by w.geoghegan on Mon, 29 Nov 2021 05:31:53 +0100

Dynamic properties unpolish() and polish() of Qt

1. Attributes in QT

  • Property refers to the properties of the window or control. For example, the opacity property represents transparency, geometry refers to position and size, and the pos property represents position. The controls in qt have their own properties. We can also define properties ourselves. QObject has a function setProperty. We can define our own properties through this function. The method is very simple, setProperty(const)
    char * name, const QVariant &
    value), the first parameter is the name of the attribute, and the second parameter is the attribute value. In addition to the above methods, there is also a method to customize attributes, which is used in a class inherited from QObject   Q_PROPERTY   Macro instruction. Its simple usage is as follows:
    Q_PROPERTY(bool focus READ hasFocus) 
    Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
    Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)

    Q_ Property (parameter type parameter name READ get property value function WRITE set property value function)
    Like Q_PROPERTY(bool bIsDoubi READ getDoubi WRITE setDoubi );
    Where the attribute type is bool type and bisdouble is the attribute name. In addition, you need to write two functions. The first is the function void that sets the property
    setDoui(bool). The second is the function bool getDoubi() to obtain the attribute.

  • 2. What are the functions of user-defined attributes

  • The currently known custom attributes have two purposes. The first is to change the style and the second is to animate. They are explained below:
  • 1) Change style

    Open the Qt assistant and find the syntax part of the style sheet. There is an attribute selector in setting the style through the selector, such as QPushButton[flat = "false"] which means the style when the button attribute flat is false.
    Take chestnuts for example. We have a QWidget class called PropertyTest. There is a button called pushButton in the interface

#pushButton{border:4px solid blue;}
PropertyTest[borderColor="red"] #pushButton{border:4px solid red;}
 PropertyTest[borderColor="green"] #pushButton{border:4px solid green;}
 PropertyTest[borderColor="blue"] #pushButton{border:4px solid blue;}

The default style of the button is blue. Change the color of the button by changing the property borderColor value of the PropertyTest class.
In the code, first define the properties

Q_PROPERTY(QString borderColor READ getBorderColor WRITE setBorderColor)

Use a member variable to save the value of the attribute, and set and obtain the value through the set and get functions respectively.

private:    
QString m_strBorderColor;
private:    
void setBorderColor(const QString &strBorderColor){ m_strBorderColor = strBorderColor; }   
QString getBorderColor(){ return m_strBorderColor; }

  Click the button pushButton to change the attribute value, thereby changing the style of the button pushButton.

void PropertyTest::changeBorderColor()
{
    if (m_iTest % 3 == 0)    
    {        
    	setBorderColor("red");    
    }    
    else if (m_iTest % 3 == 1)   
     {        
     	setBorderColor("green");    
     }    
     else   
      {        
      	setBorderColor("blue");    
      }    
      style()->unpolish(ui.pushButton_3);    
      style()->polish(ui.pushButton_3);    
      update();    
      m_iTest++;
      }

Finally, notice the unpolish and polish sections in the above code.
There is a reminder in the Qt document that when using the property selector, if the previous control has other styles, you need to rewrite the setting, "the old ones don't go, the new ones don't come", erase the old styles through unpolish and polish, and paint the new styles.

2) Use custom attributes in animation

  • If we want to make a button gradually transparent through animation, the idea will be like this: the button QPushButton inherits from the QWidget. There is a function setWindowOpacity in the QWidget, so we only need to use the animation class QPropertyAnimation, and the parameter of the attribute is set to windowOpacity.
    However, in practice, the button transparency will not change. You can only know by continuing to view the document - the property of windowOpacity can take effect only by calling the setWindowFlags function and setting the window property to Qt::Window. But pushbutton is not a normal widget.
    Therefore, it is necessary to find other methods. In QWidget, there is a function setGraphicsEffect(QGraphicsEffect *), in which QGraphicsEffect has a derived class QGraphicsOpacityEffect, which can be used to set the transparency of QWidget
    m_pOpacityEffect = new QGraphicsOpacityEffect(this);
    m_pOpacityEffect->setOpacity(1);
    this->setGraphicsEffect(m_pOpacityEffect);
    
    Q_PROPERTY(qreal buttonOpacity READ buttonOpacity WRITE setBtnOpacity)

    The above writing may not be very good, because the accuracy of qreal is related to the machine. It is best to use double or float.
    When defining the attribute, change the QGraphicsOpacityEffect object in the function setBtnOpacity to adjust the transparency.
    OK, now let's set the animation attribute name to buttonopacity——   QPropertyAnimation::setPropertyName(“buttonOpacity”)  , You can change the transparency of the button through animation.

Chestnuts

The QPropertyAnimation class defines the attribute animation of Qt.

QPropertyAnimation takes the Qt attribute as the difference value and stores it in qvariables as the attribute value. This class inherits from QVariantAnimation and supports the same meta type animation as the base class.

The class declaring the property must be a QObject. In order to make the property be used for animation, a setter must be provided (in this way, QPropertyAnimation can set the value of the property). Note: this enables it to animate many Qt controls.

QPropertyAnimation *animation = new QPropertyAnimation(myWidget, "geometry");
animation->setDuration(10000);
animation->setStartValue(QRect(0, 0, 100, 30));
animation->setEndValue(QRect(250, 250, 100, 30));
 
animation->start();

First, we create a QPropertyAnimation object through the constructor, where myWidget represents the QObject object for animation, and geometry represents the properties of QObject. You can then specify the start and end values of the attribute. This process is equivalent to implementing a custom attribute in your own class - you need to use QVariantAnimation to check whether your custom QVariant type is supported.

The QVariantAnimation class describes in detail how to animate. It should be noted that if the starting value is not set, when the QPropertyAnimation instance is created, the property will set the starting value to the value it has.

QPropertyAnimation works very well in itself. For complex animations, such as including multiple objects, you can use QAnimationGroup. An animation group is an animation that can contain other animations and manage the playback of animations. You can refer to the example of qparlelanimationgroup.

1. Original attribute

Use the geometry attribute explained above to realize an animation coordinate change.

 

QPropertyAnimation *pAnimation = new QPropertyAnimation(m_pLabel, "geometry");
pAnimation->setDuration(1000);
pAnimation->setStartValue(QRect(0, 0, 75, 25));
pAnimation->setEndValue(QRect(200, 130, 75, 25));
pAnimation->setEasingCurve(QEasingCurve::OutBounce);  // Spiral style
connect(pStartButton, SIGNAL(clicked(bool)), pAnimation, SLOT(start()));

2. Custom properties

Use the custom attribute alpha to animate the style of the label.

 

#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H
 
...
 
class MainWindow : public CustomWindow
{
    Q_OBJECT
    Q_PROPERTY(int alpha READ alpha WRITE setAlpha)
 
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
 
private:
    int alpha() const;
    void setAlpha(const int alpha);
 
private:
    int m_nAlpha;
    QLabel *m_pLabel;
};
 
#endif // MAIN_WINDOW_H
#include "main_window.h"
 
MainWindow::MainWindow(QWidget *parent)
    : CustomWindow(parent)
{
    ...
 
    QPushButton *pStartButton = new QPushButton(this);
    pStartButton->setText(QString::fromLocal8Bit("Start animation"));
 
    m_pLabel = new QLabel(this);
    m_pLabel->setText(QString::fromLocal8Bit("One, two, three miles"));
    m_pLabel->setAlignment(Qt::AlignCenter);
    m_pLabel->setStyleSheet("color: rgb(0, 160, 230);");
 
    QPropertyAnimation *pAnimation = new QPropertyAnimation();
    pAnimation->setTargetObject(this);
    pAnimation->setPropertyName("alpha");
    pAnimation->setDuration(1000);
    pAnimation->setKeyValueAt(0, 255);
    pAnimation->setKeyValueAt(0.5, 100);
    pAnimation->setKeyValueAt(1, 255);
    pAnimation->setLoopCount(-1);  //Run forever until stop
    connect(pStartButton, SIGNAL(clicked(bool)), pAnimation, SLOT(start()));
 
    ...
}
 
int MainWindow::alpha() const
{
    return m_nAlpha;
}
 
void MainWindow::setAlpha(const int alpha)
{
    m_nAlpha = alpha;
    QString strQSS = QString("color: rgb(0, 160, 230); background-color: rgba(10, 160, 105, %1);").arg(m_nAlpha);
    m_pLabel->setStyleSheet(strQSS);
}

  Qt qss dynamic attribute

QFrame#frmPreImg[selected=false]{
    border:none;
    background-color:#D8DFEA;
}
QFrame#frmPreImg[selected=true]{
    border:4px solid #32CD32;
    background-color:#D8DFEA;
}
m_frmPreImg1->setProperty("selected",true);
      m_frmPreImg1->style()->unpolish(m_frmPreImg1);
      m_frmPreImg1->style()->polish(m_frmPreImg1);

      m_frmPreImg1->update();

reference resources

  1. Dynamic properties unpolish() and polish() of Qt
  2. qpropertyanimation of Qt_ Youth is not old, struggle- CSDN blog_ qpropertyanimation

Topics: C++ git Qt