GraphicsView框架结构主要包含三个主要的类QGraphicsScene(容器)、QGraphicsView(视图)、QGraphicsItem(图形项)。QGraphicsScene本身不可见必须通过与之相连的QGraphicsView视口类来显示及与外界进行互操作,主要提供项目的操作接口、传递事件和管理各个项目状态;QGraphicsView提供一个可视的窗口,用于显示场景中的项目,一个场景中可以有多个视口;QGraphicsItem是场景中各个项目的基础类。
(1)三者间的关系
(2)坐标系统
QGraphicsScene坐标系是以中心为原点(0,0),QGraphicsView继承自QWidget以窗口的左上角作为自己坐标系的原点,而QGraphicsItem则有自己的坐标系其paint()函数重画时以此坐标系为基准。
(3)坐标映射
三个坐标系之间的相互转换函数及图形项与图形项之间的转换函数。
(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)本人思路有限,若有更好的设计建议,也可发邮件沟通,在此先感谢!邮箱地址[email protected]。