一、简介
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。