zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    关于postman使用上发现的一点问题
    关于异步的处理方法
    关于console.log() 打印得引用类型得数据得相关问题
    使用electron将单页面vue webapp 打包成 PC端应用
    当后台只接受字符串得时候,在传输复杂得数据得时候会发生得问题
    默认事件
    事件冒泡
    offsetWidth clientWidth scrollWidth 三者之间的区别和联系
    事件获取目标 currentTarget target srcElement三者之间的区别和联系
    不支持模块化规范的插件可以使用import 导入的原因
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/13826215.html
Copyright © 2011-2022 走看看