QGraphicsView 框架学习(一)、图形元素的编辑

代码在 http://download.csdn.net/detail/firebolt2002/8782273


一、给图形对象加控制点,用户通过鼠标来操作控制点来编辑图形,参考MFC drawcli的实现。

很多人通过QGraphicsItem的派生类,然后重载几个函数来处理鼠标消息:

 
 

[cpp]  view plain  copy
  1. void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) Q_DECL_OVERRIDE;  
  2. void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) Q_DECL_OVERRIDE;  
  3. void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) Q_DECL_OVERRIDE;  
  4. void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvet) Q_DECL_OVERRIDE;  
这种在图元对象内部处理鼠标消息的方法我使用过,感觉不太好用,主要是鼠标消息有时候收不到,操作比方麻烦。所以我现在通过派生一个QGraphicsScene对象,重载它的鼠标处理函数来操作图元对象,这样感觉更合理一些。

先来看看控制点对象,我从QtCreator里抄的:

[cpp]  view plain  copy
  1. 下面看看图元对象。  
[cpp]  view plain  copy
  1. //控制手柄的大小  
  2. enum { SELECTION_HANDLE_SIZE = 6, SELECTION_MARGIN = 10 };  
  3. enum SelectionHandleState { SelectionHandleOff, SelectionHandleInactive, SelectionHandleActive };  
  4.   
  5.   
  6. //通过QGraphicsRectItem派生,它本来就是个矩形嘛。  
  7. class SizeHandleRect :public QGraphicsRectItem  
  8. {    //控制点的操作方向。  
  9.     enum Direction { None = -1 , LeftTop , Top, RightTop, Right, RightBottom, Bottom, LeftBottom, Left , Extra };  
  10.     SizeHandleRect(QGraphicsItem* parent , Direction d, QGraphicsItem *resizable);  
  11.     Direction dir() const  { return m_dir; }  
  12.     void updateCursor();  
  13.     void setState(SelectionHandleState st);  
  14.     bool hitTest( const QPointF & point );  
  15.     void move(qreal x, qreal y );  
  16.   
  17. protected:  
  18.     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);  
  19.   
  20. private:  
  21.     const Direction m_dir;  
  22.     QGraphicsItem *m_resizable;  
  23.     SelectionHandleState m_state;  
  24.     QColor borderColor;  
  25. };  
