飞舞的蝴蝶(GraphicsView框架)

一、简介

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

二、关系图

(1)三者间的关系

(2)坐标系统

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

(3)坐标映射

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

三、详解

1、运行图

2、解析

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

  1. #include <QGraphicsItem>
  2. #include <QObject>
  3. class Butterfly : public QObject, public QGraphicsItem
  4. {
  5. Q_OBJECT
  6. public:
  7. Butterfly();
  8. void timerEvent(QTimerEvent *);
  9. QRectF boundingRect() const;
  10. protected:
  11. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
  12. private:
  13. bool up;
  14. QPixmap pix_up;
  15. QPixmap pix_down;
  16. qreal angle;
  17. };
  1. static const double PI = 3.14159265358979323846264338327950288419717;
  2. Butterfly::Butterfly()
  3. {
  4. setFlag(QGraphicsItem::ItemIsMovable);
  5. pix_up.load(":/images/butterfly1.PNG");
  6. pix_down.load(":/images/butterfly2.PNG");
  7. up = true;
  8. startTimer(100);
  9. }
  10. QRectF Butterfly::boundingRect() const
  11. {
  12. qreal adjust = 8;
  13. return QRectF(-pix_up.width()/2-adjust,-pix_up.height()/2-adjust,
  14. pix_up.width()+adjust*2,pix_up.height()+2*adjust);
  15. }
  16. void Butterfly::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  17. {
  18. if(up)
  19. {
  20. painter->drawPixmap(boundingRect().topLeft(),pix_up);
  21. up = !up;
  22. }
  23. else
  24. {
  25. painter->drawPixmap(boundingRect().topLeft(),pix_down);
  26. up = !up;
  27. }
  28. //    painter->setPen(Qt::NoPen);
  29. //    painter->setBrush(Qt::darkGray);
  30. //    painter->drawEllipse(-7,-7,40,40);
  31. //    painter->setPen(QPen(Qt::black,0));
  32. //    painter->setBrush(flash ? (Qt::red):(Qt::yellow));
  33. //    painter->drawEllipse(-10,-10,40,40);
  34. }
  35. void Butterfly::timerEvent(QTimerEvent *)
  36. {
  37. // edge controll
  38. qreal edgex = scene()->sceneRect().right()+boundingRect().width()/2;
  39. qreal edgetop = scene()->sceneRect().top()+boundingRect().height()/2;
  40. qreal edgebottom = scene()->sceneRect().bottom()+boundingRect().height()/2;
  41. //qDebug() << scene()->itemsBoundingRect();
  42. if (pos().x() >= edgex)
  43. setPos(scene()->sceneRect().left(),pos().y());
  44. if (pos().y() <= edgetop)
  45. setPos(pos().x(),scene()->sceneRect().bottom());
  46. if (pos().y() >= edgebottom)
  47. setPos(pos().x(),scene()->sceneRect().top());
  48. angle += (qrand()%10)/20.0;
  49. qreal dx = fabs(sin(angle*PI)*10.0);
  50. qreal dy = (qrand()%20)-10.0;
  51. setPos(mapToParent(dx,dy));
  52. update();
  53. }

分析:在定时器的timeEvent()中对QGraphicsItem进行重画,重画paint()函数中飞舞的蝴蝶是由两幅图片组成,蝴蝶的移动边界做一个限定,dx和dy是相对于蝴蝶的坐标系而言的,调用setPos函数时使用mapToParent()函数映射成场景的坐标。setFlag(QGraphicsItem::ItemIsMovable);使蝴蝶可以通过鼠标移动。

(2)来回移动的星星

  1. class StarItem : public QGraphicsItem
  2. {
  3. public:
  4. StarItem();
  5. QRectF boundingRect() const;
  6. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
  7. private:
  8. QPixmap pix;
  9. };
  1. StarItem::StarItem()
  2. {
  3. pix.load(":/images/star.png");
  4. }
  5. QRectF StarItem::boundingRect() const
  6. {
  7. return QRectF(-pix.width()/2,-pix.height()/2,pix.width(),pix.height());
  8. }
  9. void
  10. StarItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  11. {
  12. painter->drawPixmap(boundingRect().topLeft(),pix);
  13. }
  1. {
  2. StarItem *star = new StarItem;
  3. QGraphicsItemAnimation *anim = new QGraphicsItemAnimation;
  4. anim->setItem(star);
  5. QTimeLine *timeLine = new QTimeLine(4000);
  6. timeLine->setCurveShape(QTimeLine::SineCurve);
  7. timeLine->setLoopCount(0);
  8. anim->setTimeLine(timeLine);
  9. int y = (qrand()%400) - 200;
  10. for (int i=0; i<400; i++)
  11. {
  12. anim->setPosAt(i/400.0, QPointF(i-200,y));
  13. }
  14. timeLine->start();
  15. scene->addItem(star);
  16. }

