Qt QGraphicsScene管理QGraphicsItem(单击/选择/移动/缩放/删除)

在图形视图框架中,QGraphicsScene 提供一个快速的接口,用于管理大量 item,QGraphicsItem 是场景中 item 的基类。

图形视图提供了一些典型形状的标准 item,当然,我们也可以自定义 item。除此之外,QGraphicsItem 还支持以下特性:

  • 鼠标按下、移动、释放和双击事件,以及鼠标悬浮事件、滚轮事件和上下文菜单事件
  • 键盘输入焦点和键盘事件
  • 拖放
  • 分组:通过父子关系,或 QGraphicsItemGroup
  • 碰撞检测

下面,一起来看看 QGraphicsScene 对 QGraphicsItem 的管理,主要包括:单击、选择、移动、缩放、删除等。

为了实现以上功能,我们主要实现了 QGraphicsScene 和 QGraphicsItem 对应的事件,通过鼠标和键盘来操作。

操作细节主要包括:

  • 选择:点击左键、按 Shift 键可以单选,按下 Ctrl 可进行多选。
  • 添加:点击左键
  • 删除:点击右键,删除鼠标下的 item;当按下 Ctrl 选择多个 items 时,按下 Backspace 键,将选中的全部删除。
  • 移动:点击左键,选择 item,然后移动鼠标;当按下 Ctrl 选择多个 items 时,可以移动选中的 items。
  • 缩放:按 Alt 键,然后鼠标拖拽 item 的边界。

在对应操作的事件中,我们输出了一些调试信息,以便跟踪。

这里写图片描述

源码

custom_item.h:

 1 #ifndef CUSTOM_ITEM_H
 2 #define CUSTOM_ITEM_H
 3 
 4 #include <QGraphicsRectItem>
 5 #include <QGraphicsScene>
 6 
 7 //QGraphicsScene管理QGraphicsItem(单击/选择/移动/缩放/删除)
 8 // 自定义 Item
 9 class CustomItem : public QGraphicsRectItem
10 {
11 public:
12     explicit CustomItem(QGraphicsItem *parent = 0);
13 protected:
14     // Shift+左键:进行选择  Alt:准备缩放
15     void mousePressEvent(QGraphicsSceneMouseEvent *event);
16     // Alt+拖拽:进行缩放  移动
17     void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
18     void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
19     // 使item可使用qgraphicsitem_cast
20     int type() const;
21 private:
22     QPointF m_centerPointF;
23     bool m_bResizing;
24 };
25 
26 // 自定义 Scene
27 class CustomScene : public QGraphicsScene
28 {
29 protected:
30     // 左键:添加item  右键:移除item
31     void mousePressEvent(QGraphicsSceneMouseEvent *event);
32     void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
33     // Backspace键移除item
34     void keyPressEvent(QKeyEvent *event);
35 };
36 
37 #endif // CUSTOM_ITEM_H