[cpp]  view plain  copy
  1. <pre name="code" class="cpp">//手柄的绘制部分,挺简单,就是画个6x6的小矩形。   
  2. void SizeHandleRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)  
  3. {  
  4.     //不知道为啥,打开反走样后,如果加框,会很难看。  
  5.     painter->setPen(Qt::NoPen);  
  6.     painter->setBrush(QBrush(borderColor));  
  7.   
  8.     if ( m_dir >= Extend )  
  9.     {  
  10.      //   painter->setBrush(QBrush("lightseagreen"));  
  11.      //如果是额外的控制点,就画圈。  
  12.         painter->drawEllipse(rect());  
  13.     }else  
  14.         painter->drawRect(rect());  
  15.   
  16. }  
  17.   
  18. //父对象状态改变,根据状态决定是否可见。  
  19. void SizeHandleRect::setState(SelectionHandleState st)  
  20. {  
  21.     if (st == m_state)  
  22.         return;  
  23.     switch (st) {  
  24.     case SelectionHandleOff:  
  25.         hide();  
  26.         break;  
  27.     case SelectionHandleInactive:  
  28.     case SelectionHandleActive:  
  29.         show();  
  30.         break;  
  31.     }  
  32.     m_state = st;  
  33. }  
  34. //检查是否选中。  
  35. bool SizeHandleRect::hitTest(const QPointF &point)  
  36. {  
  37.     QPointF pt = mapFromScene(point);  
  38.     bool result = rect().contains(pt);  
  39.     return result;  
  40. }  
  41. //移动到指定的位置。  
  42. void SizeHandleRect::move(qreal x, qreal y)  
  43. {  
  44.     setPos(x,y);  
  45. }  
  46.   
  47.   
  48. //使用QGraphicsObject做父类,主要是想利用一下它的元属性,这样可以做一个通用的属性编辑器,后来发现很鸡肋,QPen,QBrush居然不支持,还得自己写,用它就  
  49. 不划算了。  
  50. class GraphicsBasicItem : public QGraphicsObject  
  51. {  
  52.     Q_OBJECT  
  53.     Q_PROPERTY(QColor pen READ penColor WRITE setPen )  
  54.     Q_PROPERTY(QColor brush READ brush WRITE setBrush )  
  55. public:  
  56.     explicit GraphicsBasicItem(QGraphicsItem * parent);  
  57.     explicit GraphicsBasicItem(const QString &name ,QGraphicsItem *parent );  
  58.     virtual ~GraphicsBasicItem();  
  59.     QColor brush() const {return m_brush.color();}  
  60.     QPen   pen() const {return m_pen;}  
  61.     QColor penColor() const {return m_pen.color();}  
  62.     void   setPen(const QPen & pen ) { m_pen = pen;}  
  63.     void   setBrush( const QBrush & brush ) { m_brush = brush ; }  
  64. protected:  
  65.     QBrush m_brush;  
  66.     QPen   m_pen ;  
  67. };  
  68.   
  69. //这个才图元对象。  
  70. class GraphicsItem : public GraphicsBasicItem  
  71. {  
  72.     Q_OBJECT  
  73. public:  
  74.     GraphicsItem(QGraphicsItem * parent );  
  75.     enum {Type = UserType+1};  
  76.     int  type() const { return Type; }  
  77.     //返回选中的控制点  
  78.     virtual SizeHandleRect::Direction  hitTest( const QPointF & point ) const;  
  79.     //根据控制点当前的位置改变对象的大小。  
  80.     virtual void resizeTo(SizeHandleRect::Direction dir, const QPointF & point );  
  81.     //返回控制点的光标<span style="white-space:pre">  </span>  
  82.     virtual Qt::CursorShape getCursor(SizeHandleRect::Direction dir );  
  83.     //返回本地坐标  
  84.     virtual QRectF  rect() const { return m_localRect;}  
  85.     //当释放鼠标完成size操作后,重建本地坐标。   
  86.     virtual void changeSize () {}</span>  
  87.     virtual void move( const QPointF & point ){}  
  88.     int  getHandleCount() const { return m_handles.count();}  
  89. signals:  
  90.     void selectedChange(QGraphicsItem *item);  
  91. protected:  
  92.     virtual void updateGeometry();  
  93.     void setState(SelectionHandleState st);  
  94.     void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);  
  95.     QVariant itemChange(GraphicsItemChange change, const QVariant &value);  
  96.     typedef QVector<SizeHandleRect*> Handles;  
  97.     Handles m_handles;  
  98.     QRectF m_localRect;  
  99. };  

[cpp]  view plain  copy
  1. 创建手柄的过程,和改变手柄状态的方法。  
  2. 创建手柄的过程可以在每个具体对象中实现,比如矩形有8个控制点,线有2个控制点,多边形控制点就是实际的点数。  
