|
- // PLCDocument.cpp 的完整修改版
- #include "plcdocument.h"
- #include "plcitems.h"
- #include <QPainter>
- #include <QPen>
- #include <QBrush>
- #include <QMenu>
- #include <QAction>
- #include <QGraphicsSceneMouseEvent>
- #include <QJsonDocument>
- #include <QJsonObject>
- #include <QJsonArray>
- #include <QFile>
- #include <QFileInfo>
- #include <QVBoxLayout>
- #include <QMessageBox>
- #include <QInputDialog>
- #include <QDragEnterEvent>
- #include <QDragMoveEvent>
- #include <QCursor>
- #include <QDropEvent>
- #include <QMimeData>
- #include <cmath>
- #include <QResizeEvent>
- #include <QDebug>
- #include <QGraphicsItem>
- #include <QGraphicsSceneMouseEvent>
- #include <QSet>
-
- // 固定表格尺寸的常量
- const int DEFAULT_ROWS = 20;
- const int DEFAULT_COLUMNS = 25;
- const int DEFAULT_CELL_SIZE = 50;
-
- PLCDocument::PLCDocument(QWidget *parent)
- : BaseDocument(PLC, parent)
- , m_rows(DEFAULT_ROWS)
- , m_columns(DEFAULT_COLUMNS)
- ,m_cellSize(DEFAULT_CELL_SIZE)
- {
- // 创建绘图场景
- m_scene = new QGraphicsScene(this);
- m_scene->setSceneRect(0, 0, m_columns * m_cellSize, m_rows * m_cellSize);
-
- // 创建视图
- m_view = new QGraphicsView(m_scene, this);
- m_view->setRenderHint(QPainter::Antialiasing);
- m_view->setDragMode(QGraphicsView::RubberBandDrag);
- m_view->setMouseTracking(true);
- m_view->viewport()->installEventFilter(this);
- m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- m_view->setAlignment(Qt::AlignLeft | Qt::AlignTop);
- m_view->setFixedSize(m_columns * m_cellSize, m_rows * m_cellSize);
-
- setAcceptDrops(true);
- m_view->setAcceptDrops(true);
- m_view->viewport()->setAcceptDrops(true);
-
- // 布局(让视图占满文档区域)
- auto layout = new QVBoxLayout(this);
- layout->setContentsMargins(0, 0, 0, 0);
- layout->addWidget(m_view);
- setLayout(layout);
-
- // 创建固定大小的表格
- createRealTable();
-
- // 连接场景信号
- connect(m_scene, &QGraphicsScene::selectionChanged, this, [this]() {
- auto items = m_scene->selectedItems();
- if (items.size() == 1 && dynamic_cast<PLCItem*>(items.first())) {
- PLCItem *item = static_cast<PLCItem*>(items.first());
- if (m_connectionStart) {
- endConnection(item);
- }
- }
- });
-
- // 连接场景变化信号(用于更新连接线位置)
- connect(m_scene, &QGraphicsScene::changed, this, &PLCDocument::handleSceneChanged);
- }
-
- PLCDocument::~PLCDocument()
- {
- qDeleteAll(m_connections);
- clearTable();
- }
-
- QString PLCDocument::title() const {
- return "PLC文档";
- }
-
- void PLCDocument::createRealTable()
- {
- clearTable();
-
- // 表格整体区域(覆盖整个场景)
- QRectF tableRect(0, 0, m_columns * m_cellSize, m_rows * m_cellSize);
- m_tableFrame = new QGraphicsRectItem(tableRect);
- m_tableFrame->setPen(QPen(Qt::black, 2));
- m_tableFrame->setBrush(QBrush(QColor(245, 245, 245))); // 浅灰背景区分表格区域
- m_tableFrame->setZValue(-10);
- m_scene->addItem(m_tableFrame);
-
- // 添加垂直线(单元格分隔线)
- for (int col = 0; col <= m_columns; col++) {
- int x = col * m_cellSize;
- QGraphicsLineItem* line = new QGraphicsLineItem(x, 0, x, m_rows * m_cellSize);
- line->setPen(QPen(Qt::darkGray, 1));
- line->setZValue(-9);
- m_scene->addItem(line);
- m_verticalLines.append(line);
- }
-
- // 添加水平线(单元格分隔线)
- for (int row = 0; row <= m_rows; row++) {
- int y = row * m_cellSize;
- QGraphicsLineItem* line = new QGraphicsLineItem(0, y, m_columns * m_cellSize, y);
- line->setPen(QPen(Qt::darkGray, 1));
- line->setZValue(-9);
- m_scene->addItem(line);
- m_horizontalLines.append(line);
- }
- }
-
- void PLCDocument::clearTable()
- {
- if (m_tableFrame) {
- m_scene->removeItem(m_tableFrame);
- delete m_tableFrame;
- m_tableFrame = nullptr;
- }
-
- for (auto line : m_horizontalLines) {
- m_scene->removeItem(line);
- delete line;
- }
- m_horizontalLines.clear();
-
- for (auto line : m_verticalLines) {
- m_scene->removeItem(line);
- delete line;
- }
- m_verticalLines.clear();
- }
-
- QPointF PLCDocument::snapToCellCenter(const QPointF& pos) const
- {
- // 计算所在单元格列号(0~m_columns-1)
- int col = static_cast<int>(std::floor(pos.x() / m_cellSize));
- // 计算所在单元格行号(0~m_rows-1)
- int row = static_cast<int>(std::floor(pos.y() / m_cellSize));
-
- // 限制在表格范围内
- col = qBound(0, col, m_columns - 1);
- row = qBound(0, row, m_rows - 1);
-
- return QPointF(col * m_cellSize + m_cellSize / 2.0,
- row * m_cellSize + m_cellSize / 2.0);
- }
-
- QPointF PLCDocument::constrainToTable(const QPointF &pos) const
- {
- int col = static_cast<int>(std::floor(pos.x() / m_cellSize));
- int row = static_cast<int>(std::floor(pos.y() / m_cellSize));
-
- col = qBound(0, col, m_columns - 1);
- row = qBound(0, row, m_rows - 1);
-
- return QPointF(col * m_cellSize + m_cellSize / 2.0,
- row * m_cellSize + m_cellSize / 2.0);
- }
-
- void PLCDocument::resizeEvent(QResizeEvent *event)
- {
- QWidget::resizeEvent(event);
- // 不再调整表格大小,只更新视图尺寸
- m_view->setFixedSize(m_columns * m_cellSize, m_rows * m_cellSize);
- }
-
- bool PLCDocument::eventFilter(QObject *obj, QEvent *event)
- {
- // 仅处理viewport的事件
- if (obj == m_view->viewport())
- {
- // 处理拖拽进入事件
- if (event->type() == QEvent::DragEnter) {
- QDragEnterEvent *dragEvent = static_cast<QDragEnterEvent*>(event);
- if (dragEvent->mimeData()->hasText()) {
- dragEvent->acceptProposedAction();
- return true;
- }
- }
- // 处理拖拽移动事件
- else if (event->type() == QEvent::DragMove) {
- QDragMoveEvent *dragEvent = static_cast<QDragMoveEvent*>(event);
- if(dragEvent->mimeData()->hasText()) {
- dragEvent->acceptProposedAction();
- return true;
- }
- }
- // 处理拖拽释放事件(使用单元格中心对齐)
- else if (event->type() == QEvent::Drop) {
- QDropEvent *dropEvent = static_cast<QDropEvent*>(event);
- const QMimeData *mimeData = dropEvent->mimeData();
- if (mimeData->hasText()) {
- QPoint viewportPos = m_view->viewport()->mapFromParent(dropEvent->pos());
- QPointF scenePos = m_view->mapToScene(viewportPos);
- // 对齐到单元格中心
- QPointF cellCenter = snapToCellCenter(scenePos);
- // 检查单元格是否已被占用
- QSet<int> occupiedCells;
- for (QGraphicsItem* item : m_scene->items()) {
- if (PLCItem* plcItem = dynamic_cast<PLCItem*>(item)) {
- int col = static_cast<int>(plcItem->x() / m_cellSize);
- int row = static_cast<int>(plcItem->y() / m_cellSize);
- occupiedCells.insert(col * 1000 + row); // 简单的行列唯一键
- }
- }
-
- int col = static_cast<int>(cellCenter.x() / m_cellSize);
- int row = static_cast<int>(cellCenter.y() / m_cellSize);
- int cellKey = col * 1000 + row;
-
- // 如果单元格被占用,尝试移动到最近的空单元格
- if (occupiedCells.contains(cellKey)) {
- bool found = false;
- // 尝试向右移动
- for (int offset = 1; offset < m_columns; offset++) {
- int newCol = col + offset;
- if (newCol < m_columns) {
- int newKey = newCol * 1000 + row;
- if (!occupiedCells.contains(newKey)) {
- cellCenter = QPointF(newCol * m_cellSize + m_cellSize / 2.0,
- row * m_cellSize + m_cellSize / 2.0);
- found = true;
- break;
- }
- }
- }
- if (!found) {
- // 尝试向下移动
- for (int offset = 1; offset < m_rows; offset++) {
- int newRow = row + offset;
- if (newRow < m_rows) {
- int newKey = col * 1000 + newRow;
- if (!occupiedCells.contains(newKey)) {
- cellCenter = QPointF(col * m_cellSize + m_cellSize / 2.0,
- newRow * m_cellSize + m_cellSize / 2.0);
- found = true;
- break;
- }
- }
- }
- }
- }
-
- // 创建PLC控件
- QString toolType = mimeData->text();
- createPLCItem(toolType, cellCenter);
- m_currentTool.clear();
- dropEvent->acceptProposedAction();
- return true;
- }
- }
-
- }
-
- if (obj != m_view->viewport()) {
- return QWidget::eventFilter(obj, event);
- }
-
- // 鼠标移动事件(更新临时连线)- 基于单元格中心
- if (event->type() == QEvent::MouseMove && m_tempLine) {
- QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
- QPointF scenePos = m_view->mapToScene(mouseEvent->pos());
- QPointF cellCenter = snapToCellCenter(scenePos); // 使用单元格中心
- QLineF line(m_connectionStart->rightTerminal(), cellCenter);
- m_tempLine->setLine(line);
- }
-
- // 鼠标按下事件
- if (event->type() == QEvent::MouseButtonPress) {
- QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
-
- // 右键点击 - 显示上下文菜单
- if (mouseEvent->button() == Qt::RightButton) {
- createContextMenu(mouseEvent->globalPos());
- return true;
- }
-
- // 左键点击
- if (mouseEvent->button() == Qt::LeftButton) {
- QPointF scenePos = m_view->mapToScene(mouseEvent->pos());
- QPointF cellCenter = snapToCellCenter(scenePos); // 单元格中心
-
- // 使用当前工具创建控件
- if (!m_currentTool.isEmpty()) {
- // 检查单元格是否已被占用
- QSet<int> occupiedCells;
- for (QGraphicsItem* item : m_scene->items()) {
- if (PLCItem* plcItem = dynamic_cast<PLCItem*>(item)) {
- int col = static_cast<int>(plcItem->x() / m_cellSize);
- int row = static_cast<int>(plcItem->y() / m_cellSize);
- occupiedCells.insert(col * 1000 + row); // 简单的行列唯一键
- }
- }
-
- int col = static_cast<int>(cellCenter.x() / m_cellSize);
- int row = static_cast<int>(cellCenter.y() / m_cellSize);
- int cellKey = col * 1000 + row;
-
- // 如果单元格被占用,显示警告
- if (occupiedCells.contains(cellKey)) {
- QMessageBox::warning(this, "位置被占用", "此单元格已被占用,请选择其他位置。");
- return true;
- }
-
- createPLCItem(m_currentTool, cellCenter);
- m_currentTool.clear();
- return true;
- }
-
- // 连线模式处理
- if (m_connectionStart) {
- QGraphicsItem *item = m_scene->itemAt(cellCenter, m_view->transform());
- if (PLCItem *plcItem = dynamic_cast<PLCItem*>(item)) {
- endConnection(plcItem);
- return true;
- }
- }
-
- // 开始连线
- QGraphicsItem *item = m_scene->itemAt(cellCenter, m_view->transform());
- if (PLCItem *plcItem = dynamic_cast<PLCItem*>(item)) {
- startConnection(plcItem);
- return true;
- }
- }
- }
-
- return QWidget::eventFilter(obj, event);
- }
-
- void PLCDocument::createPLCItem(const QString &type, const QPointF &pos)
- {
- PLCItem *item = nullptr;
-
- if (type == "常开") {
- item = new NormallyOpenItem;
- } else if (type == "常闭") {
- item = new NormallyClosedItem;
- } else if (type == "大于") {
- item = new GreaterThanItem;
- } else if (type == "大于等于") {
- item = new GreaterEqualItem;
- } else if (type == "小于") {
- item = new LessThanItem;
- } else if (type == "小于等于") {
- item = new LessEqualItem;
- } else if (type == "等于") {
- item = new EqualItem;
- } else if (type == "线圈") {
- item = new CoilItem;
- }
-
- if (item) {
- // 确保位置在表格内并居中
- QPointF constrainedPos = constrainToTable(pos);
- item->setPos(constrainedPos);
- m_scene->addItem(item);
- setModified(true);
-
- // 连接状态变化信号
- connect(item, &PLCItem::stateChanged, this, [this, item](bool active) {
- if (m_simulationRunning) {
- if (active) {
- m_activeItems.insert(item);
- } else {
- m_activeItems.remove(item);
- }
- updateConnections();
- }
- });
- }
- }
-
- void PLCDocument::handleSceneChanged()
- {
- // 遍历所有项目,处理位置变化
- for (QGraphicsItem *item : m_scene->items()) {
- if (PLCItem *plcItem = dynamic_cast<PLCItem*>(item)) {
- handleItemPositionChange(plcItem);
- }
- }
- }
-
- void PLCDocument::handleItemPositionChange(PLCItem *item)
- {
- // 限制项目位置在表格内
- QPointF newPos = constrainToTable(item->pos());
- if (newPos != item->pos()) {
- item->setPos(newPos);
- }
-
- // 更新所有与该项目相关的连接
- for (ConnectionLine *line : m_connections) {
- if (line->startItem() == item || line->endItem() == item) {
- line->updatePosition();
- }
- }
- }
-
- void PLCDocument::startConnection(PLCItem *startItem)
- {
- if (m_connectionStart) {
- clearCurrentConnection();
- }
-
- m_connectionStart = startItem;
- m_tempLine = new QGraphicsLineItem;
- m_tempLine->setPen(QPen(Qt::blue, 2, Qt::DashLine));
- m_tempLine->setLine(QLineF(startItem->rightTerminal(), startItem->rightTerminal()));
- m_scene->addItem(m_tempLine);
- }
-
- void PLCDocument::endConnection(PLCItem *endItem)
- {
- if (!m_connectionStart || m_connectionStart == endItem) {
- clearCurrentConnection();
- return;
- }
-
- // 创建永久连接线
- ConnectionLine *connection = new ConnectionLine(m_connectionStart, endItem);
- m_scene->addItem(connection);
- m_connections.append(connection);
-
- clearCurrentConnection();
- setModified(true);
- }
-
- void PLCDocument::clearCurrentConnection()
- {
- if (m_tempLine) {
- m_scene->removeItem(m_tempLine);
- delete m_tempLine;
- m_tempLine = nullptr;
- }
- m_connectionStart = nullptr;
- }
-
- void PLCDocument::updateConnections()
- {
- for (ConnectionLine *line : m_connections) {
- PLCItem *start = line->startItem();
- PLCItem *end = line->endItem();
-
- if (m_activeItems.contains(start) && m_activeItems.contains(end)) {
- line->setPen(QPen(Qt::green, 2));
- } else {
- line->setPen(QPen(Qt::black, 1));
- }
- }
- }
-
- void PLCDocument::setSimulationRunning(bool running)
- {
- m_simulationRunning = running;
- if (!running) {
- resetSimulation();
- }
- }
-
- void PLCDocument::resetSimulation()
- {
- m_activeItems.clear();
- for (QGraphicsItem *item : m_scene->items()) {
- if (PLCItem *plcItem = dynamic_cast<PLCItem*>(item)) {
- plcItem->setState(false);
- }
- }
- updateConnections();
- }
-
- void PLCDocument::createContextMenu(QPoint globalPos)
- {
- QMenu menu(this);
-
- QAction *runAction = menu.addAction("运行模拟");
- QAction *stopAction = menu.addAction("停止模拟");
- QAction *resetAction = menu.addAction("重置模拟");
- menu.addSeparator();
- QAction *nameAction = menu.addAction("重命名");
- menu.addSeparator();
- QAction *tableSizeAction = menu.addAction("调整表格尺寸");
- QAction *tableGridAction = menu.addAction("隐藏/显示网格");
-
- connect(runAction, &QAction::triggered, this, [this]() {
- setSimulationRunning(true);
- });
-
- connect(stopAction, &QAction::triggered, this, [this]() {
- setSimulationRunning(false);
- });
-
- connect(resetAction, &QAction::triggered, this, &PLCDocument::resetSimulation);
-
- connect(nameAction, &QAction::triggered, this, [this]() {
- QList<QGraphicsItem*> selected = m_scene->selectedItems();
- if (selected.size() == 1) {
- if (PLCItem *item = dynamic_cast<PLCItem*>(selected.first())) {
- QString name = QInputDialog::getText(this, "重命名", "输入名称:",
- QLineEdit::Normal, item->name());
- if (!name.isEmpty()) {
- item->setName(name);
- setModified(true);
- }
- }
- }
- });
-
- connect(tableSizeAction, &QAction::triggered, this, [this]() {
- bool ok;
- int cellSize = QInputDialog::getInt(this, "单元格大小", "输入单元格大小(像素):",
- m_cellSize, 10, 100, 10, &ok);
- if (ok && cellSize != m_cellSize) {
- m_cellSize = cellSize;
- m_view->setFixedSize(m_columns * m_cellSize, m_rows * m_cellSize);
- createRealTable();
- setModified(true);
- }
- });
-
- connect(tableGridAction, &QAction::triggered, this, [this]() {
- for (auto line : m_horizontalLines) {
- line->setVisible(!line->isVisible());
- }
- for (auto line : m_verticalLines) {
- line->setVisible(!line->isVisible());
- }
- });
-
- menu.exec(globalPos);
- }
-
- bool PLCDocument::saveToFile(const QString &filePath)
- {
- QFile file(filePath);
- if (!file.open(QIODevice::WriteOnly)) {
- QMessageBox::warning(this, "保存失败", "无法打开文件进行写入:" + filePath);
- return false;
- }
-
- // 创建JSON文档结构
- QJsonObject docObject;
- docObject["type"] = "PLCDocument";
-
- // 保存表格参数
- docObject["table_rows"] = m_rows;
- docObject["table_columns"] = m_columns;
- docObject["table_cell_size"] = m_cellSize;
-
- // 序列化所有PLC元件 - 改为保存单元格坐标
- QJsonArray itemsArray;
- for (QGraphicsItem *item : m_scene->items()) {
- if (PLCItem *plcItem = dynamic_cast<PLCItem*>(item)) {
- QJsonObject itemObj;
- itemObj["type"] = plcItem->itemType();
- int col = static_cast<int>(plcItem->x() / m_cellSize);
- int row = static_cast<int>(plcItem->y() / m_cellSize);
- itemObj["col"] = col; // 保存列索引
- itemObj["row"] = row; // 保存行索引
- itemObj["name"] = plcItem->name();
- itemObj["active"] = plcItem->isActive();
- itemsArray.append(itemObj);
- }
- }
- docObject["items"] = itemsArray;
-
- // 序列化所有连接 - 改为保存起始和终止元件的坐标
- QJsonArray connectionsArray;
- for (ConnectionLine *line : m_connections) {
- QJsonObject connObj;
- // 通过坐标查找起始和终止元件
- int startCol = static_cast<int>(line->startItem()->x() / m_cellSize);
- int startRow = static_cast<int>(line->startItem()->y() / m_cellSize);
- int endCol = static_cast<int>(line->endItem()->x() / m_cellSize);
- int endRow = static_cast<int>(line->endItem()->y() / m_cellSize);
- connObj["startCol"] = startCol;
- connObj["startRow"] = startRow;
- connObj["endCol"] = endCol;
- connObj["endRow"] = endRow;
- connectionsArray.append(connObj);
- }
- docObject["connections"] = connectionsArray;
-
- // 写入文件
- QJsonDocument doc(docObject);
- file.write(doc.toJson());
- file.close();
-
- // 更新文档状态
- setFilePath(filePath);
- setModified(false);
- return true;
- }
-
- bool PLCDocument::loadFromFile(const QString &filePath)
- {
- QFile file(filePath);
- if (!file.open(QIODevice::ReadOnly)) {
- QMessageBox::warning(this, "打开失败", "无法打开文件:" + filePath);
- return false;
- }
-
- // 读取并解析JSON
- QByteArray data = file.readAll();
- file.close();
-
- QJsonParseError parseError;
- QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
- if (parseError.error != QJsonParseError::NoError) {
- QMessageBox::warning(this, "文件格式错误", "JSON解析错误: " + parseError.errorString());
- return false;
- }
-
- if (doc.isNull() || !doc.isObject()) {
- QMessageBox::warning(this, "文件格式错误", "不是有效的PLC文档");
- return false;
- }
-
- // 解析文档
- QJsonObject docObject = doc.object();
- if (docObject["type"].toString() != "PLCDocument") {
- QMessageBox::warning(this, "文件类型错误", "不是有效的PLC文档");
- return false;
- }
-
- // 获取表格参数
- m_rows = docObject["table_rows"].toInt(DEFAULT_ROWS);
- m_columns = docObject["table_columns"].toInt(DEFAULT_COLUMNS);
- m_cellSize = docObject["table_cell_size"].toInt(DEFAULT_CELL_SIZE);
-
- // 停止任何模拟
- setSimulationRunning(false);
-
- // 安全地重置场景
- m_scene->blockSignals(true); // 防止在加载过程中发送变化信号
-
- // 清理现有内容 - 更安全的方式
- for (auto conn : m_connections) {
- m_scene->removeItem(conn);
- delete conn;
- }
- m_connections.clear();
-
- QList<QGraphicsItem*> allItems = m_scene->items();
- for (QGraphicsItem* item : allItems) {
- // 保留表格项,只删除PLC元件
- if (dynamic_cast<PLCItem*>(item) || dynamic_cast<ConnectionLine*>(item)) {
- m_scene->removeItem(item);
- delete item;
- }
- }
-
- m_activeItems.clear();
- m_connectionStart = nullptr;
- delete m_tempLine;
- m_tempLine = nullptr;
-
- // 创建表格
- createRealTable(); // 重新创建表格以确保正确
-
- // 加载PLC元件
- QMap<QPair<int, int>, PLCItem*> itemMap; // (列, 行) -> PLCItem
- QJsonArray itemsArray = docObject["items"].toArray();
- for (const QJsonValue &itemValue : itemsArray) {
- QJsonObject itemObj = itemValue.toObject();
- PLCItem::ItemType type = static_cast<PLCItem::ItemType>(itemObj["type"].toInt());
- int col = itemObj["col"].toInt();
- int row = itemObj["row"].toInt();
- QString name = itemObj["name"].toString();
- bool active = itemObj["active"].toBool();
-
- // 确保位置在表格范围内
- col = qBound(0, col, m_columns - 1);
- row = qBound(0, row, m_rows - 1);
-
- PLCItem *item = createItemByType(type);
- if (item) {
- QPointF pos(col * m_cellSize + m_cellSize / 2.0,
- row * m_cellSize + m_cellSize / 2.0);
- item->setPos(pos);
- item->setName(name);
- item->setState(active);
- m_scene->addItem(item);
-
- // 添加到映射表
- itemMap.insert(qMakePair(col, row), item);
-
- if (active) {
- m_activeItems.insert(item);
- }
-
- connect(item, &PLCItem::stateChanged, this, [this, item](bool active) {
- if (m_simulationRunning) {
- if (active) m_activeItems.insert(item);
- else m_activeItems.remove(item);
- updateConnections();
- }
- });
- }
- }
-
- // 加载连接
- QJsonArray connectionsArray = docObject["connections"].toArray();
- for (const QJsonValue &connValue : connectionsArray) {
- QJsonObject connObj = connValue.toObject();
- int startCol = connObj["startCol"].toInt();
- int startRow = connObj["startRow"].toInt();
- int endCol = connObj["endCol"].toInt();
- int endRow = connObj["endRow"].toInt();
-
- PLCItem *startItem = itemMap.value(qMakePair(startCol, startRow));
- PLCItem *endItem = itemMap.value(qMakePair(endCol, endRow));
-
- if (startItem && endItem && startItem != endItem) {
- ConnectionLine *line = new ConnectionLine(startItem, endItem);
- m_scene->addItem(line);
- m_connections.append(line);
- }
- }
-
- // 完成加载
- m_scene->blockSignals(false);
- handleSceneChanged(); // 手动触发位置更新
-
- // 更新UI状态
- setFilePath(filePath);
- setModified(false);
-
- qDebug() << "成功加载文件:" << filePath << "项目数:" << itemMap.size()
- << "连接数:" << m_connections.size();
-
- return true;
- }
- PLCItem* PLCDocument::createItemByType(PLCItem::ItemType type)
- {
- switch (type) {
- case PLCItem::NormallyOpen: return new NormallyOpenItem;
- case PLCItem::NormallyClosed: return new NormallyClosedItem;
- case PLCItem::GreaterThan: return new GreaterThanItem;
- case PLCItem::GreaterEqual: return new GreaterEqualItem;
- case PLCItem::LessThan: return new LessThanItem;
- case PLCItem::LessEqual: return new LessEqualItem;
- case PLCItem::Equal: return new EqualItem;
- case PLCItem::Coil: return new CoilItem;
- default:
- qWarning() << "未知的PLC元件类型:" << type;
- return nullptr;
- }
- }
- // ConnectionLine 实现
- ConnectionLine::ConnectionLine(PLCItem *start, PLCItem *end, QGraphicsItem *parent)
- : QGraphicsLineItem(parent), m_startItem(start), m_endItem(end)
- {
- setPen(QPen(Qt::black, 1));
- setZValue(-1);
- updatePosition();
- }
-
- void ConnectionLine::updatePosition()
- {
- if (m_startItem && m_endItem) {
- // 基于控件端子位置更新连线
- QLineF line(m_startItem->rightTerminal(), m_endItem->leftTerminal());
- setLine(line);
- }
- }
|