Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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