[cpp]  view plain  copy
  1. GraphicsRectItem::GraphicsRectItem(const QRect & rect ,QGraphicsItem *parent)  
  2.     :GraphicsItem(parent)  
  3.     ,m_width(rect.width())  
  4.     ,m_height(rect.height())  
  5. {  
  6.   
  7.     // handles  
  8.     m_handles.reserve(SizeHandleRect::None);  
  9.     for (int i = SizeHandleRect::LeftTop; i <= SizeHandleRect::Left; ++i) {  
  10.         SizeHandleRect *shr = new SizeHandleRect(thisstatic_cast<SizeHandleRect::Direction>(i), this);  
  11.         m_handles.push_back(shr);  
  12.     }  
  13.     updateGeometry();  
  14.     setFlag(QGraphicsItem::ItemIsMovable, true);  
  15.     setFlag(QGraphicsItem::ItemIsSelectable, true);  
  16.     setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);  
  17.     //至少需要一个图元对象打开次方法,否则QGraphicsScene不返还鼠标事件.  
  18.     this->setAcceptHoverEvents(true);  
  19. }  
  20. //移动手柄位置。  
  21. void GraphicsItem::updateGeometry()  
  22. {  
  23.     const QRectF &geom = this->boundingRect();  
  24.   
  25.     const int w = SELECTION_HANDLE_SIZE;  
  26.     const int h = SELECTION_HANDLE_SIZE;  
  27.   
  28.     const Handles::iterator hend =  m_handles.end();  
  29.     for (Handles::iterator it = m_handles.begin(); it != hend; ++it) {  
  30.         SizeHandleRect *hndl = *it;;  
  31.         switch (hndl->dir()) {  
  32.         case SizeHandleRect::LeftTop:  
  33.             hndl->move(geom.x() - w / 2, geom.y() - h / 2);  
  34.             break;  
  35.         case SizeHandleRect::Top:  
  36.             hndl->move(geom.x() + geom.width() / 2 - w / 2, geom.y() - h / 2);  
  37.             break;  
  38.         case SizeHandleRect::RightTop:  
  39.             hndl->move(geom.x() + geom.width() - w / 2, geom.y() - h / 2);  
  40.             break;  
  41.         case SizeHandleRect::Right:  
  42.             hndl->move(geom.x() + geom.width() - w / 2, geom.y() + geom.height() / 2 - h / 2);  
  43.             break;  
  44.         case SizeHandleRect::RightBottom:  
  45.             hndl->move(geom.x() + geom.width() - w / 2, geom.y() + geom.height() - h / 2);  
  46.             break;  
  47.         case SizeHandleRect::Bottom:  
  48.             hndl->move(geom.x() + geom.width() / 2 - w / 2, geom.y() + geom.height() - h / 2);  
  49.             break;  
  50.         case SizeHandleRect::LeftBottom:  
  51.             hndl->move(geom.x() - w / 2, geom.y() + geom.height() - h / 2);  
  52.             break;  
  53.         case SizeHandleRect::Left:  
  54.             hndl->move(geom.x() - w / 2, geom.y() + geom.height() / 2 - h / 2);  
  55.             break;  
  56.         default:  
  57.             break;  
  58.         }  
  59.     }  
  60. }  

[cpp]  view plain  copy
  1. 这个类里有两个方法比较重要,一个就是resizeTo,另外一个就是changeSize(),resizeTo就是改变对象的大小,为啥还要有个changeSize方法呢。这个问题后面说。  
  2. 先看看这两个函数的具体实现。  
  3. void GraphicsRectItem::resizeTo(SizeHandleRect::Direction dir, const QPointF &point)  
  4. {  
  5.     // 将场景坐标映射为本地坐标。  
  6.     QPointF local = mapFromParent(point);  
  7.     QString dirName;  
  8.     // 临时对象,记录改变后的大小。  
  9.     QRect delta = this->rect().toRect();  
  10.     switch (dir) {  
  11.     case SizeHandleRect::Right:  
  12.         dirName = "Rigth";  
  13.         delta.setRight(local.x());  
  14.         break;  
  15.     case SizeHandleRect::RightTop:  
  16.         dirName = "RightTop";  
  17.         delta.setTopRight(local.toPoint());  
  18.         break;  
  19.     case SizeHandleRect::RightBottom:  
  20.         dirName = "RightBottom";  
  21.         delta.setBottomRight(local.toPoint());  
  22.         break;  
  23.     case SizeHandleRect::LeftBottom:  
  24.         dirName = "LeftBottom";  
  25.         delta.setBottomLeft(local.toPoint());  
  26.         break;  
  27.     case SizeHandleRect::Bottom:  
  28.         dirName = "Bottom";  
  29.         delta.setBottom(local.y());  
  30.         break;  
  31.     case SizeHandleRect::LeftTop:  
  32.         dirName = "LeftTop";  
  33.         delta.setTopLeft(local.toPoint());  
  34.         break;  
  35.     case SizeHandleRect::Left:  
  36.         dirName = "Left";  
  37.         delta.setLeft(local.x());  
  38.         break;  
  39.     case SizeHandleRect::Top:  
  40.         dirName = "Top";  
  41.         delta.setTop(local.y());  
  42.         break;  
  43.    default:  
  44.         break;  
  45.     }  
  46.     // 改变矩形的大小。  
  47.    prepareGeometryChange();  
  48.   
  49.     m_width = delta.width();    m_height = delta.height();  
  50.     //改变本地坐标系,这里本地坐标系已经被破坏了,如果进行旋转操作等其他变换后,坐标系会出问题。  
  51.     //还需要调用changeSize来重建本地坐标。  
  52.     m_localRect = delta;  
  53.     updateGeometry();  
  54. }  

