综合平台编辑器
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

760 satır
26 KiB

  1. #include "hmimodule.h"
  2. #include <QGraphicsScene>
  3. #include <QGraphicsView>
  4. #include <QDateTime>
  5. #include <QTabWidget>
  6. #include <QMessageBox>
  7. #include <QVBoxLayout>
  8. #include <algorithm>
  9. #include <QColorDialog>
  10. #include <QFile>
  11. #include <QJsonDocument>
  12. #include <QJsonArray>
  13. #include <QJsonObject>
  14. #include <QDebug>
  15. HMIModule::HMIModule(Ui::MainWindow* ui, QObject *parent)
  16. : QObject{parent}, ui_(ui), m_scene(nullptr), m_modbusManager(new ModbusManager(this))
  17. {
  18. // 初始化 m_pageOrder
  19. m_pageOrder.append(1); // 初始页面
  20. // 接收 Modbus 更新
  21. connect(m_modbusManager, &ModbusManager::coilUpdated, this, [this](int address, bool value){
  22. updateComponentsByAddress(address, value);
  23. });
  24. // 接收日志
  25. connect(m_modbusManager, &ModbusManager::logMessage, this, &HMIModule::logMessageGenerated);
  26. }
  27. void HMIModule::setButtonIcon(QAbstractButton *button, const QString &iconPath)
  28. {
  29. button->setIcon(QIcon(iconPath));
  30. button->setIconSize(QSize(30, 30));
  31. }
  32. void HMIModule::init() {
  33. setButtonIcon(ui_->button, ":/resource/image/button.png");
  34. setButtonIcon(ui_->lamp, ":/resource/image/lamp.png");
  35. setButtonIcon(ui_->addPage, ":/resource/image/add.png");
  36. setButtonIcon(ui_->deletePage, ":/resource/image/delete.png");
  37. setButtonIcon(ui_->prePage, ":/resource/image/pre.png");
  38. setButtonIcon(ui_->nextPage, ":/resource/image/next.png");
  39. if (!ui_->hmiGraphicsView->scene()) {
  40. m_scene = new CustomGraphicsScene(ui_->hmiGraphicsView, this);
  41. m_scene->setSceneRect(0, 0, 800, 600);
  42. ui_->hmiGraphicsView->setScene(m_scene);
  43. } else {
  44. m_scene = qobject_cast<CustomGraphicsScene*>(ui_->hmiGraphicsView->scene());
  45. Q_ASSERT(m_scene);
  46. }
  47. connect(ui_->button, &QPushButton::clicked, this, &HMIModule::prepareToCreateButton);
  48. connect(ui_->lamp, &QPushButton::clicked, this, &HMIModule::prepareToCreateIndicator);
  49. connect(m_scene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated);
  50. connect(m_scene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested);
  51. connect(m_scene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested);
  52. connect(m_scene, &CustomGraphicsScene::deleteRequestFromScene, this, &HMIModule::onDeleteRequested);
  53. // 连接新增的槽函数
  54. connect(ui_->addPage, &QPushButton::clicked, this, &HMIModule::addPage);
  55. connect(ui_->deletePage, &QPushButton::clicked, this, &HMIModule::deletePage);
  56. connect(ui_->prePage, &QPushButton::clicked, this, &HMIModule::prePage);
  57. connect(ui_->nextPage, &QPushButton::clicked, this, &HMIModule::nextPage);
  58. // 连接信号和槽
  59. connect(this, &HMIModule::pageAdded, this, &HMIModule::onPageAdded);
  60. connect(this, &HMIModule::pageRemoved, this, &HMIModule::onPageRemoved);
  61. }
  62. bool HMIModule::saveToFile(const QString& filePath)
  63. {
  64. QTabWidget* tabWidget = ui_->tabWidget_2;
  65. QJsonArray pagesArray;
  66. for (int i = 0; i < tabWidget->count(); ++i) {
  67. QWidget* page = tabWidget->widget(i);
  68. QString pageName = tabWidget->tabText(i);
  69. QGraphicsView* graphicsView = page->findChild<QGraphicsView*>();
  70. if (!graphicsView) continue;
  71. QGraphicsScene* scene = graphicsView->scene();
  72. if (!scene) continue;
  73. QJsonObject pageObject;
  74. pageObject["pageName"] = pageName;
  75. QJsonArray componentsArray;
  76. for (QGraphicsItem* item : scene->items()) {
  77. HmiComponent* component = dynamic_cast<HmiComponent*>(item);
  78. if (!component)
  79. continue;
  80. QJsonObject compObj;
  81. // 组件类型
  82. if (dynamic_cast<HmiButton*>(component)) {
  83. compObj["type"] = "Button";
  84. } else if (dynamic_cast<HmiIndicator*>(component)) {
  85. compObj["type"] = "Indicator";
  86. } else {
  87. continue; // 忽略未知类型
  88. }
  89. // 位置
  90. QPointF pos = component->pos();
  91. compObj["x"] = pos.x();
  92. compObj["y"] = pos.y();
  93. // 颜色 (保存在HEX)
  94. compObj["color"] = component->color().name();
  95. // On / Off颜色
  96. compObj["onColor"] = component->onColor().name();
  97. compObj["offColor"] = component->offColor().name();
  98. // 组件名称
  99. compObj["componentName"] = component->componentName();
  100. // 新增地址属性
  101. compObj["address"] = component->address();
  102. // 添加按钮状态
  103. compObj["isOn"] = false; // 默认false
  104. // 保存尺寸
  105. compObj["width"] = component->boundingRect().width();
  106. compObj["height"] = component->boundingRect().height();
  107. if (auto btn = dynamic_cast<HmiButton*>(component)) {
  108. compObj["isOn"] = btn->isOn();
  109. }
  110. componentsArray.append(compObj);
  111. }
  112. pageObject["components"] = componentsArray;
  113. pagesArray.append(pageObject);
  114. }
  115. QJsonObject rootObject;
  116. rootObject["pages"] = pagesArray;
  117. QJsonDocument doc(rootObject);
  118. QFile file(filePath);
  119. if (!file.open(QIODevice::WriteOnly)) {
  120. emit logMessageGenerated(QString("无法打开文件进行保存: %1").arg(filePath));
  121. return false;
  122. }
  123. file.write(doc.toJson(QJsonDocument::Indented));
  124. file.close();
  125. emit logMessageGenerated(QString("[%1] 保存成功: %2")
  126. .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
  127. .arg(filePath));
  128. m_isModified = false;
  129. setModified(false);
  130. return true;
  131. }
  132. // 清空所有页面,重建页面并加载组件
  133. bool HMIModule::openFromFile(const QString& filePath)
  134. {
  135. QFile file(filePath);
  136. if (!file.open(QIODevice::ReadOnly)) {
  137. emit logMessageGenerated(QString("无法打开文件进行加载: %1").arg(filePath));
  138. return false;
  139. }
  140. QByteArray data = file.readAll();
  141. file.close();
  142. QJsonParseError parseError;
  143. QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
  144. if (parseError.error != QJsonParseError::NoError) {
  145. emit logMessageGenerated(QString("JSON解析错误: %1").arg(parseError.errorString()));
  146. return false;
  147. }
  148. if (!doc.isObject()) {
  149. emit logMessageGenerated("JSON格式错误,不是对象");
  150. return false;
  151. }
  152. QJsonObject rootObj = doc.object();
  153. if (!rootObj.contains("pages") || !rootObj["pages"].isArray()) {
  154. emit logMessageGenerated("JSON缺少pages数组");
  155. return false;
  156. }
  157. QJsonArray pagesArray = rootObj["pages"].toArray();
  158. QTabWidget* tabWidget = ui_->tabWidget_2;
  159. // 清空所有现有页面
  160. while (tabWidget->count() > 0) {
  161. QWidget* page = tabWidget->widget(0);
  162. tabWidget->removeTab(0);
  163. delete page;
  164. }
  165. m_availablePageNumbers.clear();
  166. m_pageOrder.clear();
  167. for (const QJsonValue& pageVal : pagesArray) {
  168. if (!pageVal.isObject())
  169. continue;
  170. QJsonObject pageObj = pageVal.toObject();
  171. QString pageName = pageObj["pageName"].toString("Unnamed");
  172. int pageNumber = 0;
  173. if (pageName.startsWith("Page ")) {
  174. pageNumber = pageName.mid(5).toInt();
  175. }
  176. // 新建页面
  177. QWidget* newPage = new QWidget(tabWidget);
  178. newPage->setObjectName(pageName);
  179. QGraphicsView* newGraphicsView = new QGraphicsView(newPage);
  180. CustomGraphicsScene* newScene = new CustomGraphicsScene(newGraphicsView, this);
  181. // 设置大小,与默认页面相同
  182. QSize defaultSize(691, 381);
  183. newGraphicsView->resize(defaultSize);
  184. newScene->setSceneRect(0, 0, 800, 600);
  185. newGraphicsView->setScene(newScene);
  186. QVBoxLayout* layout = new QVBoxLayout(newPage);
  187. layout->addWidget(newGraphicsView);
  188. newPage->setLayout(layout);
  189. int tabIndex = tabWidget->addTab(newPage, pageName);
  190. // 连接信号
  191. connect(newScene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated);
  192. connect(newScene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested);
  193. connect(newScene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested);
  194. connect(newScene, &CustomGraphicsScene::deleteRequestFromScene, this, &HMIModule::onDeleteRequested);
  195. m_pageOrder.append(pageNumber);
  196. QJsonArray compArray = pageObj["components"].toArray();
  197. for (const QJsonValue& compVal : compArray) {
  198. if (!compVal.isObject())
  199. continue;
  200. QJsonObject compObj = compVal.toObject();
  201. QString typeStr = compObj["type"].toString();
  202. double x = compObj["x"].toDouble();
  203. double y = compObj["y"].toDouble();
  204. QString colorName = compObj["color"].toString();
  205. QString onColorName = compObj["onColor"].toString();
  206. QString offColorName = compObj["offColor"].toString();
  207. QString componentName = compObj["componentName"].toString();
  208. int address = compObj["address"].toInt(0);
  209. HmiComponent* newItem = nullptr;
  210. if (typeStr == "Button") {
  211. newItem = new HmiButton();
  212. } else if (typeStr == "Indicator") {
  213. newItem = new HmiIndicator();
  214. } else {
  215. continue;
  216. }
  217. // 加载尺寸
  218. double width = compObj["width"].toDouble(65); // 默认值
  219. double height = compObj["height"].toDouble(30); // 默认值
  220. if (newItem) {
  221. // 设置尺寸
  222. newItem->setSize(width, height);
  223. newItem->setPos(QPointF(x, y));
  224. QColor color(colorName);
  225. if (color.isValid()) {
  226. newItem->setColor(color);
  227. }
  228. QColor onColor(onColorName);
  229. if (onColor.isValid())
  230. newItem->setOnColor(onColor);
  231. QColor offColor(offColorName);
  232. if (offColor.isValid())
  233. newItem->setOffColor(offColor);
  234. // 恢复 isOn 状态
  235. bool isOn = false;
  236. if (compObj.contains("isOn")) {
  237. isOn = compObj["isOn"].toBool();
  238. }
  239. if (auto btn = dynamic_cast<HmiButton*>(newItem)) {
  240. btn->setOn(isOn);
  241. }
  242. QColor currentColor(colorName);
  243. if (currentColor.isValid()) {
  244. // 根据实际业务逻辑判断,是否恢复为onColor或offColor,这里直接恢复当前颜色
  245. newItem->setColor(currentColor);
  246. } else {
  247. // 如果当前颜色无效,则使用 offColor 作为默认颜色
  248. newItem->setColor(newItem->offColor());
  249. }
  250. newItem->setComponentName(componentName);
  251. // 设置地址
  252. newItem->setAddress(address);
  253. newScene->addItem(newItem);
  254. setupNewComponent(newItem);
  255. }
  256. }
  257. }
  258. // 自动切换到第一页
  259. if (tabWidget->count() > 0) {
  260. tabWidget->setCurrentIndex(0);
  261. }
  262. emit logMessageGenerated(QString("[%1] 打开文件成功: %2")
  263. .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
  264. .arg(filePath));
  265. setModified(false);
  266. return true;
  267. }
  268. void HMIModule::resetPages()
  269. {
  270. QTabWidget* tabWidget = ui_->tabWidget_2;
  271. if (tabWidget->count() == 0) {
  272. // 没有页面,创建第一页
  273. m_pageCount = 1;
  274. m_availablePageNumbers.clear();
  275. m_pageOrder.clear();
  276. QWidget* newPage = new QWidget(tabWidget);
  277. QString pageName = QString("Page 1");
  278. newPage->setObjectName(pageName);
  279. QGraphicsView* newGraphicsView = new QGraphicsView(newPage);
  280. CustomGraphicsScene* newScene = new CustomGraphicsScene(newGraphicsView, this);
  281. QSize defaultSize(691, 381);
  282. newGraphicsView->resize(defaultSize);
  283. newScene->setSceneRect(0, 0, 800, 600);
  284. newGraphicsView->setScene(newScene);
  285. QVBoxLayout* layout = new QVBoxLayout(newPage);
  286. layout->addWidget(newGraphicsView);
  287. newPage->setLayout(layout);
  288. tabWidget->addTab(newPage, pageName);
  289. m_pageOrder.append(1);
  290. connect(newScene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated);
  291. connect(newScene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested);
  292. connect(newScene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested);
  293. connect(newScene, &CustomGraphicsScene::deleteRequestFromScene, this, &HMIModule::onDeleteRequested);
  294. return;
  295. }
  296. // 有页面时:
  297. // 删除除第一页以外的所有页面
  298. while (tabWidget->count() > 1) {
  299. QWidget* page = tabWidget->widget(1);
  300. tabWidget->removeTab(1);
  301. delete page;
  302. }
  303. // 清空第一页场景
  304. QWidget* firstPage = tabWidget->widget(0);
  305. QGraphicsView* view = firstPage->findChild<QGraphicsView*>();
  306. if (view && view->scene()) {
  307. view->scene()->clear();
  308. }
  309. // 重置页面编号管理
  310. m_availablePageNumbers.clear();
  311. m_pageOrder.clear();
  312. m_pageCount = 1;
  313. m_pageOrder.append(1);
  314. // 可以选择更新第一页Tab名称(如果可能被改名)
  315. tabWidget->setTabText(0, "Page 1");
  316. firstPage->setObjectName("Page 1");
  317. }
  318. bool HMIModule::isModified() const
  319. {
  320. return m_isModified;
  321. }
  322. void HMIModule::setModified(bool modified)
  323. {
  324. m_isModified = modified;
  325. }
  326. ModbusManager *HMIModule::getModbusManager() const
  327. {
  328. return m_modbusManager;
  329. }
  330. void HMIModule::setupNewComponent(HmiComponent* item)
  331. {
  332. if (!item) return;
  333. connect(item, &HmiComponent::selected, this, &HMIModule::onComponentSelected);
  334. connect(item, &HmiComponent::copyRequested, this, &HMIModule::onCopyRequested);
  335. connect(item, &HmiComponent::deleteRequested, this, &HMIModule::onDeleteRequested);
  336. connect(item, &HmiComponent::changeOnColorRequested, this, &HMIModule::onChangeOnColorRequested);
  337. connect(item, &HmiComponent::changeOffColorRequested, this, &HMIModule::onChangeOffColorRequested);
  338. if (auto *btn = dynamic_cast<HmiButton*>(item)) {
  339. connect(btn, &HmiButton::stateChanged, this, [this, btn](bool on){
  340. int addr = btn->address();
  341. updateComponentsByAddress(addr, on);
  342. if (m_modbusManager && m_modbusManager->isRunning()) {
  343. m_modbusManager->writeCoil(addr, on);
  344. }
  345. });
  346. }
  347. QString currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
  348. QString log = QString("[%1] 创建 %2 组件").arg(currentTime).arg(item->componentName());
  349. emit logMessageGenerated(log);
  350. }
  351. void HMIModule::updateComponentsByAddress(int address, bool on)
  352. {
  353. QTabWidget* tabWidget = ui_->tabWidget_2;
  354. for (int i = 0; i < tabWidget->count(); ++i) {
  355. QGraphicsView* view = tabWidget->widget(i)->findChild<QGraphicsView*>();
  356. if (!view) continue;
  357. auto scene = view->scene();
  358. for (auto *item : scene->items()) {
  359. if (auto hmi = dynamic_cast<HmiComponent*>(item)) {
  360. if (hmi->address() == address) {
  361. if (auto btn = dynamic_cast<HmiButton*>(hmi)) {
  362. btn->setOn(on); // 按钮联动
  363. } else {
  364. // 非按钮类就按颜色更新
  365. hmi->setColor(on ? hmi->onColor() : hmi->offColor());
  366. }
  367. }
  368. }
  369. }
  370. }
  371. }
  372. void HMIModule::prepareToCreateButton()
  373. {
  374. // 获取当前 TabWidget 中选中的 GraphicsView
  375. QTabWidget* tabWidget = ui_->tabWidget_2;
  376. QWidget* currentPage = tabWidget->currentWidget();
  377. QGraphicsView* currentGraphicsView = currentPage->findChild<QGraphicsView*>();
  378. CustomGraphicsScene* currentScene = qobject_cast<CustomGraphicsScene*>(currentGraphicsView->scene());
  379. if (currentScene) {
  380. currentScene->setComponentTypeToCreate(ComponentType::Button);
  381. currentScene->setMode(CustomGraphicsScene::Mode::CreateItem);
  382. }
  383. }
  384. void HMIModule::prepareToCreateIndicator()
  385. {
  386. // 获取当前 TabWidget 中选中的 GraphicsView
  387. QTabWidget* tabWidget = ui_->tabWidget_2;
  388. QWidget* currentPage = tabWidget->currentWidget();
  389. QGraphicsView* currentGraphicsView = currentPage->findChild<QGraphicsView*>();
  390. CustomGraphicsScene* currentScene = qobject_cast<CustomGraphicsScene*>(currentGraphicsView->scene());
  391. if (currentScene) {
  392. currentScene->setComponentTypeToCreate(ComponentType::Indicator);
  393. currentScene->setMode(CustomGraphicsScene::Mode::CreateItem);
  394. }
  395. }
  396. void HMIModule::onComponentCreated(HmiComponent* item)
  397. {
  398. setupNewComponent(item);
  399. setModified(true); // 标记已修改
  400. }
  401. void HMIModule::onCopyRequested()
  402. {
  403. // 获取当前 TabWidget 中选中的 GraphicsView
  404. QTabWidget* tabWidget = ui_->tabWidget_2;
  405. QWidget* currentPage = tabWidget->currentWidget();
  406. QGraphicsView* currentGraphicsView = currentPage->findChild<QGraphicsView*>();
  407. CustomGraphicsScene* currentScene = qobject_cast<CustomGraphicsScene*>(currentGraphicsView->scene());
  408. QList<QGraphicsItem*> selected = currentScene->selectedItems();
  409. if (selected.isEmpty()) return;
  410. HmiComponent* itemToCopy = qgraphicsitem_cast<HmiComponent*>(selected.first());
  411. if (!itemToCopy) return;
  412. if (dynamic_cast<HmiButton*>(itemToCopy)) {
  413. m_copiedType = ComponentType::Button;
  414. } else if (dynamic_cast<HmiIndicator*>(itemToCopy)) {
  415. m_copiedType = ComponentType::Indicator;
  416. }
  417. m_copiedColor = itemToCopy->color();
  418. // 复制以下属性
  419. m_copiedOnColor = itemToCopy->onColor();
  420. m_copiedOffColor = itemToCopy->offColor();
  421. m_copiedComponentName = itemToCopy->componentName();
  422. m_copiedAddress = itemToCopy->address();
  423. // 复制尺寸
  424. m_copiedWidth = itemToCopy->size().width();
  425. m_copiedHeight = itemToCopy->size().height();
  426. m_hasCopiedItem = true;
  427. emit logMessageGenerated(QString("[%1] 复制组件: %2")
  428. .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
  429. .arg(itemToCopy->componentName()));
  430. }
  431. void HMIModule::onPasteRequested(const QPointF& scenePos)
  432. {
  433. if (!m_hasCopiedItem) return;
  434. // 获取当前 TabWidget 中选中的 GraphicsView
  435. QTabWidget* tabWidget = ui_->tabWidget_2;
  436. QWidget* currentPage = tabWidget->currentWidget();
  437. QGraphicsView* currentGraphicsView = currentPage->findChild<QGraphicsView*>();
  438. CustomGraphicsScene* currentScene = qobject_cast<CustomGraphicsScene*>(currentGraphicsView->scene());
  439. HmiComponent* newItem = nullptr;
  440. if (m_copiedType == ComponentType::Button) {
  441. newItem = new HmiButton();
  442. } else {
  443. newItem = new HmiIndicator();
  444. }
  445. if (newItem) {
  446. newItem->setColor(m_copiedColor);
  447. newItem->setOnColor(m_copiedOnColor);
  448. newItem->setOffColor(m_copiedOffColor);
  449. newItem->setComponentName(m_copiedComponentName);
  450. newItem->setAddress(m_copiedAddress);
  451. // 设置尺寸
  452. newItem->setSize(m_copiedWidth, m_copiedHeight);
  453. newItem->setPos(scenePos);
  454. currentScene->addItem(newItem); // 使用当前页面的 scene
  455. setupNewComponent(newItem);
  456. }
  457. setModified(true); // 内容改变
  458. }
  459. void HMIModule::onDeleteRequested()
  460. {
  461. // 获取当前 TabWidget 中选中的 GraphicsView
  462. QTabWidget* tabWidget = ui_->tabWidget_2;
  463. QWidget* currentPage = tabWidget->currentWidget();
  464. QGraphicsView* currentGraphicsView = currentPage->findChild<QGraphicsView*>();
  465. CustomGraphicsScene* currentScene = qobject_cast<CustomGraphicsScene*>(currentGraphicsView->scene());
  466. QList<QGraphicsItem*> selected = currentScene->selectedItems();
  467. if (selected.isEmpty()) return;
  468. emit logMessageGenerated(QString("[%1] 删除 %2 个组件")
  469. .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
  470. .arg(selected.count()));
  471. for (int i = selected.count() - 1; i >= 0; --i) {
  472. QGraphicsItem* item = selected.at(i);
  473. currentScene->removeItem(item); // 使用当前页面的 scene
  474. delete item;
  475. }
  476. setModified(true); // 标记已修改
  477. }
  478. // 添加页面后的槽函数
  479. void HMIModule::onPageAdded(int pageNumber, int index)
  480. {
  481. if (index < m_pageOrder.size()) {
  482. m_pageOrder[index] = pageNumber;
  483. } else {
  484. m_pageOrder.append(pageNumber);
  485. }
  486. }
  487. // 删除页面后的槽函数
  488. void HMIModule::onPageRemoved(int pageNumber, int index)
  489. {
  490. if (index < m_pageOrder.size()) {
  491. m_pageOrder[index] = -1;
  492. }
  493. }
  494. void HMIModule::onChangeOnColorRequested(HmiComponent* item)
  495. {
  496. QColor color = QColorDialog::getColor(item->onColor(), nullptr, "选择 ON 状态颜色");
  497. if (color.isValid()) {
  498. item->setOnColor(color);
  499. emit logMessageGenerated(QString("[%1] 设置 %2 的 ON 状态颜色为 %3")
  500. .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
  501. .arg(item->componentName())
  502. .arg(color.name()));
  503. }
  504. }
  505. void HMIModule::onChangeOffColorRequested(HmiComponent* item)
  506. {
  507. QColor color = QColorDialog::getColor(item->offColor(), nullptr, "选择 OFF 状态颜色");
  508. if (color.isValid()) {
  509. item->setOffColor(color); // 同时更新当前显示颜色
  510. emit logMessageGenerated(QString("[%1] 设置 %2 的 OFF 状态颜色为 %3")
  511. .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
  512. .arg(item->componentName())
  513. .arg(color.name()));
  514. }
  515. }
  516. void HMIModule::onComponentSelected(HmiComponent* item)
  517. {
  518. // 不需要任何操作,可以留空
  519. }
  520. // 新增页面的槽函数
  521. void HMIModule::addPage()
  522. {
  523. QTabWidget* tabWidget = ui_->tabWidget_2;
  524. int pageNumber;
  525. int insertIndex = -1;
  526. int tabIndex; // 在此处声明 tabIndex
  527. // 检查是否有可用的页面编号
  528. if (!m_availablePageNumbers.isEmpty()) {
  529. pageNumber = m_availablePageNumbers.first();
  530. m_availablePageNumbers.removeFirst();
  531. // 查找可用的插入位置
  532. for (int i = 0; i < m_pageOrder.size(); ++i) {
  533. if (m_pageOrder[i] == -1) {
  534. insertIndex = i;
  535. break;
  536. }
  537. }
  538. } else {
  539. pageNumber = ++m_pageCount;
  540. }
  541. // 获取 Page 1 的 Scene
  542. CustomGraphicsScene* firstScene = m_scene;
  543. // 创建新的页面部件
  544. QWidget* newPage = new QWidget(tabWidget);
  545. QString pageName = QString("Page %1").arg(pageNumber);
  546. newPage->setObjectName(pageName);
  547. // 创建新的 GraphicsView 和 Scene
  548. QGraphicsView* newGraphicsView = new QGraphicsView(newPage);
  549. CustomGraphicsScene* newScene = new CustomGraphicsScene(newGraphicsView, this);
  550. // 设置 GraphicsView 的大小
  551. QSize newViewSize(691, 381); // 设置为指定的宽度和高度
  552. newGraphicsView->resize(newViewSize);
  553. // 设置 GraphicsScene 的大小与 Page 1 相同
  554. QRectF newSceneRect = firstScene->sceneRect();
  555. newScene->setSceneRect(newSceneRect);
  556. newGraphicsView->setScene(newScene);
  557. // 布局
  558. QVBoxLayout* layout = new QVBoxLayout(newPage);
  559. layout->addWidget(newGraphicsView);
  560. newPage->setLayout(layout);
  561. // 添加到 TabWidget
  562. if (insertIndex != -1) {
  563. tabIndex = insertIndex;
  564. tabWidget->insertTab(tabIndex, newPage, pageName);
  565. } else {
  566. tabIndex = tabWidget->addTab(newPage, pageName);
  567. }
  568. // 连接信号和槽
  569. connect(newScene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated);
  570. connect(newScene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested);
  571. connect(newScene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested);
  572. connect(newScene, &CustomGraphicsScene::deleteRequestFromScene, this, &HMIModule::onDeleteRequested);
  573. // 发送 pageAdded 信号
  574. emit pageAdded(pageNumber, tabIndex);
  575. tabWidget->setCurrentWidget(newPage);
  576. // 记录日志
  577. emit logMessageGenerated(QString("[%1] 添加页面: %2").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(pageName));
  578. setModified(true); // 页面变更,标记已修改
  579. }
  580. // 删除页面的槽函数
  581. void HMIModule::deletePage()
  582. {
  583. QTabWidget* tabWidget = ui_->tabWidget_2;
  584. int currentIndex = tabWidget->currentIndex();
  585. if (tabWidget->count() == 1) {
  586. QMessageBox::information(nullptr, "提示", "这是最后一页,不能删除!");
  587. return;
  588. }
  589. if (currentIndex >= 0) {
  590. // 获取要删除的页面
  591. QWidget* currentPage = tabWidget->widget(currentIndex);
  592. QString pageName = tabWidget->tabText(currentIndex);
  593. // 从页面名称中提取页面编号
  594. int pageNumber = pageName.remove("Page ").toInt();
  595. // 将删除的页面编号添加到可用列表中
  596. m_availablePageNumbers.append(pageNumber);
  597. std::sort(m_availablePageNumbers.begin(), m_availablePageNumbers.end());
  598. // 从 TabWidget 中移除页面
  599. tabWidget->removeTab(currentIndex);
  600. // 删除页面
  601. delete currentPage;
  602. // 发送 pageRemoved 信号
  603. emit pageRemoved(pageNumber, currentIndex);
  604. // 记录日志
  605. emit logMessageGenerated(QString("[%1] 删除页面: %2").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(pageName));
  606. }
  607. setModified(true); // 标记已修改
  608. }
  609. // 前一页的槽函数
  610. void HMIModule::prePage()
  611. {
  612. QTabWidget* tabWidget = ui_->tabWidget_2;
  613. int currentIndex = tabWidget->currentIndex();
  614. if (currentIndex > 0) {
  615. tabWidget->setCurrentIndex(currentIndex - 1);
  616. }
  617. }
  618. // 后一页的槽函数
  619. void HMIModule::nextPage()
  620. {
  621. QTabWidget* tabWidget = ui_->tabWidget_2;
  622. int currentIndex = tabWidget->currentIndex();
  623. if (currentIndex < tabWidget->count() - 1) {
  624. tabWidget->setCurrentIndex(currentIndex + 1);
  625. }
  626. }