#include "hmimodule.h" #include #include #include #include #include #include #include #include #include #include #include #include #include HMIModule::HMIModule(Ui::MainWindow* ui, QObject *parent) : QObject{parent}, ui_(ui), m_scene(nullptr) { // 初始化 m_pageOrder m_pageOrder.append(1); // 初始页面 } void HMIModule::setButtonIcon(QAbstractButton *button, const QString &iconPath) { button->setIcon(QIcon(iconPath)); button->setIconSize(QSize(30, 30)); } void HMIModule::init() { setButtonIcon(ui_->button, ":/resource/image/button.png"); setButtonIcon(ui_->lamp, ":/resource/image/lamp.png"); setButtonIcon(ui_->addPage, ":/resource/image/add.png"); setButtonIcon(ui_->deletePage, ":/resource/image/delete.png"); setButtonIcon(ui_->prePage, ":/resource/image/pre.png"); setButtonIcon(ui_->nextPage, ":/resource/image/next.png"); if (!ui_->hmiGraphicsView->scene()) { m_scene = new CustomGraphicsScene(ui_->hmiGraphicsView, this); m_scene->setSceneRect(0, 0, 800, 600); ui_->hmiGraphicsView->setScene(m_scene); } else { m_scene = qobject_cast(ui_->hmiGraphicsView->scene()); Q_ASSERT(m_scene); } connect(ui_->button, &QPushButton::clicked, this, &HMIModule::prepareToCreateButton); connect(ui_->lamp, &QPushButton::clicked, this, &HMIModule::prepareToCreateIndicator); connect(m_scene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated); connect(m_scene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested); connect(m_scene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested); connect(m_scene, &CustomGraphicsScene::deleteRequestFromScene, this, &HMIModule::onDeleteRequested); // 连接新增的槽函数 connect(ui_->addPage, &QPushButton::clicked, this, &HMIModule::addPage); connect(ui_->deletePage, &QPushButton::clicked, this, &HMIModule::deletePage); connect(ui_->prePage, &QPushButton::clicked, this, &HMIModule::prePage); connect(ui_->nextPage, &QPushButton::clicked, this, &HMIModule::nextPage); // 连接信号和槽 connect(this, &HMIModule::pageAdded, this, &HMIModule::onPageAdded); connect(this, &HMIModule::pageRemoved, this, &HMIModule::onPageRemoved); } bool HMIModule::saveToFile(const QString& filePath) { QTabWidget* tabWidget = ui_->tabWidget_2; QJsonArray pagesArray; for (int i = 0; i < tabWidget->count(); ++i) { QWidget* page = tabWidget->widget(i); QString pageName = tabWidget->tabText(i); QGraphicsView* graphicsView = page->findChild(); if (!graphicsView) continue; QGraphicsScene* scene = graphicsView->scene(); if (!scene) continue; QJsonObject pageObject; pageObject["pageName"] = pageName; QJsonArray componentsArray; for (QGraphicsItem* item : scene->items()) { HmiComponent* component = dynamic_cast(item); if (!component) continue; QJsonObject compObj; // 组件类型 if (dynamic_cast(component)) { compObj["type"] = "Button"; } else if (dynamic_cast(component)) { compObj["type"] = "Indicator"; } else { continue; // 忽略未知类型 } // 位置 QPointF pos = component->pos(); compObj["x"] = pos.x(); compObj["y"] = pos.y(); // 颜色 (保存在HEX) compObj["color"] = component->color().name(); // On / Off颜色 compObj["onColor"] = component->onColor().name(); compObj["offColor"] = component->offColor().name(); // 组件名称 compObj["componentName"] = component->componentName(); // 新增地址属性 compObj["address"] = component->address(); componentsArray.append(compObj); } pageObject["components"] = componentsArray; pagesArray.append(pageObject); } QJsonObject rootObject; rootObject["pages"] = pagesArray; QJsonDocument doc(rootObject); QFile file(filePath); if (!file.open(QIODevice::WriteOnly)) { emit logMessageGenerated(QString("无法打开文件进行保存: %1").arg(filePath)); return false; } file.write(doc.toJson(QJsonDocument::Indented)); file.close(); emit logMessageGenerated(QString("[%1] 保存成功: %2") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(filePath)); return true; } // 清空所有页面,重建页面并加载组件 bool HMIModule::openFromFile(const QString& filePath) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { emit logMessageGenerated(QString("无法打开文件进行加载: %1").arg(filePath)); return false; } QByteArray data = file.readAll(); file.close(); QJsonParseError parseError; QJsonDocument doc = QJsonDocument::fromJson(data, &parseError); if (parseError.error != QJsonParseError::NoError) { emit logMessageGenerated(QString("JSON解析错误: %1").arg(parseError.errorString())); return false; } if (!doc.isObject()) { emit logMessageGenerated("JSON格式错误,不是对象"); return false; } QJsonObject rootObj = doc.object(); if (!rootObj.contains("pages") || !rootObj["pages"].isArray()) { emit logMessageGenerated("JSON缺少pages数组"); return false; } QJsonArray pagesArray = rootObj["pages"].toArray(); QTabWidget* tabWidget = ui_->tabWidget_2; // 清空所有现有页面 while (tabWidget->count() > 0) { QWidget* page = tabWidget->widget(0); tabWidget->removeTab(0); delete page; } m_availablePageNumbers.clear(); m_pageOrder.clear(); for (const QJsonValue& pageVal : pagesArray) { if (!pageVal.isObject()) continue; QJsonObject pageObj = pageVal.toObject(); QString pageName = pageObj["pageName"].toString("Unnamed"); int pageNumber = 0; if (pageName.startsWith("Page ")) { pageNumber = pageName.mid(5).toInt(); } // 新建页面 QWidget* newPage = new QWidget(tabWidget); newPage->setObjectName(pageName); QGraphicsView* newGraphicsView = new QGraphicsView(newPage); CustomGraphicsScene* newScene = new CustomGraphicsScene(newGraphicsView, this); // 设置大小,与默认页面相同 QSize defaultSize(691, 381); newGraphicsView->resize(defaultSize); newScene->setSceneRect(0, 0, 800, 600); newGraphicsView->setScene(newScene); QVBoxLayout* layout = new QVBoxLayout(newPage); layout->addWidget(newGraphicsView); newPage->setLayout(layout); int tabIndex = tabWidget->addTab(newPage, pageName); // 连接信号 connect(newScene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated); connect(newScene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested); connect(newScene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested); connect(newScene, &CustomGraphicsScene::deleteRequestFromScene, this, &HMIModule::onDeleteRequested); m_pageOrder.append(pageNumber); QJsonArray compArray = pageObj["components"].toArray(); for (const QJsonValue& compVal : compArray) { if (!compVal.isObject()) continue; QJsonObject compObj = compVal.toObject(); QString typeStr = compObj["type"].toString(); double x = compObj["x"].toDouble(); double y = compObj["y"].toDouble(); QString colorName = compObj["color"].toString(); QString onColorName = compObj["onColor"].toString(); QString offColorName = compObj["offColor"].toString(); QString componentName = compObj["componentName"].toString(); int address = compObj["address"].toInt(0); HmiComponent* newItem = nullptr; if (typeStr == "Button") { newItem = new HmiButton(); } else if (typeStr == "Indicator") { newItem = new HmiIndicator(); } else { continue; } if (newItem) { newItem->setPos(QPointF(x, y)); QColor color(colorName); if (color.isValid()) { newItem->setColor(color); } QColor onColor(onColorName); if (onColor.isValid()) newItem->setOnColor(onColor); QColor offColor(offColorName); if (offColor.isValid()) newItem->setOffColor(offColor); QColor currentColor(colorName); if (currentColor.isValid()) { // 可以根据实际业务逻辑判断,是否恢复为onColor或offColor // 这里直接恢复当前颜色 newItem->setColor(currentColor); } else { // 如果当前颜色无效,则使用 offColor 作为默认颜色 newItem->setColor(newItem->offColor()); } newItem->setComponentName(componentName); // 设置地址 newItem->setAddress(address); newScene->addItem(newItem); setupNewComponent(newItem); } } } // 自动切换到第一页 if (tabWidget->count() > 0) { tabWidget->setCurrentIndex(0); } emit logMessageGenerated(QString("[%1] 打开文件成功: %2") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(filePath)); return true; } void HMIModule::setupNewComponent(HmiComponent* item) { if (!item) return; connect(item, &HmiComponent::selected, this, &HMIModule::onComponentSelected); connect(item, &HmiComponent::copyRequested, this, &HMIModule::onCopyRequested); connect(item, &HmiComponent::deleteRequested, this, &HMIModule::onDeleteRequested); connect(item, &HmiComponent::changeOnColorRequested, this, &HMIModule::onChangeOnColorRequested); connect(item, &HmiComponent::changeOffColorRequested, this, &HMIModule::onChangeOffColorRequested); QString currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); QString log = QString("[%1] 创建 %2 组件").arg(currentTime).arg(item->componentName()); emit logMessageGenerated(log); } void HMIModule::prepareToCreateButton() { // 获取当前 TabWidget 中选中的 GraphicsView QTabWidget* tabWidget = ui_->tabWidget_2; QWidget* currentPage = tabWidget->currentWidget(); QGraphicsView* currentGraphicsView = currentPage->findChild(); CustomGraphicsScene* currentScene = qobject_cast(currentGraphicsView->scene()); if (currentScene) { currentScene->setComponentTypeToCreate(ComponentType::Button); currentScene->setMode(CustomGraphicsScene::Mode::CreateItem); } } void HMIModule::prepareToCreateIndicator() { // 获取当前 TabWidget 中选中的 GraphicsView QTabWidget* tabWidget = ui_->tabWidget_2; QWidget* currentPage = tabWidget->currentWidget(); QGraphicsView* currentGraphicsView = currentPage->findChild(); CustomGraphicsScene* currentScene = qobject_cast(currentGraphicsView->scene()); if (currentScene) { currentScene->setComponentTypeToCreate(ComponentType::Indicator); currentScene->setMode(CustomGraphicsScene::Mode::CreateItem); } } void HMIModule::onComponentCreated(HmiComponent* item) { setupNewComponent(item); } void HMIModule::onCopyRequested() { // 获取当前 TabWidget 中选中的 GraphicsView QTabWidget* tabWidget = ui_->tabWidget_2; QWidget* currentPage = tabWidget->currentWidget(); QGraphicsView* currentGraphicsView = currentPage->findChild(); CustomGraphicsScene* currentScene = qobject_cast(currentGraphicsView->scene()); QList selected = currentScene->selectedItems(); if (selected.isEmpty()) return; HmiComponent* itemToCopy = qgraphicsitem_cast(selected.first()); if (!itemToCopy) return; if (dynamic_cast(itemToCopy)) { m_copiedType = ComponentType::Button; } else if (dynamic_cast(itemToCopy)) { m_copiedType = ComponentType::Indicator; } m_copiedColor = itemToCopy->color(); m_hasCopiedItem = true; emit logMessageGenerated(QString("[%1] 复制组件: %2") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(itemToCopy->componentName())); } void HMIModule::onPasteRequested(const QPointF& scenePos) { if (!m_hasCopiedItem) return; // 获取当前 TabWidget 中选中的 GraphicsView QTabWidget* tabWidget = ui_->tabWidget_2; QWidget* currentPage = tabWidget->currentWidget(); QGraphicsView* currentGraphicsView = currentPage->findChild(); CustomGraphicsScene* currentScene = qobject_cast(currentGraphicsView->scene()); HmiComponent* newItem = nullptr; if (m_copiedType == ComponentType::Button) { newItem = new HmiButton(); } else { newItem = new HmiIndicator(); } if (newItem) { newItem->setColor(m_copiedColor); newItem->setPos(scenePos); currentScene->addItem(newItem); // 使用当前页面的 scene setupNewComponent(newItem); } } void HMIModule::onDeleteRequested() { // 获取当前 TabWidget 中选中的 GraphicsView QTabWidget* tabWidget = ui_->tabWidget_2; QWidget* currentPage = tabWidget->currentWidget(); QGraphicsView* currentGraphicsView = currentPage->findChild(); CustomGraphicsScene* currentScene = qobject_cast(currentGraphicsView->scene()); QList selected = currentScene->selectedItems(); if (selected.isEmpty()) return; emit logMessageGenerated(QString("[%1] 删除 %2 个组件") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(selected.count())); for (int i = selected.count() - 1; i >= 0; --i) { QGraphicsItem* item = selected.at(i); currentScene->removeItem(item); // 使用当前页面的 scene delete item; } } // 添加页面后的槽函数 void HMIModule::onPageAdded(int pageNumber, int index) { if (index < m_pageOrder.size()) { m_pageOrder[index] = pageNumber; } else { m_pageOrder.append(pageNumber); } } // 删除页面后的槽函数 void HMIModule::onPageRemoved(int pageNumber, int index) { if (index < m_pageOrder.size()) { m_pageOrder[index] = -1; } } void HMIModule::onChangeOnColorRequested(HmiComponent* item) { QColor color = QColorDialog::getColor(item->onColor(), nullptr, "选择 ON 状态颜色"); if (color.isValid()) { item->setOnColor(color); emit logMessageGenerated(QString("[%1] 设置 %2 的 ON 状态颜色为 %3") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(item->componentName()) .arg(color.name())); } } void HMIModule::onChangeOffColorRequested(HmiComponent* item) { QColor color = QColorDialog::getColor(item->offColor(), nullptr, "选择 OFF 状态颜色"); if (color.isValid()) { item->setOffColor(color); // 同时更新当前显示颜色 emit logMessageGenerated(QString("[%1] 设置 %2 的 OFF 状态颜色为 %3") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(item->componentName()) .arg(color.name())); } } void HMIModule::onComponentSelected(HmiComponent* item) { // 不需要任何操作,可以留空 } // 新增页面的槽函数 void HMIModule::addPage() { QTabWidget* tabWidget = ui_->tabWidget_2; int pageNumber; int insertIndex = -1; int tabIndex; // 在此处声明 tabIndex // 检查是否有可用的页面编号 if (!m_availablePageNumbers.isEmpty()) { pageNumber = m_availablePageNumbers.first(); m_availablePageNumbers.removeFirst(); // 查找可用的插入位置 for (int i = 0; i < m_pageOrder.size(); ++i) { if (m_pageOrder[i] == -1) { insertIndex = i; break; } } } else { pageNumber = ++m_pageCount; } // 获取 Page 1 的 Scene CustomGraphicsScene* firstScene = m_scene; // 创建新的页面部件 QWidget* newPage = new QWidget(tabWidget); QString pageName = QString("Page %1").arg(pageNumber); newPage->setObjectName(pageName); // 创建新的 GraphicsView 和 Scene QGraphicsView* newGraphicsView = new QGraphicsView(newPage); CustomGraphicsScene* newScene = new CustomGraphicsScene(newGraphicsView, this); // 设置 GraphicsView 的大小 QSize newViewSize(691, 381); // 设置为指定的宽度和高度 newGraphicsView->resize(newViewSize); // 设置 GraphicsScene 的大小与 Page 1 相同 QRectF newSceneRect = firstScene->sceneRect(); newScene->setSceneRect(newSceneRect); newGraphicsView->setScene(newScene); // 布局 QVBoxLayout* layout = new QVBoxLayout(newPage); layout->addWidget(newGraphicsView); newPage->setLayout(layout); // 添加到 TabWidget if (insertIndex != -1) { tabIndex = insertIndex; tabWidget->insertTab(tabIndex, newPage, pageName); } else { tabIndex = tabWidget->addTab(newPage, pageName); } // 连接信号和槽 connect(newScene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated); connect(newScene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested); connect(newScene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested); connect(newScene, &CustomGraphicsScene::deleteRequestFromScene, this, &HMIModule::onDeleteRequested); // 发送 pageAdded 信号 emit pageAdded(pageNumber, tabIndex); tabWidget->setCurrentWidget(newPage); // 记录日志 emit logMessageGenerated(QString("[%1] 添加页面: %2").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(pageName)); } // 删除页面的槽函数 void HMIModule::deletePage() { QTabWidget* tabWidget = ui_->tabWidget_2; int currentIndex = tabWidget->currentIndex(); if (tabWidget->count() == 1) { QMessageBox::information(nullptr, "提示", "这是最后一页,不能删除!"); return; } if (currentIndex >= 0) { // 获取要删除的页面 QWidget* currentPage = tabWidget->widget(currentIndex); QString pageName = tabWidget->tabText(currentIndex); // 从页面名称中提取页面编号 int pageNumber = pageName.remove("Page ").toInt(); // 将删除的页面编号添加到可用列表中 m_availablePageNumbers.append(pageNumber); std::sort(m_availablePageNumbers.begin(), m_availablePageNumbers.end()); // 从 TabWidget 中移除页面 tabWidget->removeTab(currentIndex); // 删除页面 delete currentPage; // 发送 pageRemoved 信号 emit pageRemoved(pageNumber, currentIndex); // 记录日志 emit logMessageGenerated(QString("[%1] 删除页面: %2").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(pageName)); } } // 前一页的槽函数 void HMIModule::prePage() { QTabWidget* tabWidget = ui_->tabWidget_2; int currentIndex = tabWidget->currentIndex(); if (currentIndex > 0) { tabWidget->setCurrentIndex(currentIndex - 1); } } // 后一页的槽函数 void HMIModule::nextPage() { QTabWidget* tabWidget = ui_->tabWidget_2; int currentIndex = tabWidget->currentIndex(); if (currentIndex < tabWidget->count() - 1) { tabWidget->setCurrentIndex(currentIndex + 1); } }