[cpp]  view plain  copy
  1. 重建本地坐标。  
  2.    为啥要重建本地坐标系呢,前面已经说了,如果改变图元的尺寸,本地坐标系就会跟着改变。本地坐标又是啥样子呢,它是用户自己的坐标系,不管视图坐标,还是场景坐标他们的改变不会影响到本地坐标,通常情况下,我们会将本地坐标定义为原点在中心位置的坐标系,这个坐标比较好操作,也可以定义为原点在左上角位置。如果加入旋转等变换,最好还是把原点放到中心位置。  
  3.    当我们改变对象的大小后,本地坐标原点发生了改变,我们要调整一下坐标,使它的原点重新回到中心位置。  
  4. void GraphicsRectItem::changeSize()  
  5. {  
  6.     QPointF pt1,pt2,delta;  
  7.     //获得当前原点的场景坐标  
  8.     pt1 = mapToScene(transformOriginPoint());  
  9.     //获得改变后坐标系的中心位置,的场景坐标。  
  10.     pt2 = mapToScene(boundingRect().center());  
  11.     //计算位移  
  12.     delta = pt1 - pt2;  
  13.   
  14.     prepareGeometryChange();  
  15.       
  16.     //重建本地坐标系,使原点处于中心位置。  
  17.     m_localRect = QRectF(-m_width/2,-m_height/2,m_width,m_height);  
  18.     //移动图元对象的坐标原点。  
  19.     setTransform(transform().translate(delta.x(),delta.y()));  
  20.     //将当前图形原点移动到新的坐标系中心位置。  
  21.     setTransformOriginPoint(boundingRect().center());  
  22.     //将图形的pos移动到原点上。  
  23.     moveBy(-delta.x(),-delta.y());<span style="font-family: Arial, Helvetica, sans-serif;"> </span>  
  24.    //还原图形坐标原点   
  25.     setTransform(transform().translate(-delta.x(),-delta.y()));  
  26.     qDebug()<<"changeOrigin: "<< delta << mapFromScene( pos()) << mapFromScene(pt2)<<m_localRect;  
  27.   
  28.     updateGeometry();  
  29.   
  30. }  