分析:利用QGraphicsItemAnimation类和QTimeLine实现项目的动画效果(也可使用定时器QTimer结合重绘函数来实现)。

(3)简单正方形

  1. {
  2. QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0,0,60,60));
  3. QPen pen;
  4. pen.setWidth(3);
  5. pen.setColor(QColor(qrand()%256,qrand()%256,qrand()%256));
  6. item->setPen(pen);
  7. item->setBrush(QColor(qrand()%256,qrand()%256,qrand()%256));
  8. item->setFlag(QGraphicsItem::ItemIsMovable);
  9. scene->addItem(item);
  10. //item->setPos((qrand()%int(scene->sceneRect().width()))-200,(qrand()%int(scene->sceneRect().height()))-200);
  11. item->setPos(-200, -200);
  12. }

分析:利用继承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

  1. #ifndef MYSCENE_H
  2. #define MYSCENE_H
  3. #include <QGraphicsScene>
  4. #include <QGraphicsSceneMouseEvent>
  5. #include <QPaintEvent>
  6. #include <QKeyEvent>
  7. class MyScene : public QGraphicsScene
  8. {
  9. Q_OBJECT
  10. public:
  11. explicit MyScene(QObject *parent = 0);
  12. protected:
  13. void keyPressEvent(QKeyEvent *event);
  14. void mousePressEvent(QGraphicsSceneMouseEvent *event);
  15. signals:
  16. public slots:
  17. };
  18. #endif // MYSCENE_H
  1. #include "myscene.h"
  2. MyScene::MyScene(QObject *parent) :
  3. QGraphicsScene(parent)
  4. {
  5. clearFocus();
  6. }
  7. void MyScene::keyPressEvent(QKeyEvent *event)
  8. {
  9. qDebug("*********MyScene::keyPressEvent***************");
  10. return QGraphicsScene::keyPressEvent(event);
  11. }
  12. void MyScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
  13. {
  14. qDebug("*********MyScene::mousePressEvent***************");
  15. QGraphicsScene::mousePressEvent(event);
  16. }

2、QGraphicsView

  1. #ifndef MYVIEW_H
  2. #define MYVIEW_H
  3. #include <QGraphicsView>
  4. class MyView : public QGraphicsView
  5. {
  6. Q_OBJECT
  7. public:
  8. explicit MyView(QWidget *parent = 0);
  9. protected:
  10. void keyPressEvent(QKeyEvent *event);
  11. void mousePressEvent(QMouseEvent *event);
  12. void paintEvent(QPaintEvent * event);
  13. void mouseMoveEvent(QMouseEvent *event);
  14. signals:
  15. public slots:
  16. };
  17. #endif // MYVIEW_H
  1. #include "myview.h"
  2. #include <QKeyEvent>
  3. MyView::MyView(QWidget *parent) :
  4. QGraphicsView(parent)
  5. {
  6. }
  7. void MyView::keyPressEvent(QKeyEvent *event)
  8. {
  9. qDebug("*********MyView::keyPressEvent***************");
  10. switch (event->key())
  11. {
  12. case Qt::Key_Left :
  13. scale(1.2, 1.2);
  14. break;
  15. case Qt::Key_Right :
  16. scale(1 / 1.2, 1 / 1.2);
  17. break;
  18. case Qt::Key_Up :
  19. rotate(30);
  20. break;
  21. }
  22. QGraphicsView::keyPressEvent(event);
  23. }
  24. void MyView::mousePressEvent(QMouseEvent *event)
  25. {
  26. qDebug("************MyView::mousePressEvent*****************");
  27. QGraphicsView::mousePressEvent(event);
  28. }
  29. void MyView::paintEvent(QPaintEvent *event)
  30. {
  31. qDebug("************MyView::paintEvent*****************");
  32. QGraphicsView::paintEvent(event);
  33. }
  34. void MyView::mouseMoveEvent(QMouseEvent *event)
  35. {
  36. //qDebug("************MyView::mouseMoveEvent*****************");
  37. QGraphicsView::mouseMoveEvent(event);
  38. }

