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 }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM