@@ -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<HmiButton*>(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); | |||
@@ -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 | |||
}; | |||
// 指示灯类 | |||
@@ -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<HmiButton*>(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<HmiButton*>(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<QGraphicsView*>(); | |||
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); // 标记已修改 | |||
} | |||
// 前一页的槽函数 | |||
@@ -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<int> m_availablePageNumbers; // 存储可用的页面编号 (有序列表) | |||
QList<int> m_pageOrder; // 维护页面顺序 | |||
bool m_isModified = false; // 添加一个修改标志变量 | |||
}; | |||
#endif // HMIMODULE_H |
@@ -5,6 +5,7 @@ | |||
#include <QButtonGroup> | |||
#include <QFileDialog> | |||
#include <QMessageBox> | |||
#include <QCloseEvent> | |||
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(); | |||
} | |||
@@ -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 |