Qt浅谈之二十三QGraphicsItem旋转动画

一、简介

       QGraphicsItem中水平动画使用QGraphicsItemAnimation和QTimeLine即可实现,而旋转动画须使用QTimeLine和QTransform来实现。QWidget中也可实现相同的效果。

二、运行图

(1)绕X轴旋转
       rotate()参数为Qt::XAxis
Qt浅谈之二十三QGraphicsItem旋转动画_第1张图片
(2)绕Y轴旋转      
       rotate()参数为Qt::YAxis
Qt浅谈之二十三QGraphicsItem旋转动画_第2张图片

(2)绕Z轴旋转      
       rotate()参数为Qt::ZAxis

Qt浅谈之二十三QGraphicsItem旋转动画_第3张图片

三、详解

1、代码(QTimer)

(1)main.cpp

#include "mainwindow.h"
#include <QApplication>
#include <QtGui>
#include <QGraphicsScene>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    TxtItem *txtItem = new TxtItem;
    txtItem->setText("How are you, my friend!!");

    QGraphicsScene scene;
    MyQView mqv(&scene);

    scene.addItem(txtItem);

    mqv.show();
    return a.exec();
}
(2)mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsView>
#include <QGraphicsItem>
#include <QTimer>

class MyQView : public QGraphicsView {
    Q_OBJECT
public:
    MyQView(QGraphicsScene *scene);
    ~MyQView();
};

class TxtItem : public QObject, public QGraphicsItem {
    Q_OBJECT
public:
    explicit TxtItem(QGraphicsItem *parent = 0);
    ~TxtItem();

   void paint(QPainter * painter,
              const QStyleOptionGraphicsItem * option,
              QWidget * widget = 0);
   QRectF boundingRect () const;
   void setText(const QString &newText);

public slots:
   void flip();

private slots:
   void animateFilp();

private:
    QTimer *tm;
    int m_angle;   //rotation angle
    int m_delta;
    int m_current; //store rotation direction
    QString m_text;
};

#endif // MAINWINDOW_H
(3)mainwindow.cpp
#include "mainwindow.h"
#include <QTimer>
#include <QDebug>

MyQView::MyQView(QGraphicsScene *scene) : QGraphicsView(scene)
{
    setGeometry(100, 100, 800, 600);
    setWindowFlags(Qt::FramelessWindowHint);
}

MyQView::~MyQView()
{
}

TxtItem::TxtItem(QGraphicsItem *parent)
    : QGraphicsItem(parent)
{

    m_angle = 0;
    m_delta = 0;
    m_current = 0;
    //setOpacity(0.5);

    tm = new QTimer;
    tm->setInterval(2000);
    connect(tm, SIGNAL(timeout()), this, SLOT(flip()));
    tm->start();
    //QTimer::singleShot(10, this, SLOT(flip()));
    //flip();
}

TxtItem::~TxtItem()
{
    if (tm) {
       if (tm->isActive()) tm->stop();
       delete tm;
       tm = NULL;
    }
}

void TxtItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QBrush brush(Qt::cyan);
    painter->setBrush(brush);

    painter->drawRect(boundingRect());

    painter->setPen(QPen(Qt::magenta, 10));
    painter->drawText(boundingRect().x() + 180, boundingRect().y(),
                      boundingRect().width(), boundingRect().height(),
                      Qt::AlignLeft | Qt::AlignVCenter, m_text);
}

QRectF TxtItem::boundingRect() const
{
    return QRectF(0, 0, 500, 300);
}

void TxtItem::setText(const QString &newText) {
    m_text = newText;
}

void TxtItem::animateFilp()
{
    m_angle += m_delta;

    if(180 == m_angle) {
        m_current ^= 1;
    }
    QRectF r = boundingRect();
    setTransform(QTransform()
                 .translate(r.width() / 2, r.height() /2)
                 .rotate(m_angle, Qt::YAxis)
                 .translate(-r.width() / 2, -r.height() / 2));
    if((0 == m_current && m_angle > 0) || (1 == m_current && m_angle < 360)) {
        QTimer::singleShot(25, this, SLOT(animateFilp()));
    }
}

