Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

219 rader
7.4 KiB

  1. #include "mygraphicsview.h"
  2. #include <QMimeData>
  3. #include <QCursor>
  4. #include <QGraphicsScene>
  5. #include <QDebug>
  6. #include <QMenu>
  7. MyGraphicsView::ClipInfo MyGraphicsView::clipboard_ = {};
  8. MyGraphicsView::MyGraphicsView(QWidget *parent)
  9. : QGraphicsView(parent)
  10. {
  11. setAcceptDrops(true);
  12. setRenderHint(QPainter::Antialiasing);
  13. setFocusPolicy(Qt::StrongFocus);
  14. setDragMode(QGraphicsView::RubberBandDrag);
  15. }
  16. void MyGraphicsView::dragEnterEvent(QDragEnterEvent *event)
  17. {
  18. if (event->mimeData()->hasFormat("application/x-component"))
  19. event->acceptProposedAction();
  20. else
  21. event->ignore();
  22. }
  23. void MyGraphicsView::dragMoveEvent(QDragMoveEvent *event)
  24. {
  25. if (event->mimeData()->hasFormat("application/x-component"))
  26. event->acceptProposedAction();
  27. else
  28. event->ignore();
  29. }
  30. void MyGraphicsView::dropEvent(QDropEvent *event)
  31. {
  32. if (!event->mimeData()->hasFormat("application/x-component")) {
  33. event->ignore();
  34. return;
  35. }
  36. QString type = QString::fromUtf8(event->mimeData()->data("application/x-component"));
  37. QPointF scenePos = mapToScene(event->pos());
  38. Item *item = creatItem(type);
  39. item->setPos(scenePos);
  40. connect(item, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
  41. connect(item, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
  42. scene()->addItem(item);
  43. event->acceptProposedAction();
  44. }
  45. void MyGraphicsView::keyPressEvent(QKeyEvent *event)
  46. {
  47. if (event->key() == Qt::Key_Delete && scene()) {
  48. QList<QGraphicsItem*> selectedItems = scene()->selectedItems();
  49. for (QGraphicsItem* item : selectedItems) {
  50. if (auto conn = dynamic_cast<Connection*>(item)) {
  51. // 先通知两端节点断开
  52. conn->from_->removeConnection(conn);
  53. conn->to_->removeConnection(conn);
  54. scene()->removeItem(conn);
  55. delete conn;
  56. } else if (auto node = dynamic_cast<Item*>(item)) {
  57. // 删除节点的所有连线
  58. QList<Connection*> conns = node->connections();
  59. for (Connection* conn : conns) {
  60. conn->from_->removeConnection(conn);
  61. conn->to_->removeConnection(conn);
  62. scene()->removeItem(conn);
  63. delete conn;
  64. }
  65. scene()->removeItem(node);
  66. delete node;
  67. }
  68. }
  69. }else if (event->matches(QKeySequence::Copy)) {
  70. // Ctrl+C
  71. QList<QGraphicsItem*> selectedItems = scene()->selectedItems();
  72. for (QGraphicsItem* item : selectedItems) {
  73. if (auto node = dynamic_cast<Item*>(item)) {
  74. clipboard_.input = node->itemType();
  75. break;
  76. }
  77. }
  78. } else if (event->matches(QKeySequence::Paste)) {
  79. // Ctrl+V
  80. if (!clipboard_.input.isEmpty()) {
  81. QPointF center = mapToScene(viewport()->rect().center());
  82. Item* newItem = creatItem(clipboard_.input);
  83. newItem->setPos(center);
  84. connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
  85. connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
  86. scene()->addItem(newItem);
  87. }
  88. } else {
  89. QGraphicsView::keyPressEvent(event);
  90. }
  91. }
  92. void MyGraphicsView::contextMenuEvent(QContextMenuEvent *event)
  93. {
  94. QPointF scenePos = mapToScene(event->pos());
  95. QList<QGraphicsItem*> itemsAt = scene()->items(scenePos);
  96. if (itemsAt.isEmpty() && !clipboard_.input.isEmpty()) {
  97. QMenu menu;
  98. QAction* pasteAct = menu.addAction("粘贴");
  99. QAction* sel = menu.exec(event->globalPos());
  100. if (sel == pasteAct) {
  101. Item* newItem = creatItem(clipboard_.input);
  102. newItem->setPos(scenePos);
  103. connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
  104. connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
  105. scene()->addItem(newItem);
  106. }
  107. } else {
  108. QGraphicsView::contextMenuEvent(event); // 让Item自己弹出菜单
  109. }
  110. }
  111. // ----------- 连线交互 ------------
  112. Item* MyGraphicsView::anchorItemAt(const QPoint& viewPos, Item::AnchorType& anchorType)
  113. {
  114. QPointF scenePos = mapToScene(viewPos);
  115. for (QGraphicsItem* item : scene()->items(scenePos)) {
  116. if (Item* node = dynamic_cast<Item*>(item)) {
  117. QRectF r = node->boundingRect();
  118. QPointF local = node->mapFromScene(scenePos);
  119. if (QLineF(local, QPointF(r.left(), r.center().y())).length() < 10) {
  120. anchorType = Item::Left;
  121. return node;
  122. }
  123. if (QLineF(local, QPointF(r.right(), r.center().y())).length() < 10) {
  124. anchorType = Item::Right;
  125. return node;
  126. }
  127. }
  128. }
  129. return nullptr;
  130. }
  131. void MyGraphicsView::onItemRequestCopy(Item *item)
  132. {
  133. clipboard_.input = item->itemType();
  134. }
  135. void MyGraphicsView::onItemRequestDelete(Item *item)
  136. {
  137. QList<Connection*> conns = item->connections();
  138. for (Connection* conn : conns) {
  139. conn->from_->removeConnection(conn);
  140. conn->to_->removeConnection(conn);
  141. scene()->removeItem(conn);
  142. delete conn;
  143. }
  144. scene()->removeItem(item);
  145. delete item;
  146. }
  147. void MyGraphicsView::mousePressEvent(QMouseEvent *event)
  148. {
  149. if (event->button() == Qt::LeftButton) {
  150. Item::AnchorType anchor;
  151. Item* node = anchorItemAt(event->pos(), anchor);
  152. if (node) {
  153. drawingConnection_ = true;
  154. startItem_ = node;
  155. startAnchor_ = anchor;
  156. tempLine_ = scene()->addLine(QLineF(node->anchorPos(anchor), mapToScene(event->pos())),
  157. QPen(Qt::darkGray, 2, Qt::DashLine));
  158. return;
  159. }
  160. }
  161. QGraphicsView::mousePressEvent(event);
  162. }
  163. void MyGraphicsView::mouseMoveEvent(QMouseEvent *event)
  164. {
  165. if (drawingConnection_ && tempLine_) {
  166. QLineF l = tempLine_->line();
  167. l.setP2(mapToScene(event->pos()));
  168. tempLine_->setLine(l);
  169. return;
  170. }
  171. QGraphicsView::mouseMoveEvent(event);
  172. }
  173. void MyGraphicsView::mouseReleaseEvent(QMouseEvent *event)
  174. {
  175. if (drawingConnection_ && tempLine_) {
  176. // 检查鼠标释放点是否在某个Item boundingRect内
  177. QPointF scenePos = mapToScene(event->pos());
  178. for (QGraphicsItem* item : scene()->items(scenePos)) {
  179. if (Item* node = dynamic_cast<Item*>(item)) {
  180. QRectF r = node->boundingRect();
  181. QPointF local = node->mapFromScene(scenePos);
  182. // 计算落点距离左右端点
  183. double distLeft = QLineF(local, QPointF(r.left(), r.center().y())).length();
  184. double distRight = QLineF(local, QPointF(r.right(), r.center().y())).length();
  185. Item::AnchorType anchor = (distLeft < distRight) ? Item::Left : Item::Right;
  186. // 生成连线
  187. Connection* conn = new Connection(startItem_, startAnchor_, node, anchor);
  188. scene()->addItem(conn);
  189. break;
  190. }
  191. }
  192. // 清除临时线
  193. scene()->removeItem(tempLine_);
  194. delete tempLine_;
  195. tempLine_ = nullptr;
  196. drawingConnection_ = false;
  197. startItem_ = nullptr;
  198. return;
  199. }
  200. QGraphicsView::mouseReleaseEvent(event);
  201. }