[cpp]  view plain  copy
  1. 这里多边形重新本地坐标过程有些不一样,需要对每个点的坐标进行重建。  
  2. void GraphicsPolygonItem::changeSize()  
  3. {  
  4.   
  5.     QPointF pt1,pt2,delta;  
  6.     //把原来的点映射到场景坐标  
  7.     QPolygonF pts = mapToScene(m_points);  
  8.     pt1 = mapToScene(transformOriginPoint());  
  9.     pt2 = mapToScene(boundingRect().center());  
  10.     delta = pt1 - pt2;  
  11.     //对每个点进行移动,重建坐标系  
  12.     for (int i = 0; i < pts.count() ; ++i )  
  13.         pts[i]+=delta;  
  14.   
  15.     //还原本地坐标  
  16.     m_points = mapFromScene(pts);  
  17.   
  18.     setTransform(transform().translate(delta.x(),delta.y()));  
  19.     setTransformOriginPoint(boundingRect().center());  
  20.     moveBy(-delta.x(),-delta.y());  
  21.     setTransform(transform().translate(-delta.x(),-delta.y()));  
  22.     prepareGeometryChange();  
  23.   
  24.     qDebug()<<"changeOrigin: "<< delta << mapFromScene( pos()) << transformOriginPoint()<<boundingRect();  
  25.   
  26.     updateGeometry();  
  27.   
  28. }  
  29. //场景类,这里传递鼠标消息给绘图工具。  
  30. class DrawScene : public QGraphicsScene  
  31. {  
  32.     Q_OBJECT  
  33. public:  
  34.     explicit DrawScene(QObject *parent = 0);  
  35.     void setView(QGraphicsView * view ) { m_view = view ; }<pre name="code" class="cpp">class DrawTool  
  36. {  
  37. public:  
  38.     DrawTool( DrawShape shape );  
  39.     virtual void mousePressEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene ) ;  
  40.     virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene ) ;  
  41.     virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene );  
  42.     virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event ,DrawScene *scene );  
  43.     DrawShape m_drawShape;  
  44.     bool m_hoverSizer;  
  45.   
  46.     static DrawTool * findTool( DrawShape drawShape );  
  47.     static QList<DrawTool*> c_tools;  
  48.     static QPointF c_down;  
  49.     static quint32 c_nDownFlags;  
  50.     static QPointF c_last;  
  51.     static DrawShape c_drawShape;  
  52. };  
  53.   
  54. //绘图工具类,参考drawcli  
  55. class SelectTool : public DrawTool  
  56. {  
  57. public:  
  58.     SelectTool();  
  59.     virtual void mousePressEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene ) ;  
  60.     virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene ) ;  
  61.     virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene );  
  62.     QSizeF  m_lastSize;  
  63.     QPointF initialPositions;  
  64.     QGraphicsPathItem * dashRect;  
  65. };  
  66.   
  67. class  RotationTool : public DrawTool  
  68. {  
  69. public:  
  70.     RotationTool();  
  71.     virtual void mousePressEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene ) ;  
  72.     virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene ) ;  
  73.     virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene );  
  74.     qreal lastAngle;  
  75.     QGraphicsPathItem * dashRect;  
  76. };  
  77.   
  78. class RectTool : public DrawTool  
  79. {  
  80. public:  
  81.     RectTool(DrawShape drawShape);  
  82.     virtual void mousePressEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene ) ;  
  83.     virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene ) ;  
  84.     virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene );  
  85.     GraphicsItem * item;  
  86. };  
  87.   
  88. class PolygonTool : public DrawTool  
  89. {  
  90. public:  
  91.     PolygonTool(DrawShape shape );  
  92.     virtual void mousePressEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene ) ;  
  93.     virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene ) ;  
  94.     virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event , DrawScene * scene );  
  95.     virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event ,DrawScene *scene );  
  96.     GraphicsPolygonItem * item;  
  97.     QPointF initialPositions;  
  98.   
  99. };  
[cpp]  view plain  copy
  1. <pre name="code" class="cpp"><pre name="code" class="cpp">class DrawScene : public QGraphicsScene  
  2. {  
  3.     Q_OBJECT  
  4. public:  
  5.     explicit DrawScene(QObject *parent = 0);  
  6.     void setView(QGraphicsView * view ) { m_view = view ; }  
  7.     QGraphicsView * view() { return m_view; };  
  8.     void mouseEvent(QGraphicsSceneMouseEvent *mouseEvent );  
  9.   
  10. signals:  
  11.     void itemSelected(QGraphicsItem *item);  
  12.   
  13. protected:  
  14.     void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) Q_DECL_OVERRIDE;  
  15.     void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) Q_DECL_OVERRIDE;  
  16.     void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) Q_DECL_OVERRIDE;  
  17.     void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvet) Q_DECL_OVERRIDE;  
  18.     QGraphicsView * m_view;  
  19.   
  20. };  
 
 
 
 
 
 
 
 
 
 //场景类的具体实现 
 
 
 
