25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
7.4 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. item->setRegisterId(d.registerId);
  105. connect(item, &Item::requestCopy, ui->graphicsView, &MyGraphicsView::onItemRequestCopy);
  106. connect(item, &Item::requestDelete, ui->graphicsView, &MyGraphicsView::onItemRequestDelete);
  107. connect(item, &Item::requestBindRegister, ui->graphicsView, &MyGraphicsView::onItemRequestBindRegister);
  108. plc_scene_->addItem(item);
  109. itemObjs.append(item);
  110. }
  111. for (const auto& c : proj.connections_) {
  112. if (c.from >= 0 && c.from < itemObjs.size() && c.to >= 0 && c.to < itemObjs.size()) {
  113. Connection* conn = new Connection(
  114. itemObjs[c.from], static_cast<Item::AnchorType>(c.fromType),
  115. itemObjs[c.to], static_cast<Item::AnchorType>(c.toType));
  116. plc_scene_->addItem(conn);
  117. }
  118. }
  119. }
  120. void PLC::extractSceneToProject(Project& proj)
  121. {
  122. proj.clear();
  123. QList<Item*> items;
  124. // (1) 先收集所有Item
  125. for (QGraphicsItem* gi : plc_scene_->items()) {
  126. if (Item* it = dynamic_cast<Item*>(gi)) {
  127. items.append(it);
  128. }
  129. }
  130. // (2) 存Item数据
  131. for (Item* it : items) {
  132. Project::ItemData d;
  133. d.type = it->itemType();
  134. d.x = it->pos().x();
  135. d.y = it->pos().y();
  136. d.registerId = it->registerId();
  137. proj.items_.append(d);
  138. }
  139. // (3) 存连线数据
  140. for (QGraphicsItem* gi : plc_scene_->items()) {
  141. if (Connection* conn = dynamic_cast<Connection*>(gi)) {
  142. int fromIdx = items.indexOf(conn->from_);
  143. int toIdx = items.indexOf(conn->to_);
  144. if (fromIdx >= 0 && toIdx >= 0) {
  145. Project::ConnectionData c;
  146. c.from = fromIdx;
  147. c.to = toIdx;
  148. c.fromType = static_cast<int>(conn->fromType_);
  149. c.toType = static_cast<int>(conn->toType_);
  150. proj.connections_.append(c);
  151. }
  152. }
  153. }
  154. }
  155. void PLC::onListwidgetCurrenttextchanged(const QString &text)
  156. {
  157. selectedComponentType = text;
  158. }
  159. void PLC::btnInsertClicked()
  160. {
  161. // 1. 找场景中被选中的连线
  162. QList<QGraphicsItem*> selectedItems = ui->graphicsView->scene()->selectedItems();
  163. Connection* selectedConn = nullptr;
  164. for (QGraphicsItem* item : selectedItems) {
  165. selectedConn = dynamic_cast<Connection*>(item);
  166. if (selectedConn) break;
  167. }
  168. if (!selectedConn) {
  169. QMessageBox::warning(this, "提示", "请先选中一条连线");
  170. return;
  171. }
  172. if (selectedComponentType.isEmpty()) {
  173. QMessageBox::warning(this, "提示", "请先在列表中选择要插入的组件");
  174. return;
  175. }
  176. // 2. 计算插入点(中点)
  177. QLineF lf = selectedConn->line();
  178. QPointF insertPos = (lf.p1() + lf.p2()) / 2;
  179. // 3. 删除原连线
  180. Item* from = selectedConn->from_;
  181. Item* to = selectedConn->to_;
  182. Item::AnchorType fromType = selectedConn->fromType_;
  183. Item::AnchorType toType = selectedConn->toType_;
  184. from->removeConnection(selectedConn);
  185. to->removeConnection(selectedConn);
  186. ui->graphicsView->scene()->removeItem(selectedConn);
  187. delete selectedConn;
  188. // 4. 插入新元件
  189. Item* newItem = creatItem(selectedComponentType);
  190. newItem->setPos(insertPos);
  191. connect(newItem, &Item::requestCopy, ui->graphicsView, &MyGraphicsView::onItemRequestCopy);
  192. connect(newItem, &Item::requestDelete, ui->graphicsView, &MyGraphicsView::onItemRequestDelete);
  193. connect(newItem, &Item::requestBindRegister, ui->graphicsView, &MyGraphicsView::onItemRequestBindRegister);
  194. ui->graphicsView->scene()->addItem(newItem);
  195. // 5. 新建两条连线
  196. Connection* c1 = new Connection(from, fromType, newItem, Item::Left);
  197. ui->graphicsView->scene()->addItem(c1);
  198. Connection* c2 = new Connection(newItem, Item::Right, to, toType);
  199. ui->graphicsView->scene()->addItem(c2);
  200. }