zoukankan      html  css  js  c++  java
  • Qt QGraphics 实现可移动缩放的矩形框

    效果展示

    在这里插入图片描述

    QT 实现可移动缩放的矩形框

    完成该功能选择Graphics View Framework这个框架,重写QGraphicsItem、QGraphicsScene、QGraphicsView三个类,然后基本就是完成mousePressEvent、mouseMoveEvent、mouseReleaseEvent这几个事件,再加上坐标位置的变换。
    有一个问题是鼠标在矩形边缘位置拖动缩放时,常见的矩形边缘的特殊点,开始时在Qt的类中查看好像并没有这个功能,参考了其他一些资料,大多实现此功能是人为在边缘特殊点绘制8个小矩形。

    实现缩放时用到的小矩形

    此功能定义为一个类:SizeHandleRect,继承自QGraphicsRectItem
    主要内容为对应位置的记录、鼠标位置的判断、坐标移动、是否选择时的隐藏与显示。
    头文件:sizehandlerect.h

     1 #ifndef SIZEHANDLERECT_H
     2 #define SIZEHANDLERECT_H
     3 
     4 #include <QGraphicsRectItem>
     5 
     6 enum SelectionHandleState { SelectionHandleOff, SelectionHandleInactive, SelectionHandleActive };
     7 
     8 class SizeHandleRect : public QGraphicsRectItem
     9 {
    10 public:
    11     enum Direction { LeftTop , Top, RightTop, Right, RightBottom, Bottom, LeftBottom, Left , Center, None};
    12     SizeHandleRect(QGraphicsItem* parent , QRectF rect, Direction dir);
    13     Direction dir() const;
    14     bool hitTest( const QPointF & point );
    15     void move(qreal x, qreal y );
    16     void setState(SelectionHandleState st);
    17 protected:
    18     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    19 private:
    20     const Direction m_dir;
    21     SelectionHandleState m_state;
    22 };
    23 
    24 #endif // SIZEHANDLERECT_H

    其中Direction为一个枚举类型,用于表示小矩形所代表的位置,边缘特殊点共8个。
    bool hitTest( const QPointF & point );用于判断当前鼠标位置是否在小矩形区域中,实现如下:

    1 bool SizeHandleRect::hitTest(const QPointF &point)
    2 {
    3     QPointF pt = mapFromScene(point);
    4     return rect().contains(pt);
    5 }

    void setState(SelectionHandleState st);用于设置小矩形选中状态时的隐藏和显示,实现如下:

     1 void SizeHandleRect::setState(SelectionHandleState st)
     2 {
     3     if (st == m_state)
     4         return;
     5     switch (st) {
     6     case SelectionHandleOff:
     7         hide();
     8         break;
     9     case SelectionHandleInactive:
    10     case SelectionHandleActive:
    11         show();
    12         break;
    13     }
    14     m_state = st;
    15 }

    实现所要绘制的矩形类

    类名定义为GraphicsRectItem,继承自QGraphicsItem
    主要内容为:
    1、在构造函数中作为父类实例化8个小矩形SizeHandleRect,并将其放在对应的位置。
    2、当大小变化时,重新绘制。
    3、根据不同位置设置鼠标的形状。
    4、管理鼠标位置引起的标志变化。
    5、选择项目变化时的事件处理。
    头文件:graphicsrectitem.h

     1 #ifndef GRAPHICSRECTITEM_H
     2 #define GRAPHICSRECTITEM_H
     3 
     4 #include <QGraphicsItem>
     5 #include "sizehandlerect.h"
     6 
     7 class GraphicsRectItem : public QGraphicsItem
     8 {
     9 public:
    10     GraphicsRectItem(const QRect & rect ,QGraphicsItem * parent);
    11 
    12     QRectF boundingRect() const;
    13     virtual void resizeTo(SizeHandleRect::Direction dir, const QPointF & point );
    14     virtual Qt::CursorShape getCursor(SizeHandleRect::Direction dir );
    15     SizeHandleRect::Direction  hitTest( const QPointF & point ) const;
    16     virtual QRectF  rect() const;
    17 
    18 private:
    19     QRectF m_rect;
    20     typedef QVector<SizeHandleRect*> Handles;
    21     Handles m_handles;
    22     int selection_handle_size = 4;
    23 
    24 protected:
    25     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    26     virtual void updateGeometry();
    27     void setState(SelectionHandleState st);
    28     QVariant itemChange(GraphicsItemChange change, const QVariant &value);
    29 };
    30 
    31 #endif // GRAPHICSRECTITEM_H

    构造函数中绘制8个小矩形,并设置一些标志属性:

     1 GraphicsRectItem::GraphicsRectItem(const QRect &rect, QGraphicsItem *parent) :
     2     QGraphicsItem(parent)
     3 {
     4     m_rect = rect;
     5     m_handles.reserve(SizeHandleRect::None);
     6     for (int i = SizeHandleRect::LeftTop; i <= SizeHandleRect::Left; ++i) {
     7         SizeHandleRect *shr = new SizeHandleRect(this, QRectF(0,0,4,4), static_cast<SizeHandleRect::Direction>(i));
     8         m_handles.push_back(shr);
     9     }
    10     updateGeometry();
    11     setFlag(QGraphicsItem::ItemIsMovable, true);
    12     setFlag(QGraphicsItem::ItemIsSelectable, true);
    13     setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
    14     this->setAcceptHoverEvents(true);
    15 }

    重写QGRAPHICSSCENE类完成主要功能及鼠标事件

    类名定义为GraphicsScene
    主要内容:
    1、完成鼠标三事件,mousePressEvent、mouseMoveEvent、mouseReleaseEvent
    2、创建矩形
    3、添加图像
    头文件:graphicsscene.h

     1 #ifndef GRAPHICSSCENE_H
     2 #define GRAPHICSSCENE_H
     3 
     4 #include <QGraphicsScene>
     5 #include "GraphicsRect/graphicsrectitem.h"
     6 #include <QGraphicsSceneMouseEvent>
     7 
     8 class GraphicsScene : public QGraphicsScene
     9 {
    10     Q_OBJECT
    11 
    12 public:
    13     GraphicsScene();
    14     void creatRect();
    15     void SetBackGroundImage(QPixmap pix, int width, int height);
    16 
    17     GraphicsRectItem *m_RectItem = NULL;
    18 
    19 private:
    20     void setCursor(const QCursor & cursor );
    21 //    void keyPressEvent(QKeyEvent *event);
    22     void mousePressEvent(QGraphicsSceneMouseEvent *event);
    23     void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    24     void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
    25 };
    26 
    27 #endif // GRAPHICSSCENE_H

    下面着重看下鼠标事件:

    1 enum SelectMode
    2 {
    3     none,
    4     netSelect,
    5     move, //移动
    6     size, //改变大小
    7     rotate //反转
    8 };

    用于记录鼠标事件中的不同任务。
    鼠标点击

     1 void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
     2 {
     3     QList<QGraphicsItem *> items = this->selectedItems();
     4     GraphicsRectItem *item = 0;
     5     if ( items.count() == 1 )
     6     {
     7         item = qgraphicsitem_cast<GraphicsRectItem*>(items.first());
     8 
     9         nDragHandle = item->hitTest(event->scenePos());
    10         if ( nDragHandle !=SizeHandleRect::None)
    11             selectMode = size;
    12         else
    13             selectMode =  move;
    14     }
    15     if(selectMode == move || selectMode == none){
    16         QGraphicsScene::mousePressEvent(event);
    17     }
    18 }

    判断鼠标位置,确定操作类型:缩放-size,移动-move,无操作-none
    鼠标移动:

     1 void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
     2 {
     3     QList<QGraphicsItem *> items = this->selectedItems();
     4     if(items.count() == 1){
     5         GraphicsRectItem *item = qgraphicsitem_cast<GraphicsRectItem*>(items.first());
     6         if ( nDragHandle != SizeHandleRect::None && selectMode == size ){
     7             item->resizeTo(nDragHandle,event->scenePos());
     8         }
     9         else if(nDragHandle == SizeHandleRect::None && selectMode == none ){
    10 
    11 
    12             SizeHandleRect::Direction handle = item->hitTest(event->scenePos());
    13             if ( handle != SizeHandleRect::None){
    14                 setCursor(item->getCursor(handle));
    15             }else{
    16                 setCursor(Qt::ArrowCursor);
    17             }
    18         }
    19         else if(nDragHandle == SizeHandleRect::None && selectMode == move ){
    20             QGraphicsScene::mouseMoveEvent(event);
    21         }
    22     }
    23 
    24     this->update();
    25 }

    鼠标释放:

    1 void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
    2 {
    3     setCursor(Qt::ArrowCursor);
    4     selectMode = none;
    5     nDragHandle = SizeHandleRect::None;
    6     QGraphicsScene::mouseReleaseEvent(event);
    7 }

    重写QGRAPHICSVIEW

    类名定义为GraphicsView
    小知识点:重写控件类,可以在Qt ui中拖入一个控件,右键“提升”为重写的控件类。
    重写此类对于要完成的功能没什么作用,添加上示范一下鼠标滚轮放大,键盘等效果。
    头文件:graphicsview.h

     1 #ifndef GRAPHICSVIEW_H
     2 #define GRAPHICSVIEW_H
     3 
     4 #include <QGraphicsView>
     5 #include <QKeyEvent>
     6 #include <QWheelEvent>
     7 
     8 class GraphicsView : public QGraphicsView
     9 {
    10     Q_OBJECT
    11 
    12 public:
    13     GraphicsView(QWidget *parent = 0);
    14 
    15 protected:
    16     void keyPressEvent(QKeyEvent *event);
    17     void wheelEvent(QWheelEvent *event);
    18 };
    19 
    20 #endif // GRAPHICSVIEW_H

    比如鼠标滚轮事件:

    1 void GraphicsView::wheelEvent(QWheelEvent *event)
    2 {
    3     // 滚轮的滚动量
    4     QPoint scrollAmount = event->angleDelta();
    5     // 正值表示滚轮远离使用者(放大),负值表示朝向使用者(缩小)
    6     scrollAmount.y() > 0 ? scale(1.2, 1.2) : scale(1 / 1.2, 1 / 1.2);
    7 }

     

  • 相关阅读:
    GO 语言使用copy 拷贝切片的问题
    ggplot 局部放大
    R语言hist重叠图作法
    illumina SNP 芯片转基因型矩阵
    Shell 变量嵌套
    JVM指令
    VUE—CLI学习
    Gradle 项目打开自动下载Zip问题及相关配置
    MySQL8服务无法启动,服务没有报告任何错误
    SpringMVC相关
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/13862254.html
Copyright © 2011-2022 走看看