[cpp]  view plain  copy
  1. <pre name="code" class="cpp">DrawScene::DrawScene(QObject *parent)  
  2.     :QGraphicsScene(parent)  
  3. {  
  4.     m_view = NULL;  
  5.   
  6. }  
  7. //有些消息需要继续传递给QGraphicsScene,可以通过这个函数传回来。  
  8. void DrawScene::mouseEvent(QGraphicsSceneMouseEvent *mouseEvent)  
  9. {  
  10.     switch( mouseEvent->type() ){  
  11.     case QEvent::GraphicsSceneMousePress:  
  12.         QGraphicsScene::mousePressEvent(mouseEvent);  
  13.         break;  
  14.     case QEvent::GraphicsSceneMouseMove:  
  15.         QGraphicsScene::mouseMoveEvent(mouseEvent);  
  16.         break;  
  17.     case QEvent::GraphicsSceneMouseRelease:  
  18.         QGraphicsScene::mouseReleaseEvent(mouseEvent);  
  19.         break;  
  20.     }  
  21. }  
  22.   
  23.   
  24. void DrawScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)  
  25. {  
  26.   
  27.     DrawTool * tool = DrawTool::findTool( DrawTool::c_drawShape );  
  28.     if ( tool )  
  29.         tool->mousePressEvent(mouseEvent,this);  
  30. }  
  31.   
  32. void DrawScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)  
  33. {  
  34.     DrawTool * tool = DrawTool::findTool( DrawTool::c_drawShape );  
  35.     if ( tool )  
  36.         tool->mouseMoveEvent(mouseEvent,this);  
  37. }  
  38.   
  39. void DrawScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)  
  40. {  
  41.     DrawTool * tool = DrawTool::findTool( DrawTool::c_drawShape );  
  42.     if ( tool )  
  43.         tool->mouseReleaseEvent(mouseEvent,this);  
  44. }  
  45.   
  46. void DrawScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvet)  
  47. {  
  48.     DrawTool * tool = DrawTool::findTool( DrawTool::c_drawShape );  
  49.     if ( tool )  
  50.         tool->mouseDoubleClickEvent(mouseEvet,this);  
  51.   
  52. }  


 
 //选择工具的具体实现 
 
