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

一、简介

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

二、运行图

(1)绕X轴旋转
       rotate()参数为Qt::XAxis

(2)绕Y轴旋转      
       rotate()参数为Qt::YAxis

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


三、详解

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)若有不足,请留言,在此先感谢!
  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
要在Qt中实现在QGraphicsView中拖动QGraphicsItem,你可以按照以下步骤: 1. 创建一个QGraphicsScene实例,并将其设置为QGraphicsView的场景。 2. 在QGraphicsScene中创建一个QGraphicsItem。 3. 将QGraphicsItem添加到QGraphicsScene中。 4. 重写QGraphicsItem的mousePressEvent和mouseMoveEvent方法,以便在鼠标按下和移动时更新其位置。 5. 为QGraphicsView启用拖动功能,通过将setDragMode方法设置为ScrollHandDrag来实现。 下面是一个简单的示例代码: ```cpp #include <QtWidgets> class GraphicsItem : public QGraphicsRectItem { public: GraphicsItem(QGraphicsItem* parent = nullptr) : QGraphicsRectItem(parent) { setRect(0, 0, 50, 50); setFlag(QGraphicsItem::ItemIsMovable, true); } protected: void mousePressEvent(QGraphicsSceneMouseEvent* event) override { QGraphicsRectItem::mousePressEvent(event); setCursor(Qt::ClosedHandCursor); } void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override { QGraphicsRectItem::mouseMoveEvent(event); } void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override { QGraphicsRectItem::mouseReleaseEvent(event); setCursor(Qt::OpenHandCursor); } }; int main(int argc, char** argv) { QApplication app(argc, argv); QGraphicsScene scene; QGraphicsView view(&scene); view.setDragMode(QGraphicsView::ScrollHandDrag); GraphicsItem* item = new GraphicsItem; scene.addItem(item); view.setSceneRect(0, 0, 500, 500); view.show(); return app.exec(); } ``` 在这个例子中,我们创建了一个自定义的QGraphicsRectItem子类,重写了mousePressEvent、mouseMoveEvent和mouseReleaseEvent方法。当鼠标按下时,我们将鼠标光标设置为ClosedHandCursor,表示拖动状态开始。当鼠标移动时,QGraphicsRectItem的默认实现会更新其位置。当鼠标释放时,我们将鼠标光标设置为OpenHandCursor,表示拖动状态结束。 我们还创建了一个QGraphicsScene实例,并在其中添加了一个GraphicsItem实例。最后,我们将QGraphicsView的场景设置为QGraphicsScene,并启用了拖动功能。 这个例子只是一个简单的演示,你可以根据你的需求进行更改和扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乌托邦2号

博文不易,支持的请给予小小打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值