1

I'm trying to animate a line around a fixed point in Qt. I assume I need to use the QPropertyAnimation class to do this but cannot figure out which property to use.

For clarity, here's what I'm trying to do.

|        (5, 10)
|       /
|      /
|     /
|    /          (10, 5)   
|   /          .
|  /
| /           
|/
|--------------------------
 ^
 |---(0,0)

Given (x1, y1) = (0, 0) & (x2, y2) = (5, 10), this would be the first frame of the animation. I'd like to then do a smooth animation from (x1, y1), (x2, y2), (with (x1, y1) being one end of the line and (x2, y2) being the other end) to (x1, y1), (x3, y3), with (x3, y3) = (10, 5). Similar to how a clock hand is animated. And before someone posts the analog clock example it uses a rotating pixmap which is not what I need.

I haven't found a whole lot of information on Qt animations, just a lot of basic GUI tutorials.

I have tried doing the following

QPropertyAnimation *anim = new QPropertyAnimation(widget, "geometry")

and the problem with this method is that in this technique the widget is moved between 2 points based on (0, 0) of the widget using the ->setStartValue(startX, startY, ...) and does not allow me to keep one of my lines at a fixed point.

and

QPropertyAnimation *anim = new QPropertyAnimation(widget, "rotation")

The problem with this method being similar to geometry in that it rotates said widget along a (0, 0) point.

Can someone tell me how to achieve the desired effect?

Thanks.

Mohammad Kanan
  • 4,452
  • 10
  • 23
  • 47
GotAQtQ
  • 13
  • 2
  • How are you drawing the line, are you using QPainter, or QGraphicsLineItem, or another method? – eyllanesc Jul 20 '18 at 13:54
  • Ideally I'd like to use QGraphicsLineItem but I'm open to whatever gets the job done. – GotAQtQ Jul 20 '18 at 13:57
  • According to what I see, you want the line to rotate with respect to the point (0, 0), is that correct? – eyllanesc Jul 20 '18 at 14:00
  • ... sort of... but I don't mean using the "rotation" property because I need to be able to control the line length. Rotation implies I cannot control line length. Using transformed pixmaps (like analog clock example), geometry property or rotation property is not what I'm looking for. You can think of it as rotating a line while being able to control how long the line is. The aforementioned methods do not allow me to control how long the line is. Hopefully that's clear. – GotAQtQ Jul 20 '18 at 14:04
  • Actually if you know how to do it using geomtry or rotation property I'm all ears but have tried a lot of ways with those methods and it didn't work. – GotAQtQ Jul 20 '18 at 14:05
  • call P1 at the fixed end and P2 at the mobile end of the line, I understand that you want to move P2 from an initial P2 (5, 10) to a final P2 (10, 5) through a certain trajectory, what is that trajectory? – eyllanesc Jul 20 '18 at 14:07
  • You understand correctly. Ideally I would like to move the mobile end of the line along a straight line from mobile end P2 to mobile end P3, what exactly that trajectory is would normally be determined by QPropertyAnimation->setEasingCurve(Qt::...) but for right now I'm literally open to any trajectory and any method that allows for a smooth animation between the mobile points. – GotAQtQ Jul 20 '18 at 14:12
  • okay, now I understand it a lot better. – eyllanesc Jul 20 '18 at 14:13

1 Answers1

0

QGraphicsXXXItem do not support q-properties so they can not be used with QPropertyAnimation directly. So the solution is to create a class that inherits QObject and QGraphicsLineItem, plus we must add a q-property that handles the p2 position of the QLineF associated with the line as shown below:

lineitem.h

#ifndef LINEITEM_H
#define LINEITEM_H

#include <QGraphicsLineItem>
#include <QObject>

class LineItem: public QObject, public QGraphicsLineItem {
    Q_OBJECT
    Q_PROPERTY(QPointF p1 READ p1 WRITE setP1)
    Q_PROPERTY(QPointF p2 READ p2 WRITE setP2)

public:
    using QGraphicsLineItem::QGraphicsLineItem;

    QPointF p1() const {
        return  line().p1();
    }

    void setP1(const QPointF & p){
        QLineF l = line();
        l.setP1(p);
        setLine(l);
    }

    QPointF p2() const {
        return  line().p2();
    }

    void setP2(const QPointF & p){
        QLineF l = line();
        l.setP2(p);
        setLine(l);
    }
};

#endif // LINEITEM_H

main.cpp

#include "lineitem.h"

#include <QApplication>
#include <QGraphicsView>
#include <QPropertyAnimation>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsScene scene(-100, -100, 200, 200);
    QGraphicsView view(&scene);

    QGraphicsLineItem *item = scene.addLine(QLine(0, 100, 100, 0));
    item->setPen(QPen(Qt::red, 5));

    LineItem *lineItem = new LineItem(QLineF(QPointF(0, 0), QPointF(0, 100)));
    scene.addItem(lineItem);
    lineItem->setPen(QPen(Qt::green, 2));

    QPropertyAnimation *anim = new QPropertyAnimation(lineItem, "p2");
    anim->setStartValue(QPointF(0, 100));
    anim->setEndValue(QPointF(100, 0));
    anim->setDuration(2000);
    anim->start();

    view.resize(640, 480);
    view.show();
    return a.exec();
}

Another way is to use QVariantAnimation:

#include <QApplication>
#include <QGraphicsView>
#include <QPropertyAnimation>
#include <QGraphicsLineItem>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsScene scene(-100, -100, 200, 200);
    QGraphicsView view(&scene);

    scene.addLine(QLine(0, 100, 100, 0), QPen(Qt::green));

    QGraphicsLineItem *item = scene.addLine(QLine(0, 0, 0, 100));
    item->setPen(QPen(Qt::red, 5));

    QVariantAnimation * anim = new QVariantAnimation(&scene);
    anim->setStartValue(QPointF(0, 100));
    anim->setEndValue(QPointF(100, 0));
    anim->setDuration(2000);
    anim->start();

    QObject::connect(anim, &QVariantAnimation::valueChanged, [item](const QVariant & val){
        QLineF l = item->line();
        l.setP2(val.toPointF());
        item->setLine(l);
    });

    view.resize(640, 480);
    view.show();
    return a.exec();
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • The task is simple if you know the operation and requirements of each class, read the following: http://doc.qt.io/qt-5/animation-overview.html – eyllanesc Jul 20 '18 at 14:47
  • does not qt already has class QGraphicsObject that is combination of QGraphicsItem and QObject ? – Andrew Kashpur Jul 20 '18 at 14:57
  • @AndrewKashpur Yes, you could use QGraphicsObject, that's another option but let's say the *drawback* is that you'll have to implement the paint() and boundingRect() method. :) – eyllanesc Jul 20 '18 at 14:59