[cpp]  view plain  copy
  1. <pre name="code" class="cpp">SelectTool::SelectTool()  
  2.     :DrawTool(selection)  
  3. {  
  4.     m_lastSize.setHeight(0);  
  5.     m_lastSize.setWidth(0);  
  6.     dashRect = 0;  
  7. }  
  8.   
  9. void SelectTool::mousePressEvent(QGraphicsSceneMouseEvent *event, DrawScene *scene)  
  10. {  
  11.     DrawTool::mousePressEvent(event,scene);  
  12.   
  13.     QPointF itemPoint;  
  14.   
  15.     if (!m_hoverSizer)  
  16.       scene->mouseEvent(event);  
  17.   
  18.     selectMode = none;  
  19.     QList<QGraphicsItem *> items = scene->selectedItems();  
  20.     GraphicsItem *item = 0;  
  21.   
  22.     if ( items.count() == 1 )  
  23.         item = qgraphicsitem_cast<GraphicsItem*>(items.first());  
  24.   
  25.     if ( item != 0 ){  
  26.   
  27.         nDragHandle = item->hitTest(event->scenePos());  
  28.         if ( nDragHandle !=SizeHandleRect::None)  
  29.              selectMode = size;  
  30.         else  
  31.             selectMode =  move;  
  32.   
  33.         m_lastSize = item->boundingRect().size();  
  34.         itemPoint = item->mapFromScene(c_down);  
  35.   
  36.         setCursor(scene,Qt::ClosedHandCursor);  
  37.   
  38.     }  
  39.   
  40.   
  41.     if( selectMode == none ){  
  42.         selectMode = netSelect;  
  43.         if ( scene->view() ){  
  44.             QGraphicsView * view = scene->view();  
  45.             view->setDragMode(QGraphicsView::RubberBandDrag);  
  46.         }  
  47.   
  48.     }  
  49.   
  50.   
  51.     if ( selectMode == move && items.count() == 1 ){  
  52.   
  53.         if (dashRect ){  
  54.             scene->removeItem(dashRect);  
  55.             delete dashRect;  
  56.             dashRect = 0;  
  57.         }  
  58.   
  59.         dashRect = new QGraphicsPathItem(item->shape());  
  60.         dashRect->setPen(Qt::DashLine);  
  61.         dashRect->setPos(item->pos());  
  62.         dashRect->setTransformOriginPoint(item->transformOriginPoint());  
  63.         dashRect->setTransform(item->transform());  
  64.         dashRect->setRotation(item->rotation());  
  65.         dashRect->setScale(item->scale());  
  66.         initialPositions = dashRect->pos();  
  67.         scene->addItem(dashRect);  
  68.     }  
  69. }  
  70.   
  71. void SelectTool::mouseMoveEvent(QGraphicsSceneMouseEvent *event, DrawScene *scene)  
  72. {  
  73.   
  74.     DrawTool::mouseMoveEvent(event,scene);  
  75.     QList<QGraphicsItem *> items = scene->selectedItems();  
  76.     GraphicsItem * item = 0;  
  77.     if ( items.count() == 1 ){  
  78.         item = qgraphicsitem_cast<GraphicsItem*>(items.first());  
  79.         if ( item != 0 ){  
  80.             if ( nDragHandle != SizeHandleRect::None && selectMode == size ){  
  81.                 QSizeF delta(c_last.x() - c_down.x() , c_last.y() - c_down.y());  
  82.                 item->resizeTo(nDragHandle,c_last);  
  83.             }  
  84.             else if(nDragHandle == SizeHandleRect::None && selectMode == selection ){  
  85.                  SizeHandleRect::Direction handle = item->hitTest(event->scenePos());  
  86.                  if ( handle != SizeHandleRect::None){  
  87.                      setCursor(scene,Qt::OpenHandCursor/*item->getCursor(handle)*/);  
  88.                      m_hoverSizer = true;  
  89.                  }else{  
  90.                      setCursor(scene,Qt::ArrowCursor);  
  91.                      m_hoverSizer = false;  
  92.                  }  
  93.              }  
  94.         }  
  95.     }  
  96.     if ( selectMode == move ){  
  97.         if ( dashRect ){  
  98.             dashRect->setPos(initialPositions + c_last - c_down);  
  99.         }  
  100.     }  
  101.     if ( selectMode != size  && items.count() > 1)  
  102.     {  
  103.         scene->mouseEvent(event);  
  104.   
  105.     }  
  106.   
  107. }  
  108.   
  109. void SelectTool::mouseReleaseEvent(QGraphicsSceneMouseEvent *event, DrawScene *scene)  
  110. {  
  111.     DrawTool::mouseReleaseEvent(event,scene);  
  112.   
  113.     QList<QGraphicsItem *> items = scene->selectedItems();  
  114.     if ( items.count() == 1 ){  
  115.         GraphicsItem * item = qgraphicsitem_cast<GraphicsItem*>(items.first());  
  116.         if ( item != 0  && selectMode == move && c_last != c_down ){  
  117.              item->setPos(initialPositions + c_last - c_down);  
  118.              qDebug()<<"move to :" << item->mapFromScene(item->pos());  
  119.         }else if ( item !=0 && selectMode == size && c_last != c_down ){  
  120.             item->changeSize();  
  121.         }  
  122.     }  
  123.   
  124.     if (selectMode == netSelect ){  
  125.   
  126.         if ( scene->view() ){  
  127.             QGraphicsView * view = scene->view();  
  128.             view->setDragMode(QGraphicsView::NoDrag);  
  129.         }  
  130.     }  
  131.   
  132.     if (dashRect ){  
  133.         scene->removeItem(dashRect);  
  134.         delete dashRect;  
  135.         dashRect = 0;  
  136.     }  
  137.   
  138.     selectMode = none;  
  139.     nDragHandle = SizeHandleRect::None;  
  140.     m_hoverSizer = false;  
  141.     scene->mouseEvent(event);  
  142.   
  143. }  


 
 
 
 //创建矩形工具 
 