custom_item.cpp:

  1 #include <QKeyEvent>
  2 #include <QGraphicsSceneMouseEvent>
  3 #include <QDebug>
  4 #include "custom_item.h"
  5 
  6 // 自定义 Item
  7 CustomItem::CustomItem(QGraphicsItem *parent)
  8     : QGraphicsRectItem(parent)
  9 {
 10     // 画笔 - 边框色
 11     QPen p = pen();
 12     p.setWidth(2);
 13     p.setColor(QColor(0, 160, 230));
 14 
 15     setPen(p);
 16     // 画刷 - 背景色
 17     setBrush(QColor(247, 160, 57));
 18 
 19     // 可选择、可移动
 20     setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
 21 }
 22 
 23 void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
 24 {
 25     if (event->button() == Qt::LeftButton) {
 26         if (event->modifiers() == Qt::ShiftModifier) {
 27             qDebug() << "Custom item left clicked with shift key.";
 28             // 选中 item
 29             setSelected(true);
 30         } else if (event->modifiers() == Qt::AltModifier) {
 31             qDebug() << "Custom item left clicked with alt key.";
 32             // 重置 item 大小
 33             double radius = boundingRect().width() / 2.0;
 34             QPointF topLeft = boundingRect().topLeft();
 35             m_centerPointF = QPointF(topLeft.x() + pos().x() + radius, topLeft.y() + pos().y() + radius);
 36             QPointF pos = event->scenePos();
 37             qDebug() << boundingRect() << radius << this->pos() << pos << event->pos();
 38             double dist = sqrt(pow(m_centerPointF.x()-pos.x(), 2) + pow(m_centerPointF.y()-pos.y(), 2));
 39             if (dist / radius > 0.8) {
 40                 qDebug() << dist << radius << dist / radius;
 41                 m_bResizing = true;
 42             } else {
 43                 m_bResizing = false;
 44             }
 45         } else {
 46             qDebug() << "Custom item left clicked.";
 47             QGraphicsItem::mousePressEvent(event);
 48             event->accept();
 49         }
 50     } else if (event->button() == Qt::RightButton) {
 51         qDebug() << "Custom item right clicked.";
 52         event->ignore();
 53     }
 54 }
 55 
 56 void CustomItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
 57 {
 58     if ((event->modifiers() == Qt::AltModifier) && m_bResizing) {
 59         QPointF pos = event->scenePos();
 60         double dist = sqrt(pow(m_centerPointF.x()-pos.x(), 2) + pow(m_centerPointF.y()-pos.y(), 2));
 61         setRect(m_centerPointF.x()-this->pos().x()-dist, m_centerPointF.y()-this->pos().y()-dist, dist*2, dist*2);
 62     } else if(event->modifiers() != Qt::AltModifier) {
 63         qDebug() << "Custom item moved.";
 64         QGraphicsItem::mouseMoveEvent(event);
 65         qDebug() << "moved" << pos();
 66     }
 67 }
 68 
 69 void CustomItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
 70 {
 71     if ((event->modifiers() == Qt::AltModifier) && m_bResizing) {
 72         m_bResizing = false;
 73     } else {
 74         QGraphicsItem::mouseReleaseEvent(event);
 75     }
 76 }
 77 
 78 int CustomItem::type() const
 79 {
 80     return UserType + 1;
 81 }
 82 
 83 // 自定义 Scene
 84 void CustomScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
 85 {
 86     qDebug() << "Custom scene clicked.";
 87     QGraphicsScene::mousePressEvent(event);
 88     if (!event->isAccepted()) {
 89         if (event->button() == Qt::LeftButton) {
 90             // 在 Scene 上添加一个自定义 item
 91             QPointF point = event->scenePos();
 92             CustomItem *item = new CustomItem();
 93             item->setRect(point.x()-25, point.y()-25, 60, 60);
 94             addItem(item);
 95         } else if (event->button() == Qt::RightButton) {
 96             // 检测光标下是否有 item
 97             QGraphicsItem *itemToRemove = NULL;
 98             foreach (QGraphicsItem *item, items(event->scenePos())) {
 99                 if (item->type() == QGraphicsItem::UserType+1) {
100                     itemToRemove = item;
101                     break;
102                 }
103             }
104             // 从 Scene 上移除 item
105             if (itemToRemove != NULL)
106                 removeItem(itemToRemove);
107         }
108     }
109 }
110 
111 void CustomScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
112 {
113     qDebug() << "Custom scene moved.";
114     QGraphicsScene::mouseMoveEvent(event);
115 }
116 
117 void CustomScene::keyPressEvent(QKeyEvent *event) {
118     if (event->key() == Qt::Key_Backspace) {
119         // 移除所有选中的 items
120         qDebug() << "selected items " << selectedItems().size();
121         while (!selectedItems().isEmpty()) {
122             removeItem(selectedItems().front());
123         }
124     } else {
125         QGraphicsScene::keyPressEvent(event);
126     }
127 }

使用很简单,将 item 添加至 scene 中,通过 view 显示即可。

 1 #include <QApplication>
 2 #include <QGraphicsView>
 3 #include "custom_item.h"
 4 
 5 int main(int argc, char *argv[])
 6 {
 7     QApplication a(argc, argv);
 8 
 9     // 创建 item
10     CustomItem *pItem = new CustomItem();
11     pItem->setRect(20, 20, 60, 60);
12 
13     // 将 item 添加至场景中
14     CustomScene scene;
15     scene.setSceneRect(0, 0, 400, 300);
16     scene.addItem(pItem);
17 
18     // 为视图设置场景
19     QGraphicsView view;
20     view.setScene(&scene);
21     view.show();
22 
23     return a.exec();
24 }
原文地址:https://www.cnblogs.com/ybqjymy/p/13826215.html