飞舞的蝴蝶(GraphicsView框架)
飞舞的蝴蝶(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添加一个正方形的图形项。
注意编译时会出现如下警告:
Warning::Class Butterfly imlements the interface QGraphicsItem but does not list it in Q_INTERFACES ;qobject_cast to QGraphicsItem will not work
原因:
QGraphicsItem的paint方法是在item被重绘时调用的,除了调用这个接口函数外,他还需要调用另外几个接口函数,你是不是在类中没有写呀?
需要添加的函数列表:
QRectF boundingRect() const;
QPainterPath shape() const;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget);
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
void hoverEnterEvent(QGraphicsSceneHoverEvent * event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent * event);
一、简介
GraphicsView支持事件传播体系结构,可以使图元在场景scene中得到提高了已被的精确交互能力。图形视图框架中的事件都是首先由视图进行接收,然后传递给场景,再由场景给相应的图形项。
对于键盘鼠标事件,scene会传递给获得焦点的图形项。如果场景没有获得焦点,那键盘事件会丢弃;如果调用场景setFocus()或者场景中的一个图形项获得了焦点,那么场景会自动获得焦点;如果场景丢失了焦点(如调用clearFocus())而其中一个图形项获得焦点那场景会保存这个图形项的焦点信息。
图形项默认无法接收悬停事件,可以使用QGraphicsItem的setAcceptHoverEvents()函数使图形项可以接收悬停事件。
二、运行图
(1)五个图形项的运行图如下图所示。
三、详解
1、QGraphicsScene
- #ifndef MYSCENE_H
- #define MYSCENE_H
- #include <QGraphicsScene>
- #include <QGraphicsSceneMouseEvent>
- #include <QPaintEvent>
- #include <QKeyEvent>
- class MyScene : public QGraphicsScene
- {
- Q_OBJECT
- public:
- explicit MyScene(QObject *parent = 0);
- protected:
- void keyPressEvent(QKeyEvent *event);
- void mousePressEvent(QGraphicsSceneMouseEvent *event);
- signals:
- public slots:
- };
- #endif // MYSCENE_H
- #include "myscene.h"
- MyScene::MyScene(QObject *parent) :
- QGraphicsScene(parent)
- {
- clearFocus();
- }
- void MyScene::keyPressEvent(QKeyEvent *event)
- {
- qDebug("*********MyScene::keyPressEvent***************");
- return QGraphicsScene::keyPressEvent(event);
- }
- void MyScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
- {
- qDebug("*********MyScene::mousePressEvent***************");
- QGraphicsScene::mousePressEvent(event);
- }
2、QGraphicsView
- #ifndef MYVIEW_H
- #define MYVIEW_H
- #include <QGraphicsView>
- class MyView : public QGraphicsView
- {
- Q_OBJECT
- public:
- explicit MyView(QWidget *parent = 0);
- protected:
- void keyPressEvent(QKeyEvent *event);
- void mousePressEvent(QMouseEvent *event);
- void paintEvent(QPaintEvent * event);
- void mouseMoveEvent(QMouseEvent *event);
- signals:
- public slots:
- };
- #endif // MYVIEW_H
- #include "myview.h"
- #include <QKeyEvent>
- MyView::MyView(QWidget *parent) :
- QGraphicsView(parent)
- {
- }
- void MyView::keyPressEvent(QKeyEvent *event)
- {
- qDebug("*********MyView::keyPressEvent***************");
- switch (event->key())
- {
- case Qt::Key_Left :
- scale(1.2, 1.2);
- break;
- case Qt::Key_Right :
- scale(1 / 1.2, 1 / 1.2);
- break;
- case Qt::Key_Up :
- rotate(30);
- break;
- }
- QGraphicsView::keyPressEvent(event);
- }
- void MyView::mousePressEvent(QMouseEvent *event)
- {
- qDebug("************MyView::mousePressEvent*****************");
- QGraphicsView::mousePressEvent(event);
- }
- void MyView::paintEvent(QPaintEvent *event)
- {
- qDebug("************MyView::paintEvent*****************");
- QGraphicsView::paintEvent(event);
- }
- void MyView::mouseMoveEvent(QMouseEvent *event)
- {
- //qDebug("************MyView::mouseMoveEvent*****************");
- QGraphicsView::mouseMoveEvent(event);
- }
3、QGraphicsItem
- #ifndef MYITEM_H
- #define MYITEM_H
- #include <QGraphicsItem>
- #include <QGraphicsSceneEvent>
- class MyItem : public QGraphicsItem
- {
- public:
- MyItem();
- QRectF boundingRect() const;
- void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
- QWidget *widget);
- void setColor(const QColor &color) { brushColor = color; }
- protected:
- void keyPressEvent(QKeyEvent *event);
- void mousePressEvent(QGraphicsSceneMouseEvent *event);
- void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
- void hoverLeaveEvent (QGraphicsSceneHoverEvent * event);
- void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
- void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
- private:
- QColor brushColor;
- };
- #endif // MYITEM_H
- #include "myitem.h"
- #include <QPainter>
- #include <QCursor>
- #include <QKeyEvent>
- #include <QGraphicsSceneHoverEvent>
- #include <QGraphicsSceneContextMenuEvent>
- #include <QMenu>
- MyItem::MyItem()
- {
- brushColor = Qt::red;
- setFlag(QGraphicsItem::ItemIsFocusable);
- setFlag(QGraphicsItem::ItemIsMovable);
- //setAcceptHoverEvents(true);
- }
- QRectF MyItem::boundingRect() const
- {
- qreal adjust = 0.5;
- return QRectF(-10 - adjust, -10 - adjust,
- 20 + adjust, 20 + adjust);
- }
- void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
- QWidget *widget)
- { qDebug("************MyItem::paint*****************");
- if(hasFocus()) {
- painter->setPen(QPen(QColor(255,255,255,200)));
- } else {
- painter->setPen(QPen(QColor(100,100,100,100)));
- }
- painter->setBrush(brushColor);
- painter->drawRect(-10, -10, 20, 20);
- }
- // 鼠标按下事件处理函数,设置被点击的图形项获得焦点,并改变光标外观
- void MyItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
- {
- qDebug("************MyItem::mousePressEvent*****************");
- setFocus();
- setCursor(Qt::ClosedHandCursor);
- }
- // 键盘按下事件处理函数,判断是否是向下方向键,如果是,则向下移动图形项
- void MyItem::keyPressEvent(QKeyEvent *event)
- {
- qDebug("************MyItem::keyPressEvent*****************");
- if(event->key() == Qt::Key_Down)
- moveBy(0, 10);
- }
- // 悬停事件处理函数,设置光标外观和提示
- void MyItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
- {
- qDebug("************MyItem::hoverEnterEvent*****************");
- setCursor(Qt::OpenHandCursor);
- setToolTip("I am item");
- }
- void MyItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
- {
- qDebug("************MyItem::hoverLeaveEvent*****************");
- setCursor(Qt::ArrowCursor);
- }
- // 右键菜单事件处理函数,为图形项添加一个右键菜单
- void MyItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
- {
- QMenu menu;
- QAction *moveAction = menu.addAction("move back");
- QAction *actAction = menu.addAction("test");
- QAction *selectedAction = menu.exec(event->screenPos());
- if(selectedAction == moveAction) {
- setPos(0, 0);
- }
- }
- void MyItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
- {
- qDebug("************MyItem::mouseMoveEvent*****************");
- QGraphicsItem::mouseMoveEvent(event);
- }
4、main及运行
- #include <QApplication>
- #include "myitem.h"
- #include "myview.h"
- #include "myscene.h"
- #include <QTime>
- int main(int argc,char* argv[ ])
- {
- QApplication app(argc,argv);
- qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
- MyScene scene;
- scene.setSceneRect(-200, -150, 400, 300);
- for(int i = 0; i < 5; ++i) {
- MyItem *item = new MyItem;
- item->setColor(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
- item->setPos(i * 50 - 90, -50);
- scene.addItem(item);
- }
- MyView view;
- view.setScene(&scene);
- view.setBackgroundBrush(QPixmap(":/background.png"));
- view.show();
- return app.exec();
- }
分析:keyPressEvent键盘按下事件由View—Scene—Item
分析:mousePressEven鼠标按下事件由View—Scene—Item
分析:事件项Item没有获得焦点时,mousePressEven鼠标按下事件只由View传递到Scene。
分析:事件项Item的悬停事件,在构造函数中设置了setAcceptHoverEvents(true)。
飞舞的蝴蝶(GraphicsView框架)的更多相关文章
- Qt的Graphics-View框架和OpenGL结合详解
Qt的Graphics-View框架和OpenGL结合详解 演示程序下载地址:这里 程序源代码下载地址:这里 这是一篇纯技术文,介绍了这一个月来我抽时间研究的成果. Qt中有一个非常炫的例子:Boxe ...
- Qt浅谈之十八:GraphicsView框架事件处理(有源码下载)
一.简介 GraphicsView支持事件传播体系结构,可以使图元在场景scene中得到提高了已被的精确交互能力.图形视图框架中的事件都是首先由视图进行接收,然后传递给场景,再由场景给相应的图形项. ...
- pyqt5.0 GraphicsView框架
场景(The Scene) QGraphicsScene提供图形视图场景.该场景具有以下职责: 提供用于管理大量图元的快速界面(锅) 将事件传播到每个图元(把螃蟹烧熟了) 管理图元状态,例如选择和焦点 ...
- Android中的动画具体解释系列【2】——飞舞的蝴蝶
这一篇来使用逐帧动画和补间动画来实现一个小样例,首先我们来看看Android中的补间动画. Android中使用Animation代表抽象的动画类,该类包含以下几个子类: AlphaAnimation ...
- Android中的动画详解系列【2】——飞舞的蝴蝶
这一篇来使用逐帧动画和补间动画来实现一个小例子,首先我们来看看Android中的补间动画. Android中使用Animation代表抽象的动画类,该类包括下面几个子类: AlphaAnimation ...
- Qt 动画框架
最近一个项目中的需要做动画效果,很自然就想起来用qt animation framework .这个框架真的很强大.支持多个动画组合,线性动画,并行动画等.在此总结一下使用该框架一些需要注意的地方: ...
- 【转】QT Graphics-View官方介绍(中文翻译)
一.GraphicsView框架简介 QT4.2开始引入了Graphics View框架用来取代QT3中的Canvas模块,并作出了改进,Graphics View框架实现了模型-视图结构的图形管理, ...
- QT Graphics-View 3D编程例子- 3D Model Viewer
学习在Graphics-View框架中使用opengl进行3D编程,在网上找了一个不错的例子“3D Model Viewer”,很值得学习. 可以在http://www.oyonale.com/acc ...
- QT学习笔记4:QT中GraphicsView编程
一.QGraphicsScene 1.QGraphicsScene QGraphicsScene继承自QObject,是一个管理图元的容器,与QGraphicsView合用可以在2D屏幕上显示如线.三 ...
随机推荐
- 【SHOI2008】堵塞的交通
题面 题解 这里提供几种不用脑子的算法(当然是离线的): $\text{LCT}$ 记下每条边的删除时间,用$\text{LCT}$维护最大生成树,每次加进一条边时,跟原来那条链上的做比较,删除那条删 ...
- cf 448c Painting Fence
http://codeforces.com/problemset/problem/448/C 题目大意:给你一个栅栏,每次选一横排或竖排染色,求把全部染色的最少次数,一个点不能重复染色. 和这道题有点 ...
- 【JUC源码解析】ThreadPoolExecutor
简介 ThreadPoolExecutor,线程池的基石. 概述 线程池,除了用HashSet承载一组线程做任务以外,还用BlockingQueue承载一组任务.corePoolSize和maximu ...
- 搜索引擎ElasticSearch系列(四): ElasticSearch2.4.4 sql插件安装
一:ElasticSearch sql插件简介 With this plugin you can query elasticsearch using familiar SQL syntax. You ...
- 世界杯足彩怎么买划算?机器学习AI告诉你答案(含预测)
本文首发于InfoQ公众号头条. 四年一度的世界杯又来了,作为没什么时间看球的码农,跟大家一样,靠买买足彩给自己点看球动力和乐趣, 然而总是买错球队,面对各种赔率也不知道怎么买才划算,足彩是不是碰大运 ...
- request,logging,ConfigParser——接口框架
做一个将参数和用例分开放置,并且输出log的接口测试框架 我的框架如下所示 Log文件用来设置log输出文件,需要时可以在用例内调用输出,config用来填写一切需要的参数信息,jiekou_post ...
- MongoDB开启权限认证
MongoDB默认安装完后,如果在配置文件中没有加上auth = true,是没有用户权限认证的,这样对于一个数据库来说是相对不安全的,尤其是在外网的情况下. 接下来是配置权限的过程: //切入到 ...
- Docker虚拟机172.17网段冲突,导致网络访问问题
在虚拟机中安装docker,linux ubuntu16 ,安装完公司172.17网段被docker0覆盖,导致ssh无法连接到ubuntu. 经过官网的这篇build your own bridge ...
- [python]序列的重复操作符
当你需要需要一个序列的多份拷贝时,重复操作符非常有用,它的语法如下: sequence * copies_int In [1]: a = [1,2,3,4] In [2]: a * 5 Out[2]: ...
- 基于 Agent 的模型入门:Python 实现隔离仿真
2005 年诺贝尔经济学奖得主托马斯·谢林(Thomas Schelling)在上世纪 70 年代就纽约的人种居住分布得出了著名的 Schelling segregation model,这是一个 A ...