飞舞的蝴蝶(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)。

最新文章

  1. c++顺序表基本功能
  2. Matlab 2013b 在El Capitan 中无法使用问题解决
  3. 如何在UIimageview里显示一张图片里的某一部分
  4. 有效的PhoneGap CSS: WebKit Tap Highlight Color
  5. 在 C++ 代码中使用 UE4 插件---Using a plugin in C++ code
  6. Android 开关按钮切换,类似于iphone 效果,view实现
  7. Git学习记录
  8. Raft
  9. jquery easyui datebox 时间控件默认显示当前日期的实现方法
  10. Call to undefined function bcscale()
  11. duilib combo控件,当鼠标滚动时下拉列表自动关闭的bug的修复
  12. [转] 关于c++的头文件依赖
  13. 最受欢迎的Web开发工具
  14. 2017-11-22 Intall Ubuntu Log
  15. 输入和输出--RandomAccessFile类
  16. Asp.Net Core MailKit 完美附件(中文名、长文件名)
  17. react native 项目版本升级
  18. Codeforces963C Cutting Rectangle 【数学】
  19. C# WinForm窗体隐藏右上角最小化、最大化、关闭按钮
  20. 【做题】agc008f - Black Radius——计数&amp;讨论&amp;思维

热门文章

  1. Spark 序列化问题
  2. 两个字段联合约束(mysql)
  3. ython进阶06 循环对象
  4. 关于kv的jch分片存储
  5. ShipStation Now Uses AWS And Amazon Fulfillment To Automatically Ship From eBay, Sears And Other Marketplaces
  6. Beta版软件使用说明
  7. 404 Note Found -(课堂实战)- 项目UML设计(团队)
  8. Nginx 配置站点
  9. 中国剩余定理---FZU 1402 猪的安家
  10. 安装libvirt管理套件(C/S架构模式,用户管理kvm虚拟机)