Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

223 Zeilen
7.2 KiB

  1. #include "plc.h"
  2. #include "ui_plc.h"
  3. #include "item.h"
  4. #include <QListWidgetItem>
  5. #include <QMimeData>
  6. #include <QDrag>
  7. #include <QPainter>
  8. #include <QMouseEvent>
  9. #include <QDropEvent>
  10. #include <QGraphicsView>
  11. #include <QMessageBox>
  12. #include "creatitem.h"
  13. PLC::PLC(QWidget *parent) :
  14. QWidget(parent),
  15. ui(new Ui::PLC)
  16. {
  17. ui->setupUi(this);
  18. /* 1. 场景 */
  19. plc_scene_ = new QGraphicsScene(this);
  20. ui->graphicsView->setScene(plc_scene_);
  21. ui->graphicsView->setSceneRect(0, 0, 800, 600);
  22. ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
  23. /* 2. 列表 */
  24. ui->listWidget->setViewMode(QListView::IconMode);
  25. ui->listWidget->setIconSize(QSize(60, 30));
  26. ui->listWidget->setDragEnabled(false);
  27. ui->listWidget->viewport()->installEventFilter(this);
  28. /* 3. 填充列表 */
  29. createComponents();
  30. connect(ui->listWidget,&QListWidget::currentTextChanged,this,&PLC::onListwidgetCurrenttextchanged);
  31. connect(ui->btn_insert,&QPushButton::clicked,this,&PLC::btnInsertClicked);
  32. }
  33. PLC::~PLC()
  34. {
  35. delete ui;
  36. }
  37. bool PLC::eventFilter(QObject *obj, QEvent *event)
  38. {
  39. if (obj == ui->listWidget->viewport()) {
  40. static QListWidgetItem *dragItem = nullptr;
  41. static QPoint startPos;
  42. if (event->type() == QEvent::MouseButtonPress) {
  43. auto *me = static_cast<QMouseEvent*>(event);
  44. if (me->button() == Qt::LeftButton) {
  45. dragItem = ui->listWidget->itemAt(me->pos());
  46. startPos = me->pos();
  47. }
  48. } else if (event->type() == QEvent::MouseMove && dragItem) {
  49. auto *me = static_cast<QMouseEvent*>(event);
  50. if ((me->pos() - startPos).manhattanLength()
  51. >= QApplication::startDragDistance()) {
  52. QString type = dragItem->data(Qt::UserRole).toString();
  53. QMimeData *mime = new QMimeData;
  54. mime->setData("application/x-component", type.toUtf8());
  55. QDrag *drag = new QDrag(this);
  56. drag->setMimeData(mime);
  57. drag->setPixmap(dragItem->icon().pixmap(ui->listWidget->iconSize()));
  58. drag->setHotSpot(drag->pixmap().rect().center());
  59. drag->exec(Qt::CopyAction);
  60. dragItem = nullptr;
  61. }
  62. } else if (event->type() == QEvent::MouseButtonRelease) {
  63. dragItem = nullptr;
  64. }
  65. }
  66. return QWidget::eventFilter(obj, event);
  67. }
  68. void PLC::createComponents()
  69. {
  70. struct Comp { QString name; QColor color; };
  71. const QVector<Comp> comps = {
  72. {"常开", Qt::blue},
  73. {"常闭", Qt::red},
  74. {"比较", Qt::green},
  75. {"线圈", Qt::darkYellow}
  76. };
  77. for (const Comp &c : comps) {
  78. QListWidgetItem *it = new QListWidgetItem(c.name, ui->listWidget);
  79. QPixmap pix(60, 30);
  80. pix.fill(Qt::white);
  81. QPainter p(&pix);
  82. p.setRenderHint(QPainter::Antialiasing);
  83. p.setBrush(c.color.lighter(150));
  84. p.setPen(QPen(c.color, 2));
  85. p.drawRoundedRect(QRect(5, 5, 50, 20), 3, 3);
  86. p.setPen(Qt::black);
  87. p.drawText(QRect(5, 5, 50, 20), Qt::AlignCenter, c.name);
  88. it->setIcon(QIcon(pix));
  89. it->setData(Qt::UserRole, c.name);
  90. }
  91. }
  92. void PLC::clearScene()
  93. {
  94. plc_scene_->clear();
  95. }
  96. void PLC::applyProjectToScene(const Project& proj)
  97. {
  98. clearScene();
  99. QVector<Item*> itemObjs;
  100. for (const auto& d : proj.items_) {
  101. Item* item = creatItem(d.type);
  102. if (!item) continue;
  103. item->setPos(d.x, d.y);
  104. connect(item, &Item::requestCopy, ui->graphicsView, &MyGraphicsView::onItemRequestCopy);
  105. connect(item, &Item::requestDelete, ui->graphicsView, &MyGraphicsView::onItemRequestDelete);
  106. connect(item, &Item::requestBindRegister, ui->graphicsView, &MyGraphicsView::onItemRequestBindRegister);
  107. plc_scene_->addItem(item);
  108. itemObjs.append(item);
  109. }
  110. for (const auto& c : proj.connections_) {
  111. if (c.from >= 0 && c.from < itemObjs.size() && c.to >= 0 && c.to < itemObjs.size()) {
  112. Connection* conn = new Connection(
  113. itemObjs[c.from], static_cast<Item::AnchorType>(c.fromType),
  114. itemObjs[c.to], static_cast<Item::AnchorType>(c.toType));
  115. plc_scene_->addItem(conn);
  116. }
  117. }
  118. }
  119. void PLC::extractSceneToProject(Project& proj)
  120. {
  121. proj.clear();
  122. QList<Item*> items;
  123. // (1) 先收集所有Item
  124. for (QGraphicsItem* gi : plc_scene_->items()) {
  125. if (Item* it = dynamic_cast<Item*>(gi)) {
  126. items.append(it);
  127. }
  128. }
  129. // (2) 存Item数据
  130. for (Item* it : items) {
  131. Project::ItemData d;
  132. d.type = it->itemType();
  133. d.x = it->pos().x();
  134. d.y = it->pos().y();
  135. proj.items_.append(d);
  136. }
  137. // (3) 存连线数据
  138. for (QGraphicsItem* gi : plc_scene_->items()) {
  139. if (Connection* conn = dynamic_cast<Connection*>(gi)) {
  140. int fromIdx = items.indexOf(conn->from_);
  141. int toIdx = items.indexOf(conn->to_);
  142. if (fromIdx >= 0 && toIdx >= 0) {
  143. Project::ConnectionData c;
  144. c.from = fromIdx;
  145. c.to = toIdx;
  146. c.fromType = static_cast<int>(conn->fromType_);
  147. c.toType = static_cast<int>(conn->toType_);
  148. proj.connections_.append(c);
  149. }
  150. }
  151. }
  152. }
  153. void PLC::onListwidgetCurrenttextchanged(const QString &text)
  154. {
  155. selectedComponentType = text;
  156. }
  157. void PLC::btnInsertClicked()
  158. {
  159. // 1. 找场景中被选中的连线
  160. QList<QGraphicsItem*> selectedItems = ui->graphicsView->scene()->selectedItems();
  161. Connection* selectedConn = nullptr;
  162. for (QGraphicsItem* item : selectedItems) {
  163. selectedConn = dynamic_cast<Connection*>(item);
  164. if (selectedConn) break;
  165. }
  166. if (!selectedConn) {
  167. QMessageBox::warning(this, "提示", "请先选中一条连线");
  168. return;
  169. }
  170. if (selectedComponentType.isEmpty()) {
  171. QMessageBox::warning(this, "提示", "请先在列表中选择要插入的组件");
  172. return;
  173. }
  174. // 2. 计算插入点(中点)
  175. QLineF lf = selectedConn->line();
  176. QPointF insertPos = (lf.p1() + lf.p2()) / 2;
  177. // 3. 删除原连线
  178. Item* from = selectedConn->from_;
  179. Item* to = selectedConn->to_;
  180. Item::AnchorType fromType = selectedConn->fromType_;
  181. Item::AnchorType toType = selectedConn->toType_;
  182. from->removeConnection(selectedConn);
  183. to->removeConnection(selectedConn);
  184. ui->graphicsView->scene()->removeItem(selectedConn);
  185. delete selectedConn;
  186. // 4. 插入新元件
  187. Item* newItem = creatItem(selectedComponentType);
  188. newItem->setPos(insertPos);
  189. connect(newItem, &Item::requestCopy, ui->graphicsView, &MyGraphicsView::onItemRequestCopy);
  190. connect(newItem, &Item::requestDelete, ui->graphicsView, &MyGraphicsView::onItemRequestDelete);
  191. ui->graphicsView->scene()->addItem(newItem);
  192. // 5. 新建两条连线
  193. Connection* c1 = new Connection(from, fromType, newItem, Item::Left);
  194. ui->graphicsView->scene()->addItem(c1);
  195. Connection* c2 = new Connection(newItem, Item::Right, to, toType);
  196. ui->graphicsView->scene()->addItem(c2);
  197. }