25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

238 satır
8.2 KiB

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