3、QGraphicsItem

  1. #ifndef MYITEM_H
  2. #define MYITEM_H
  3. #include <QGraphicsItem>
  4. #include <QGraphicsSceneEvent>
  5. class MyItem : public QGraphicsItem
  6. {
  7. public:
  8. MyItem();
  9. QRectF boundingRect() const;
  10. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
  11. QWidget *widget);
  12. void setColor(const QColor &color) { brushColor = color; }
  13. protected:
  14. void keyPressEvent(QKeyEvent *event);
  15. void mousePressEvent(QGraphicsSceneMouseEvent *event);
  16. void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
  17. void hoverLeaveEvent (QGraphicsSceneHoverEvent * event);
  18. void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
  19. void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
  20. private:
  21. QColor brushColor;
  22. };
  23. #endif // MYITEM_H
  1. #include "myitem.h"
  2. #include <QPainter>
  3. #include <QCursor>
  4. #include <QKeyEvent>
  5. #include <QGraphicsSceneHoverEvent>
  6. #include <QGraphicsSceneContextMenuEvent>
  7. #include <QMenu>
  8. MyItem::MyItem()
  9. {
  10. brushColor = Qt::red;
  11. setFlag(QGraphicsItem::ItemIsFocusable);
  12. setFlag(QGraphicsItem::ItemIsMovable);
  13. //setAcceptHoverEvents(true);
  14. }
  15. QRectF MyItem::boundingRect() const
  16. {
  17. qreal adjust = 0.5;
  18. return QRectF(-10 - adjust, -10 - adjust,
  19. 20 + adjust, 20 + adjust);
  20. }
  21. void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
  22. QWidget *widget)
  23. {   qDebug("************MyItem::paint*****************");
  24. if(hasFocus()) {
  25. painter->setPen(QPen(QColor(255,255,255,200)));
  26. } else {
  27. painter->setPen(QPen(QColor(100,100,100,100)));
  28. }
  29. painter->setBrush(brushColor);
  30. painter->drawRect(-10, -10, 20, 20);
  31. }
  32. // 鼠标按下事件处理函数,设置被点击的图形项获得焦点,并改变光标外观
  33. void MyItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
  34. {
  35. qDebug("************MyItem::mousePressEvent*****************");
  36. setFocus();
  37. setCursor(Qt::ClosedHandCursor);
  38. }
  39. // 键盘按下事件处理函数,判断是否是向下方向键,如果是,则向下移动图形项
  40. void MyItem::keyPressEvent(QKeyEvent *event)
  41. {
  42. qDebug("************MyItem::keyPressEvent*****************");
  43. if(event->key() == Qt::Key_Down)
  44. moveBy(0, 10);
  45. }
  46. // 悬停事件处理函数,设置光标外观和提示
  47. void MyItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
  48. {
  49. qDebug("************MyItem::hoverEnterEvent*****************");
  50. setCursor(Qt::OpenHandCursor);
  51. setToolTip("I am item");
  52. }
  53. void MyItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
  54. {
  55. qDebug("************MyItem::hoverLeaveEvent*****************");
  56. setCursor(Qt::ArrowCursor);
  57. }
  58. // 右键菜单事件处理函数,为图形项添加一个右键菜单
  59. void MyItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
  60. {
  61. QMenu menu;
  62. QAction *moveAction = menu.addAction("move back");
  63. QAction *actAction = menu.addAction("test");
  64. QAction *selectedAction = menu.exec(event->screenPos());
  65. if(selectedAction == moveAction) {
  66. setPos(0, 0);
  67. }
  68. }
  69. void MyItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
  70. {
  71. qDebug("************MyItem::mouseMoveEvent*****************");
  72. QGraphicsItem::mouseMoveEvent(event);
  73. }

