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