diff --git a/customgraphics.cpp b/customgraphics.cpp index 9a05ad1..d867b2f 100644 --- a/customgraphics.cpp +++ b/customgraphics.cpp @@ -86,6 +86,26 @@ void HmiComponent::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) QMenu menu; QAction *propertyAction = menu.addAction("属性"); + + QAction *setOnAction = nullptr; + QAction *setOffAction = nullptr; + + // 只有按钮才添加“置ON”和“置OFF” + if (auto btn = dynamic_cast(this)) { + setOnAction = menu.addAction("置ON"); + setOffAction = menu.addAction("置OFF"); + + connect(setOnAction, &QAction::triggered, this, [btn]() { + btn->setOn(true); + }); + + connect(setOffAction, &QAction::triggered, this, [btn]() { + btn->setOn(false); + }); + } + + menu.addSeparator(); + QAction *copyAction = menu.addAction("复制"); QAction *deleteAction = menu.addAction("删除"); @@ -278,7 +298,7 @@ QColor HmiComponent::offColor() const { } -HmiButton::HmiButton(QGraphicsItem *parent) : HmiComponent(parent) +HmiButton::HmiButton(QGraphicsItem *parent) : HmiComponent(parent), m_isOn(false) { m_color = Qt::gray; m_offColor = m_color; // OFF状态颜色设为默认颜色 @@ -287,6 +307,23 @@ HmiButton::HmiButton(QGraphicsItem *parent) : HmiComponent(parent) setColor(m_offColor); // 当前显示OFF颜色 } +bool HmiButton::isOn() const +{ + return m_isOn; +} + +void HmiButton::setOn(bool on) +{ + if (m_isOn != on) { + m_isOn = on; + if (m_isOn) + setColor(m_onColor); + else + setColor(m_offColor); + update(); + } +} + QRectF HmiButton::boundingRect() const { return QRectF(0, 0, 65, 30); diff --git a/customgraphics.h b/customgraphics.h index 9d7c434..93d1fb8 100644 --- a/customgraphics.h +++ b/customgraphics.h @@ -74,8 +74,15 @@ public: HmiButton(QGraphicsItem *parent = nullptr); QRectF boundingRect() const override; + // 新增状态标志,true = ON,false = OFF + bool isOn() const; + void setOn(bool on); + protected: void paintShape(QPainter *painter) override; + +private: + bool m_isOn = false; // 默认OFF }; // 指示灯类 diff --git a/hmimodule.cpp b/hmimodule.cpp index f5903d0..9ebd5b2 100644 --- a/hmimodule.cpp +++ b/hmimodule.cpp @@ -111,6 +111,11 @@ bool HMIModule::saveToFile(const QString& filePath) compObj["componentName"] = component->componentName(); // 新增地址属性 compObj["address"] = component->address(); + // 添加按钮状态 + compObj["isOn"] = false; // 默认false + if (auto btn = dynamic_cast(component)) { + compObj["isOn"] = btn->isOn(); + } componentsArray.append(compObj); } @@ -136,6 +141,8 @@ bool HMIModule::saveToFile(const QString& filePath) emit logMessageGenerated(QString("[%1] 保存成功: %2") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(filePath)); + m_isModified = false; + setModified(false); return true; } @@ -261,10 +268,18 @@ bool HMIModule::openFromFile(const QString& filePath) if (offColor.isValid()) newItem->setOffColor(offColor); + // 恢复 isOn 状态 + bool isOn = false; + if (compObj.contains("isOn")) { + isOn = compObj["isOn"].toBool(); + } + if (auto btn = dynamic_cast(newItem)) { + btn->setOn(isOn); + } + QColor currentColor(colorName); if (currentColor.isValid()) { - // 可以根据实际业务逻辑判断,是否恢复为onColor或offColor - // 这里直接恢复当前颜色 + // 根据实际业务逻辑判断,是否恢复为onColor或offColor,这里直接恢复当前颜色 newItem->setColor(currentColor); } else { // 如果当前颜色无效,则使用 offColor 作为默认颜色 @@ -288,9 +303,84 @@ bool HMIModule::openFromFile(const QString& filePath) emit logMessageGenerated(QString("[%1] 打开文件成功: %2") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(filePath)); + setModified(false); return true; } +void HMIModule::resetPages() +{ + QTabWidget* tabWidget = ui_->tabWidget_2; + + if (tabWidget->count() == 0) { + // 没有页面,创建第一页 + m_pageCount = 1; + m_availablePageNumbers.clear(); + m_pageOrder.clear(); + + QWidget* newPage = new QWidget(tabWidget); + QString pageName = QString("Page 1"); + 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); + + tabWidget->addTab(newPage, pageName); + + m_pageOrder.append(1); + + 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); + + return; + } + + // 有页面时: + // 删除除第一页以外的所有页面 + while (tabWidget->count() > 1) { + QWidget* page = tabWidget->widget(1); + tabWidget->removeTab(1); + delete page; + } + + // 清空第一页场景 + QWidget* firstPage = tabWidget->widget(0); + QGraphicsView* view = firstPage->findChild(); + if (view && view->scene()) { + view->scene()->clear(); + } + + // 重置页面编号管理 + m_availablePageNumbers.clear(); + m_pageOrder.clear(); + m_pageCount = 1; + m_pageOrder.append(1); + + // 可以选择更新第一页Tab名称(如果可能被改名) + tabWidget->setTabText(0, "Page 1"); + firstPage->setObjectName("Page 1"); +} + +bool HMIModule::isModified() const +{ + return m_isModified; +} + +void HMIModule::setModified(bool modified) +{ + m_isModified = modified; +} + void HMIModule::setupNewComponent(HmiComponent* item) { if (!item) return; @@ -338,6 +428,7 @@ void HMIModule::prepareToCreateIndicator() void HMIModule::onComponentCreated(HmiComponent* item) { setupNewComponent(item); + setModified(true); // 标记已修改 } void HMIModule::onCopyRequested() @@ -360,6 +451,13 @@ void HMIModule::onCopyRequested() m_copiedType = ComponentType::Indicator; } m_copiedColor = itemToCopy->color(); + + // 新增复制以下属性 + m_copiedOnColor = itemToCopy->onColor(); + m_copiedOffColor = itemToCopy->offColor(); + m_copiedComponentName = itemToCopy->componentName(); + m_copiedAddress = itemToCopy->address(); + m_hasCopiedItem = true; emit logMessageGenerated(QString("[%1] 复制组件: %2") @@ -386,10 +484,15 @@ void HMIModule::onPasteRequested(const QPointF& scenePos) if (newItem) { newItem->setColor(m_copiedColor); + newItem->setOnColor(m_copiedOnColor); + newItem->setOffColor(m_copiedOffColor); + newItem->setComponentName(m_copiedComponentName); + newItem->setAddress(m_copiedAddress); newItem->setPos(scenePos); currentScene->addItem(newItem); // 使用当前页面的 scene setupNewComponent(newItem); } + setModified(true); // 内容改变 } void HMIModule::onDeleteRequested() @@ -412,6 +515,7 @@ void HMIModule::onDeleteRequested() currentScene->removeItem(item); // 使用当前页面的 scene delete item; } + setModified(true); // 标记已修改 } @@ -533,6 +637,7 @@ void HMIModule::addPage() // 记录日志 emit logMessageGenerated(QString("[%1] 添加页面: %2").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(pageName)); + setModified(true); // 页面变更,标记已修改 } // 删除页面的槽函数 @@ -570,6 +675,7 @@ void HMIModule::deletePage() // 记录日志 emit logMessageGenerated(QString("[%1] 删除页面: %2").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(pageName)); } + setModified(true); // 标记已修改 } // 前一页的槽函数 diff --git a/hmimodule.h b/hmimodule.h index ae28dc2..d6fa741 100644 --- a/hmimodule.h +++ b/hmimodule.h @@ -17,6 +17,10 @@ public: void init(); bool saveToFile(const QString& filePath); bool openFromFile(const QString& filePath); + // 重置页面,清空所有页,只保留一个空的第一页 + void resetPages(); + bool isModified() const; // 判断是否有未保存的修改 + void setModified(bool modified); // 设置修改状态 signals: void pageAdded(int pageNumber, int index); @@ -48,10 +52,17 @@ private: CustomGraphicsScene* m_scene; ComponentType m_copiedType; QColor m_copiedColor; + // 新增这些成员变量 + QColor m_copiedOnColor; + QColor m_copiedOffColor; + QString m_copiedComponentName; + int m_copiedAddress = 0; + bool m_hasCopiedItem = false; // 指示当前是否已经有组件被复制 int m_pageCount = 1; // 初始化页面计数器 QList m_availablePageNumbers; // 存储可用的页面编号 (有序列表) QList m_pageOrder; // 维护页面顺序 + bool m_isModified = false; // 添加一个修改标志变量 }; #endif // HMIMODULE_H diff --git a/mainwindow.cpp b/mainwindow.cpp index 000da13..6f5e0f0 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -5,6 +5,7 @@ #include #include #include +#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -18,8 +19,11 @@ MainWindow::MainWindow(QWidget *parent) // 连接 HMIModule 的信号到 MainWindow 的槽 connect(hmi_, &HMIModule::logMessageGenerated, this, &MainWindow::appendLog); + // 新建菜单 + connect(ui_->action, &QAction::triggered, this, &MainWindow::onNewFile); + connect(ui_->action_3, &QAction::triggered, this, [this]() { - QString fileName = QFileDialog::getSaveFileName(this, "保存HMI设计", "", "JSON文件 (*.json)"); + QString fileName = QFileDialog::getSaveFileName(this, "保存HMI文件", "", "JSON文件 (*.hmi)"); if (!fileName.isEmpty()) { if (!hmi_->saveToFile(fileName)) { QMessageBox::warning(this, "保存失败", "文件保存失败!"); @@ -28,7 +32,7 @@ MainWindow::MainWindow(QWidget *parent) }); connect(ui_->action_2, &QAction::triggered, this, [this]() { - QString fileName = QFileDialog::getOpenFileName(this, "打开HMI设计", "", "JSON文件 (*.json)"); + QString fileName = QFileDialog::getOpenFileName(this, "打开HMI文件", "", "JSON文件 (*.hmi)"); if (!fileName.isEmpty()) { if (!hmi_->openFromFile(fileName)) { QMessageBox::warning(this, "打开失败", "文件打开失败或格式不正确!"); @@ -46,6 +50,8 @@ void MainWindow::initMainWindow() { setWindowTitle("综合平台编辑器"); setWindowIcon(QIcon(":/resource/image/editor.png")); + // 运行默认打开HMI页面 + ui_->tabWidget->setCurrentIndex(1); } // 实现槽函数 @@ -53,3 +59,36 @@ void MainWindow::appendLog(const QString& message) { ui_->textEdit->append(message); } + +// 新建菜单动作槽函数 +void MainWindow::onNewFile() +{ + if (!hmi_) + return; + + if (hmi_->isModified()) { + auto ret = QMessageBox::warning(this, "提示", + "当前文件有未保存的更改,是否保存?", + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, + QMessageBox::Save); + + if (ret == QMessageBox::Save) { + QString fileName = QFileDialog::getSaveFileName(this, "保存HMI设计", "", "JSON文件 (*.json)"); + if (!fileName.isEmpty()) { + if (!hmi_->saveToFile(fileName)) { + QMessageBox::warning(this, "保存失败", "文件保存失败!"); + return; // 不新建,保存失败 + } + } else { + return; // 取消保存,取消新建 + } + } else if (ret == QMessageBox::Cancel) { + return; // 取消新建 + } + // 如果是Discard,直接继续新建,丢弃当前修改 + } + + // 清空编辑区,新建页面 + hmi_->resetPages(); +} + diff --git a/mainwindow.h b/mainwindow.h index f53f325..32cab95 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -21,12 +21,13 @@ public: private: void initMainWindow(); - // 一个用于接收日志并更新UI的槽函数 private slots: void appendLog(const QString& message); + void onNewFile(); // 新增槽函数,处理“新建”菜单 private: Ui::MainWindow *ui_; HMIModule* hmi_; }; + #endif // MAINWINDOW_H