How to animate color of QBrush

1.9k Views Asked by At

I want to animate Color of QBrush. For more details see code below

That's my .h file

class Cell : public QObject, public QGraphicsRectItem
{
    Q_OBJECT
    Q_PROPERTY(QBrush brush READ brush WRITE set_Brush)
public:
    QBrush _brush() const;
    void set_Brush(const QBrush&);
    Cell(QGraphicsItem *parent = 0); //конструктор
}

That's my .cpp file

Cell::Cell(QGraphicsItem *parent)
    : QObject(), QGraphicsRectItem(parent) 
{
    this->setRect(0, 0, Scale, Scale); 
}

QBrush Cell::_brush() const
{
    return this->brush();
}

void Cell::set_Brush(const QBrush & brush)
{
    this->setBrush(brush);
}

and that's animation:

QPropertyAnimation* animation = new QPropertyAnimation(selectedCell, "brush");
animation->setDuration(10000);
animation->setStartValue(QBrush(QColor(255,0,0)));
animation->setEndValue(QBrush(QColor(0,255,0)));
animation->start();

But it doesn't work, nothing happens, color of brush is the same that was before. What should I do to fix it?

2

There are 2 best solutions below

0
On BEST ANSWER

QT does not know how to perform a transition between the start QBrush and the end QBrush. QBrush has more properties than just color, you could envisage an animation where the color stays the same and only the pattern changes. Thus there is no default support for this kind of transition. As @fscibe hinted, you can write your own method to perform a transition in which you specify how you want to transition from one QBrush to the other.

Crude example:

QVariant myColorInterpolator(const QBrush &start, const QBrush &end, qreal progress)
{
  QColor cstart = start.color();
  QColor cend = end.color();
  int sh = cstart.hsvHue();
  int eh = cend.hsvHue();
  int ss = cstart.hsvSaturation();
  int es = cend.hsvSaturation();
  int sv = cstart.value();
  int ev = cend.value();
  int hr = qAbs( sh - eh );
  int sr = qAbs( ss - es );
  int vr = qAbs( sv - ev );
  int dirh =  sh > eh ? -1 : 1;
  int dirs =  ss > es ? -1 : 1;
  int dirv =  sv > ev ? -1 : 1;

  return QBrush(QColor::fromHsv( sh + dirh * progress * hr,
                             ss + dirs * progress * sr,
                             sv + dirv * progress * vr), progress > 0.5 ? Qt::SolidPattern : Qt::Dense6Pattern  );


}

this performs a transition in the colors but also changes the pattern halfway through the transition.

Then here would be a dummy application of this transition in your code:

int main(int argc, char** argv)
{
  QApplication app(argc,argv);
  QGraphicsView *view = new QGraphicsView;
  QGraphicsScene *scene = new QGraphicsScene;
  QDialog *dialog = new QDialog;
  QGridLayout *layout = new QGridLayout;
  layout->addWidget(view);
  view->setScene(scene);
  scene->setSceneRect(-500,-500,1000,1000);
  dialog->setLayout(layout);
  dialog->show();

  Cell *selectedCell = new Cell;
  scene->addItem(selectedCell);

  qRegisterAnimationInterpolator<QBrush>(myColorInterpolator);
  QPropertyAnimation* animation = new QPropertyAnimation(selectedCell, "brush");
  animation->setDuration(10000);
  animation->setStartValue(QBrush(Qt::blue));
  animation->setEndValue(QBrush(Qt::red));
  animation->start();

  return app.exec();
}

Obviously this is dummy example and for the color change it is re-inventing the wheel as you see from fscibe answer, but this is to show you that defining your own transition method for e.g. QBrush you can do more than simply change the color.

2
On

You must provide your own implementation for interpolating on QBrush type. From Qt's doc:

"QPropertyAnimation interpolates over Qt properties. As property values are stored in QVariants, the class inherits QVariantAnimation, and supports animation of the same variant types as its super class." (http://qt-project.org/doc/qt-4.8/qpropertyanimation.html)

See the list of supported types and an example of how to implement a custom interpolation here in the "Detailed Description" section: http://qt-project.org/doc/qt-4.8/qvariantanimation.html

An alternative would be to interpolate between QColors only, and then update your brush:

class Cell : public QObject, public QGraphicsRectItem
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ _color WRITE set_Color)
public:
    Cell()
    {
        setRect(0,0,100,100); // non-zero rect
        m_brush.setStyle(Qt::SolidPattern); // fill color is active
    }

    QColor _color() const
    {
        return brush().color();
    }
    void set_Color(const QColor& c)
    {
        m_brush.setColor(c);
        setBrush( m_brush );
    }

    QBrush m_brush;
};

With animation:

QPropertyAnimation* animation = new QPropertyAnimation(selectedCell, "color");
animation->setDuration(10000);
animation->setStartValue(QColor(255,0,0));
animation->setEndValue(QColor(0,255,0));
animation->start();