4、main及运行

  1. #include <QApplication>
  2. #include "myitem.h"
  3. #include "myview.h"
  4. #include "myscene.h"
  5. #include <QTime>
  6. int main(int argc,char* argv[ ])
  7. {
  8. QApplication app(argc,argv);
  9. qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
  10. MyScene scene;
  11. scene.setSceneRect(-200, -150, 400, 300);
  12. for(int i = 0; i < 5; ++i) {
  13. MyItem *item = new MyItem;
  14. item->setColor(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
  15. item->setPos(i * 50 - 90, -50);
  16. scene.addItem(item);
  17. }
  18. MyView view;
  19. view.setScene(&scene);
  20. view.setBackgroundBrush(QPixmap(":/background.png"));
  21. view.show();
  22. return app.exec();
  23. }


分析:keyPressEvent键盘按下事件由View—Scene—Item


分析:mousePressEven鼠标按下事件由View—Scene—Item

分析:事件项Item没有获得焦点时,mousePressEven鼠标按下事件只由View传递到Scene。

分析:事件项Item的悬停事件,在构造函数中设置了setAcceptHoverEvents(true)。

飞舞的蝴蝶(GraphicsView框架)的更多相关文章

  1. Qt的Graphics-View框架和OpenGL结合详解

    Qt的Graphics-View框架和OpenGL结合详解 演示程序下载地址:这里 程序源代码下载地址:这里 这是一篇纯技术文,介绍了这一个月来我抽时间研究的成果. Qt中有一个非常炫的例子:Boxe ...

  2. Qt浅谈之十八:GraphicsView框架事件处理(有源码下载)

    一.简介 GraphicsView支持事件传播体系结构,可以使图元在场景scene中得到提高了已被的精确交互能力.图形视图框架中的事件都是首先由视图进行接收,然后传递给场景,再由场景给相应的图形项. ...

  3. pyqt5.0 GraphicsView框架

    场景(The Scene) QGraphicsScene提供图形视图场景.该场景具有以下职责: 提供用于管理大量图元的快速界面(锅) 将事件传播到每个图元(把螃蟹烧熟了) 管理图元状态,例如选择和焦点 ...

  4. Android中的动画具体解释系列【2】——飞舞的蝴蝶

    这一篇来使用逐帧动画和补间动画来实现一个小样例,首先我们来看看Android中的补间动画. Android中使用Animation代表抽象的动画类,该类包含以下几个子类: AlphaAnimation ...

  5. Android中的动画详解系列【2】——飞舞的蝴蝶

    这一篇来使用逐帧动画和补间动画来实现一个小例子,首先我们来看看Android中的补间动画. Android中使用Animation代表抽象的动画类,该类包括下面几个子类: AlphaAnimation ...

  6. Qt 动画框架

    最近一个项目中的需要做动画效果,很自然就想起来用qt animation framework .这个框架真的很强大.支持多个动画组合,线性动画,并行动画等.在此总结一下使用该框架一些需要注意的地方: ...

  7. 【转】QT Graphics-View官方介绍(中文翻译)

    一.GraphicsView框架简介 QT4.2开始引入了Graphics View框架用来取代QT3中的Canvas模块,并作出了改进,Graphics View框架实现了模型-视图结构的图形管理, ...

  8. QT Graphics-View 3D编程例子- 3D Model Viewer

    学习在Graphics-View框架中使用opengl进行3D编程,在网上找了一个不错的例子“3D Model Viewer”,很值得学习. 可以在http://www.oyonale.com/acc ...

  9. QT学习笔记4:QT中GraphicsView编程

    一.QGraphicsScene 1.QGraphicsScene QGraphicsScene继承自QObject,是一个管理图元的容器,与QGraphicsView合用可以在2D屏幕上显示如线.三 ...

随机推荐

  1. 向日期添加指定的时间间隔(mysql)

    DATE_ADD( 原始日期, INTERVAL 要加的年数 YEAR) DATE_ADD( 原始日期, INTERVAL 要加的月份 MONTH) DATE_ADD( 原始日期, INTERVAL ...

  2. Oracle dba权限下修改用户密码 授予用户权限 解锁用户

    1.修改用户密码 alter user scott identified by 123 2.授予用户权限 grant connect,resource to scott 3.解锁用户 alter us ...

  3. artDialog基本使用

    artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口l  自适应内容artDialog的特殊UI框架能够适应内容变化,甚至连外部程序动态插入的内容它仍然能自适 ...

  4. Python数据结构 将列表作为栈和队列使用

    列表作为栈使用 Python列表方法使得列表作为堆栈非常容易,最后一个插入,最先取出(“后进先出”).要添加一个元素到堆栈的顶端,使用 append() .要从堆栈顶部取出一个元素,使用 pop()  ...

  5. 【java请求】- jmeter_jdbc脚本实战

    一,导入 使用Jmeter运行Java脚本,需要用到Jmeter的提供的框架jar包(分别在jmeter目录下的lib和ext目录下)1.ApacheJMeter_core.jar2.ApacheJM ...

  6. javascript 强制转换规则 boolean 布尔值类型

    摘自 <你不知道的Javascript(中卷)> p55 一句话简述, 假值表以外的值均可以认为是真值,部分浏览器可能自定义了假值表以外的假值,并不符合W3C规范,需要特殊对待. 首先也是 ...

  7. 多主机Docker容器的VLAN划分

    原文发表于cu:2016-06-06 参考文档: Docker网络的4种模式,pipework/ovs的简单使用等:http://www.infoq.com/cn/articles/docker-ne ...

  8. js页面跳转,url带url参数解决方案

    今天,在做一个项目的时候,向后端发送了一个Ajax请求,后端返回了一个字符串,告诉我未登录.那么我需要跳转到登录页面,同时告诉登录页面,登录成功后,需要跳回的url.也就是标题所说,url中的一个参数 ...

  9. Python模块random使用详情

    python常用模块目录 1.random.random()#用于生成一个0到1的随机浮点数:0<= n < 1.0 import random mcw = random.random() ...

  10. 微信小程序---scroll-view在苹果手机上触底或触顶页面闪动问题

    在项目开发中遇到一个关于scroll-view的的问题,具体如下: 项目要求是横向滚动,由于直接在scroll-view组件设置display:flex不生效,因此考虑直接在scroll-view下增 ...