void TxtItem::flip()
{
    m_delta = (m_current == 0 ? 9 : -9);
    animateFilp();
}
       要想控制旋转的坐标轴,修改setTransform()中rotate()的第二个参数,默认是绕Z轴旋转。若只想旋转一次,则在构造函数中关闭定时器,使用QTimer::singleShot(10, this, SLOT(flip()));或直接调用flip()即可。

2、代码(QTimeLine)

(1)main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QtGui>
#include <QGraphicsScene>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    TxtItem *txtItem = new TxtItem;
    txtItem->setText("How are you, my friend!!");

    QGraphicsScene scene;
    MyQView mqv(&scene);

    scene.addItem(txtItem);

    mqv.show();
    return a.exec();
}
(2)mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsView>
#include <QGraphicsItem>
#include <QTimeLine>
#include <QDebug>
#include <QPushButton>
#include <QGraphicsProxyWidget>

class MyQView : public QGraphicsView {
    Q_OBJECT
public:
    MyQView(QGraphicsScene *scene);
    ~MyQView();

private slots:
    void slotClickedBtn();
};

class TxtItem : public QObject, public QGraphicsItem {
    Q_OBJECT
public:
    explicit TxtItem(QGraphicsItem *parent = 0);
    ~TxtItem();

   void paint(QPainter * painter,
              const QStyleOptionGraphicsItem * option,
              QWidget * widget = 0);
   QRectF boundingRect () const;
   void setText(const QString &newText);
   void setStatus();

private slots:
   void animateFilp(qreal value);

private:
    QString m_text;

    QTimeLine *timeLine;
};

#endif // MAINWINDOW_H
(3)mainwindow.cpp
#include "mainwindow.h"

MyQView::MyQView(QGraphicsScene *scene) : QGraphicsView(scene)
{
    setGeometry(100, 100, 800, 600);
    setWindowFlags(Qt::FramelessWindowHint);

    QPushButton *button = new QPushButton(this);
    connect(button, SIGNAL(clicked()), this, SLOT(slotClickedBtn()));

    button->setText(tr("Change"));
    button->move(350, 100);

}

MyQView::~MyQView()
{
}

void MyQView::slotClickedBtn()
{
    QList<QGraphicsItem *>itemList = this->items();
    dynamic_cast<TxtItem *>(itemList.at(0))->setStatus();
}

TxtItem::TxtItem(QGraphicsItem *parent)
    : QGraphicsItem(parent)
{
    timeLine = new QTimeLine(1500, this);
    timeLine->setDirection(QTimeLine::Forward);
    connect(timeLine, SIGNAL(valueChanged(qreal)), this, SLOT(animateFilp(qreal)));
    timeLine->start();

}

TxtItem::~TxtItem()
{
    if (timeLine) {
        if (timeLine->state() == QTimeLine::Running)
            timeLine->stop();
        delete timeLine;
        timeLine = NULL;
    }
}

void TxtItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QBrush brush(Qt::cyan);
    painter->setBrush(brush);

    painter->drawRect(boundingRect());

    painter->setPen(QPen(Qt::magenta, 10));
    painter->drawText(boundingRect().x() + 180, boundingRect().y(),
                      boundingRect().width(), boundingRect().height(),
                      Qt::AlignLeft | Qt::AlignVCenter, m_text);
}

QRectF TxtItem::boundingRect() const
{
    return QRectF(0, 0, 500, 300);
}

void TxtItem::setText(const QString &newText) {
    m_text = newText;
}

void TxtItem::setStatus()
{
    if (timeLine->state() == QTimeLine::Running) {
        return;
    }
    if (timeLine->currentValue() == 0) {
        timeLine->setDirection(QTimeLine::Forward);
        timeLine->start();
    }
    else {
        timeLine->setDirection(QTimeLine::Backward);
        timeLine->start();
    }
}

void TxtItem::animateFilp(qreal value)
{
    QRectF r = boundingRect();
    setTransform(QTransform()
                 .translate(r.width() / 2, r.height() /2)
                 .rotate(180 *value, Qt::YAxis)
                 .translate(-r.width() / 2, -r.height() / 2));
}
运行:

四、总结

(1)运行过程中会产生虚影,暂时不清楚怎么有什么参数可以优化。
(2)若有不足,请留言,在此先感谢!

你可能感兴趣的:(python)