1

I'm doing a school project and I'm stuck here. I'm trying to make my hexagon gradually change its color from yellow to blue. This is my hexagon.hh:

#ifndef HEXAGON_HH
#define HEXAGON_HH

#include <QGraphicsPolygonItem>
#include <QPropertyAnimation>
#include "gamecontroller.hh"


class GameController;

class Hexagon : public QGraphicsPolygonItem
{
public:
    Hexagon(QGraphicsItem *parent = 0);
    ~Hexagon();

    GameController* _controller;
    Common::CubeCoordinate _coord;

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent* event);

};

#endif // HEXAGON_HH

I tried to use QPropertyAnimation like this:

QPropertyAnimation* animation = new QPropertyAnimation(_Tilemap.at(tileCoord)->hexagon_, "brush");
animation->setDuration(10000);
animation->setStartValue(QBrush(Qt::yellow()));
animation->setEndValue(QBrush(Qt::blue()));
animation->start();

But it couldn't be used on the hexagon class so it didn't work. How could I make the hexagon change its color so that there's an animation?

e: heres the error I get when I tried to use QPropertyAnimation:

/home/litmanen/test/UI/gamecontroller.cpp:256: error: no matching function for call to ?QPropertyAnimation::QPropertyAnimation(Hexagon*&, const char [6])?
     QPropertyAnimation* animation = new QPropertyAnimation(_Tilemap.at(tileCoord)->hexagon_, "brush");
Haplme
  • 13
  • 3
  • 1
    change `Qt::yellow()` to `Qt::yellow` and `Qt::blue()` to `Qt::blue` – eyllanesc Nov 18 '18 at 12:53
  • Ah sorry I accidentally left them like that, they're actually just like you suggested in my code. – Haplme Nov 18 '18 at 12:57
  • Do you have an error message? – eyllanesc Nov 18 '18 at 13:02
  • error: no matching function for call to ?QPropertyAnimation::QPropertyAnimation(Hexagon*&, const char [6])? QPropertyAnimation* animation = new QPropertyAnimation(_Tilemap.at(tileCoord)->hexagon_, "brush"); I figured I need to figure out an alternative method to make the animation(?) – Haplme Nov 18 '18 at 13:04
  • that information is important, add it in your question – eyllanesc Nov 18 '18 at 13:05

1 Answers1

1

The error is caused because QPropertyAnimation only apply to QObject, in your case QGraphicsPolygonItem is not. So a possible solution is to inherit from QObject:

*.h

#ifndef HEXAGON_H
#define HEXAGON_H

#include <QBrush>
#include <QGraphicsPolygonItem>
#include <QObject>

class Hexagon : public QObject, public QGraphicsPolygonItem
{
    Q_OBJECT
    Q_PROPERTY(QBrush brush READ brush WRITE setBrush)
public:
    explicit Hexagon(QObject *parent=nullptr);

    GameController* _controller;
    Common::CubeCoordinate _coord;
protected:
    void mousePressEvent(QGraphicsSceneMouseEvent* event);

};

#endif // HEXAGON_H

*.cpp

#include "hexagon.h"

Hexagon::Hexagon(QObject *parent):
    QObject(parent)
{
    /*another code*/
}

void Hexagon::mousePressEvent(QGraphicsSceneMouseEvent* event){
    /*another code*/
}

On the other hand it still does not work since there is no interpolator for QBrush, so the solution is to implement an interpolator (use the interpolator of this solution)

static QVariant brushInterpolator(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  );

}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    qRegisterAnimationInterpolator<QBrush>(brushInterpolator);
    // ...

Another solution is to implement the same logic with QColor that does not need an interpolator:

*.h

#ifndef HEXAGON_H
#define HEXAGON_H

#include <QGraphicsPolygonItem>
#include <QObject>

class Hexagon : public QObject, public QGraphicsPolygonItem
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ color WRITE setColor)
public:
    explicit Hexagon(QObject *parent=nullptr);
    QColor color() const;
    void setColor(const QColor &color);

    GameController* _controller;
    Common::CubeCoordinate _coord;
protected:
    void mousePressEvent(QGraphicsSceneMouseEvent* event);
};

#endif // HEXAGON_H

*.cpp

#include "hexagon.h"

#include <QBrush>

Hexagon::Hexagon(QObject *parent):
    QObject(parent)
{
    QBrush b = brush();
    b.setStyle(Qt::SolidPattern);
    setBrush(b);
    /*another code*/
}

QColor Hexagon::color() const
{
    return brush().color();
}

void Hexagon::setColor(const QColor &color)
{
    QBrush b = brush();
    b.setColor(color);
    setBrush(b);
}

void Hexagon::mousePressEvent(QGraphicsSceneMouseEvent* event){
    /*another code*/
}

Then you use "color" instead of "brush":

QPropertyAnimation* animation = new QPropertyAnimation(_Tilemap.at(tileCoord)->hexagon_, "color");
animation->setDuration(10000);
animation->setStartValue(QColor(Qt::yellow));
animation->setEndValue(QColor(Qt::blue));
animation->start();

Another simpler solution is to use QVariantAnimation:

auto it = _Tilemap.at(tileCoord)->hexagon_;
QVariantAnimation *animation = new QVariantAnimation;
QObject::connect(animation, &QVariantAnimation::valueChanged, [it](const QVariant & v){
    it->setBrush(QBrush(v.value<QColor>()));
});
animation->setDuration(10000);
animation->setStartValue(QColor(Qt::yellow));
animation->setEndValue(QColor(Qt::blue));
animation->start();
eyllanesc
  • 235,170
  • 19
  • 170
  • 241