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

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

其中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);用于设置小矩形选中状态时的隐藏和显示,实现如下:

CSDN QT大纲:Qt开发必备技术栈学习路线和资料

 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

扫描二维码关注公众号,回复: 14714897 查看本文章
 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 }

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

猜你喜欢

转载自blog.csdn.net/m0_73443478/article/details/128052976#comments_25743881