zoukankan      html  css  js  c++  java
  • 飞舞的蝴蝶(GraphicsView框架)

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

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

    (2)来回移动的星星

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

    分析:利用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.   
    4. #include <QGraphicsScene>  
    5. #include <QGraphicsSceneMouseEvent>  
    6. #include <QPaintEvent>  
    7. #include <QKeyEvent>  
    8.   
    9. class MyScene : public QGraphicsScene  
    10. {  
    11.     Q_OBJECT  
    12. public:  
    13.     explicit MyScene(QObject *parent = 0);  
    14.   
    15. protected:  
    16.     void keyPressEvent(QKeyEvent *event);  
    17.     void mousePressEvent(QGraphicsSceneMouseEvent *event);  
    18.   
    19. signals:  
    20.   
    21. public slots:  
    22.   
    23. };  
    24.   
    25. #endif // MYSCENE_H  
     
    1. #include "myscene.h"  
    2.   
    3. MyScene::MyScene(QObject *parent) :  
    4.     QGraphicsScene(parent)  
    5. {  
    6.     clearFocus();  
    7. }  
    8.   
    9. void MyScene::keyPressEvent(QKeyEvent *event)  
    10. {  
    11.     qDebug("*********MyScene::keyPressEvent***************");  
    12.     return QGraphicsScene::keyPressEvent(event);  
    13. }  
    14.   
    15. void MyScene::mousePressEvent(QGraphicsSceneMouseEvent *event)  
    16. {  
    17.     qDebug("*********MyScene::mousePressEvent***************");  
    18.     QGraphicsScene::mousePressEvent(event);  
    19. }  

    2、QGraphicsView

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

    3、QGraphicsItem

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

    4、main及运行

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


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


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

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

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

  • 相关阅读:
    python学习-33 max和min函数的高级使用
    XML--XSL
    XML--XML概览
    Linux|Zookeeper--CentOS7开机启动Zookeeper
    VMWare WorkStation15--Win10下开机启动虚拟机
    Zookeeper--命令介绍
    Zookeeper--复制模式安装
    Zookeeper--Zookeeper单机安装
    soupui--替换整个case的url
    Git--cherry-pick
  • 原文地址:https://www.cnblogs.com/lsgxeva/p/7823055.html
Copyright © 2011-2022 走看看