飞舞的蝴蝶(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. 电信NB-IOT的温湿度采集器开发记录

    1. 首先打开浏览器,登录电信商用服务器,上传profile文件 2. 上传编解码插件在,注意的是,上传编解码插件是电信测试用服务器平台(不同的网址),反正不明白电信搞啥幺蛾子,得两个地方去上传 3. ...

  2. DSP5509项目之用FFT识别钢琴音调(4)之麦克风输入和Line in输入

    1. 麦克风输入需要修改的内容,之前的版本是LINE IN的输入.实现功能,检测麦克风的输入,并且同时在耳机里面播放. #include <csl.h> #include <csl_ ...

  3. IBM X3650M4简单排错方法

    如果出问题了,首先看开机的那个地方的灯是否显示正常,有黄色的灯亮一般都不正常: 这种服务器带有一个错误指示板,只需要在电源开关那,如上图,把那个蓝色的按钮往里面按,就能把里面的一个板子抽出来,可以看到 ...

  4. linux信号处理相关知识

      因为要处理最近项目中碰上的多个子进程退出信号同时到达,导致程序不当产生core的情况,今天我花了时间看了一些关于linux信号处理的博客. 总结一下:(知识未经实践) linux信号分两种,一种实 ...

  5. Python接口测试实战1(下)- 接口测试工具的使用

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  6. 接口测试工具Postman接口测试图文教程

    Postman接口测试工具使用 一.前言     在前后端分离开发时,后端工作人员完成系统接口开发后,需要与前端人员对接,测试调试接口,验证接口的正确性可用性.而这要求前端开发进度和后端进度保持基本一 ...

  7. JavaScript学习笔记(三)——对象

    第四章 理解对象 1 说明 对象的状态:属性,行为:方法: 对象定义放在花括号内: 用冒号分隔属性名和属性值: 用逗号分隔属性名和属性值对,包括方法: 最后一个属性值后面不加逗号: 属性名可以是任何字 ...

  8. ShipStation Now Uses AWS And Amazon Fulfillment To Automatically Ship From eBay, Sears And Other Marketplaces

    ShipStation today unveiled a first-of-its-kind service to leverage Amazon Web Services and Amazon.co ...

  9. Android 对话框(Dialogs)

    对话框是提示用户作出决定或输入额外信息的小窗口. 对话框不会填充屏幕,通常用于需要用户采取行动才能继续执行的模式事件. 1.对话框设计 如需了解有关如何设计对话框的信息(包括语言建议),请阅读对话框设 ...

  10. Linux中打开文件管理器的命令

    在Mac中,我们可以使用open命令,在终端打开指定目录下的文件管理器,在Linux中,同样可以使用类似的命令:nautilus.