[cpp]  view plain  copy
  1. RectTool::RectTool(DrawShape drawShape)  
  2.     :DrawTool(drawShape)  
  3. {  
  4.     item = 0;  
  5. }  
  6.   
  7. void RectTool::mousePressEvent(QGraphicsSceneMouseEvent *event, DrawScene *scene)  
  8. {  
  9.     DrawTool::mousePressEvent(event,scene);  
  10.   
  11.     scene->clearSelection();  
  12.     switch ( c_drawShape ){  
  13.     case rectangle:  
  14.         item = new GraphicsRectItem(QRect(0,0,0,0),NULL);  
  15.         break;  
  16.     case roundrect:  
  17.         item = new GraphicsRoundRectItem(QRect(0,0,0,0),NULL);  
  18.         break;  
  19.     case ellipse:  
  20.         item = new GraphicsEllipseItem(QRect(0,0,0,0),NULL);  
  21.         break;  
  22.     case line:  
  23.         item = new GraphicsLineItem(0);  
  24.         break;  
  25.     case arc:  
  26.         item = new GraphicsArcItem(0);  
  27.         break;  
  28.     }  
  29.     if ( item == 0) return;  
  30.     item->setPos(event->scenePos());  
  31.     scene->addItem(item);  
  32.   
  33.     scene->connect(item, SIGNAL(selectedChange(QGraphicsItem*)),  
  34.             scene, SIGNAL(itemSelected(QGraphicsItem*)));  
  35.   
  36.     item->setSelected(true);  
[cpp]  view plain  copy
  1. //设置当前状态为改变大小  
  2. selectMode = size;  
[cpp]  view plain  copy
  1.     //设置当前控制点为右下角。  
  2.     nDragHandle = SizeHandleRect::RightBottom;  
  3.   
  4. }  
  5.   
  6. void RectTool::mouseMoveEvent(QGraphicsSceneMouseEvent *event, DrawScene *scene)  
  7. {  
  8.     setCursor(scene,Qt::CrossCursor);  
  9.     //传递消息给选择工具  
  10.     selectTool.mouseMoveEvent(event,scene);  
  11. }  
  12.   
  13. void RectTool::mouseReleaseEvent(QGraphicsSceneMouseEvent *event, DrawScene *scene)  
  14. {  
  15.     if ( event->scenePos() == c_down ){  
  16.   
  17.        if ( item != 0){  
  18.          item->setSelected(false);  
  19.          scene->removeItem(item);  
  20.          delete item ;  
  21.          item = 0;  
  22.        }  
  23.        selectTool.mousePressEvent(event,scene);  
  24.        qDebug()<<"RectTool removeItem:";  
  25.     }  
  26.     selectTool.mouseReleaseEvent(event,scene);  
  27.     c_drawShape = selection;  
  28. }  


 
 
 
 
后面还有旋转工具,多边形工具等,就不一一贴代码了。
 
 
 
 
http://blog.csdn.net/firebolt2002/article/details/46583589

猜你喜欢

转载自blog.csdn.net/wishfly/article/details/77817091