Qt浅谈之十七:飞舞的蝴蝶(GraphicsView框架)

一、简介

       GraphicsView框架结构主要包含三个主要的类QGraphicsScene(容器)、QGraphicsView(视图)、QGraphicsItem(图形项)。QGraphicsScene本身不可见必须通过与之相连的QGraphicsView视口类来显示及与外界进行互操作,主要提供项目的操作接口、传递事件和管理各个项目状态;QGraphicsView提供一个可视的窗口,用于显示场景中的项目,一个场景中可以有多个视口;QGraphicsItem是场景中各个项目的基础类。

二、关系图

(1)三者间的关系


(2)坐标系统

QGraphicsScene坐标系是以中心为原点(0,0),QGraphicsView继承自QWidget以窗口的左上角作为自己坐标系的原点,而QGraphicsItem则有自己的坐标系其paint()函数重画时以此坐标系为基准。

(3)坐标映射

三个坐标系之间的相互转换函数及图形项与图形项之间的转换函数。

三、详解

1、运行图


2、解析

(1)利用定时器实现QGraphicsItem不停上下飞舞的蝴蝶的动画效果

#include <QGraphicsItem>
#include <QObject>

class Butterfly : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    Butterfly();
    void timerEvent(QTimerEvent *);
    QRectF boundingRect() const;
   
protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

    
private:
    bool up;
    QPixmap pix_up;
    QPixmap pix_down; 
    
    qreal angle;

};
static const double PI = 3.14159265358979323846264338327950288419717;

Butterfly::Butterfly()
{ 
    setFlag(QGraphicsItem::ItemIsMovable);

    pix_up.load(":/images/butterfly1.PNG");
    pix_down.load(":/images/butterfly2.PNG");
    up = true;
    startTimer(100);
}

QRectF Butterfly::boundingRect() const
{
    qreal adjust = 8;
    return QRectF(-pix_up.width()/2-adjust,-pix_up.height()/2-adjust,
                pix_up.width()+adjust*2,pix_up.height()+2*adjust);
}

void Butterfly::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    if(up)
    {
    	painter->drawPixmap(boundingRect().topLeft(),pix_up);
    	up = !up;
    }
    else
    {
    	painter->drawPixmap(boundingRect().topLeft(),pix_down);
    	up = !up;
    }
//    painter->setPen(Qt::NoPen);
//    painter->setBrush(Qt::darkGray);
//    painter->drawEllipse(-7,-7,40,40);

//    painter->setPen(QPen(Qt::black,0));
//    painter->setBrush(flash ? (Qt::red):(Qt::yellow));
//    painter->drawEllipse(-10,-10,40,40);
    	
}

void Butterfly::timerEvent(QTimerEvent *)
{
    // edge controll
    qreal edgex = scene()->sceneRect().right()+boundingRect().width()/2;
    qreal edgetop = scene()->sceneRect().top()+boundingRect().height()/2;
    qreal edgebottom = scene()->sceneRect().bottom()+boundingRect().height()/2;
    //qDebug() << scene()->itemsBoundingRect();
    if (pos().x() >= edgex)
    	setPos(scene()->sceneRect().left(),pos().y());
    if (pos().y() <= edgetop)
        setPos(pos().x(),scene()->sceneRect().bottom());
    if (pos().y() >= edgebottom)
        setPos(pos().x(),scene()->sceneRect().top());
    
    angle += (qrand()%10)/20.0;
    qreal dx = fabs(sin(angle*PI)*10.0);
    qreal dy = (qrand()%20)-10.0;
    
    setPos(mapToParent(dx,dy));
    update();
}
分析:在定时器的timeEvent()中对QGraphicsItem进行重画,重画paint()函数中飞舞的蝴蝶是由两幅图片组成,蝴蝶的移动边界做一个限定,dx和dy是相对于蝴蝶的坐标系而言的,调用setPos函数时使用mapToParent()函数映射成场景的坐标。setFlag(QGraphicsItem::ItemIsMovable);使蝴蝶可以通过鼠标移动。

(2)来回移动的星星

class StarItem : public QGraphicsItem
{
public:
    StarItem();

    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

private:
    QPixmap pix;
};
StarItem::StarItem()
{
    pix.load(":/images/star.png");
}

QRectF StarItem::boundingRect() const
{
    return QRectF(-pix.width()/2,-pix.height()/2,pix.width(),pix.height());
}

void
StarItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->drawPixmap(boundingRect().topLeft(),pix);
}
{
    StarItem *star = new StarItem;
    QGraphicsItemAnimation *anim = new QGraphicsItemAnimation;
    anim->setItem(star);
    QTimeLine *timeLine = new QTimeLine(4000);
    timeLine->setCurveShape(QTimeLine::SineCurve);
    timeLine->setLoopCount(0);
    anim->setTimeLine(timeLine);

    int y = (qrand()%400) - 200;
    for (int i=0; i<400; i++)
    {
        anim->setPosAt(i/400.0, QPointF(i-200,y));
    }
    timeLine->start();
    scene->addItem(star);
}
分析:利用QGraphicsItemAnimation类和QTimeLine实现项目的动画效果(也可使用定时器QTimer结合重绘函数来实现)。

(3)简单正方形

{
    QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0,0,60,60));
    QPen pen;
    pen.setWidth(3);
    pen.setColor(QColor(qrand()%256,qrand()%256,qrand()%256));
    item->setPen(pen);
    item->setBrush(QColor(qrand()%256,qrand()%256,qrand()%256));
    item->setFlag(QGraphicsItem::ItemIsMovable);
    scene->addItem(item);
    //item->setPos((qrand()%int(scene->sceneRect().width()))-200,(qrand()%int(scene->sceneRect().height()))-200);
    item->setPos(-200, -200);
} 
分析:利用继承QGraphicsItem的类QGraphicsRectItem添加一个正方形的图形项。

四、总结

(1)GraphicsView框架相对与QWidget难于理解,且内容也比较多,以后会继续更新相应的内容。

(2)本文没有涉及GraphicsView的事件的处理和传播(事件首先由视图接收然后传递给场景再由场景给相应的图形项),读者可自行查阅相应的资料。

(3)源码已经打包上传到csdn上可登录下载(http://download.csdn.net/detail/taiyang1987912/7785071)。  

(4)本人思路有限,若有更好的设计建议,也可发邮件沟通,在此先感谢!邮箱地址yang.ao@i-soft.com.cn。


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

乌托邦2号

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

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

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

打赏作者

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

抵扣说明:

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

余额充值