No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

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