You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

728 lines
25 KiB

  1. #include "mainwindow.h"
  2. #include "hmidocument.h"
  3. #include "plcdocument.h"
  4. #include <QMenuBar>
  5. #include <QAction>
  6. #include <QToolButton>
  7. #include <QMimeData>
  8. #include <QDrag>
  9. #include <QTabBar>
  10. #include <QEvent>
  11. #include <QMouseEvent>
  12. #include <QDragEnterEvent>
  13. #include <QDragMoveEvent>
  14. #include <QDropEvent>
  15. #include <QDebug>
  16. #include <QVBoxLayout>
  17. #include <QFileDialog>
  18. #include <QMessageBox>
  19. #include <QTextEdit>
  20. #include <QDockWidget>
  21. #include <QStatusBar>
  22. #include<QLabel>
  23. MainWindow::MainWindow(QWidget *parent)
  24. : QMainWindow(parent)
  25. {
  26. setWindowTitle("综合平台编程器");
  27. setGeometry(500, 200, 1000, 700);
  28. // 1. 先创建中央区域
  29. QWidget* centralContainer = new QWidget;
  30. QHBoxLayout* centralLayout = new QHBoxLayout(centralContainer);
  31. centralLayout->setContentsMargins(0, 0, 0, 0);
  32. // 2. 左侧工具栏区
  33. createToolbars(); // 创建工具栏对象
  34. centralLayout->addWidget(m_leftToolBar);
  35. // 3. 中央文档区
  36. m_tabWidget = new QTabWidget;
  37. m_tabWidget->setTabsClosable(true);
  38. centralLayout->addWidget(m_tabWidget, 1); // 占据剩余空间
  39. // 4. 设置中央部件
  40. setCentralWidget(centralContainer);
  41. // 5. 创建日志面板
  42. createLogPanel();
  43. // 连接信号
  44. connect(m_tabWidget, &QTabWidget::currentChanged, this, &MainWindow::onTabChanged);
  45. connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, &MainWindow::onCloseTab);
  46. // 创建菜单
  47. createMenus();
  48. }
  49. MainWindow::~MainWindow()
  50. {
  51. }
  52. void MainWindow::createLogPanel()
  53. {
  54. m_logDock = new QDockWidget("消息输出", this);
  55. m_logDock->setAllowedAreas(Qt::BottomDockWidgetArea);
  56. m_logDock->setFeatures(QDockWidget::DockWidgetClosable |
  57. QDockWidget::DockWidgetMovable |
  58. QDockWidget::DockWidgetFloatable);
  59. m_logDock->setMinimumHeight(150);
  60. m_logDock->setMaximumHeight(400);
  61. // 创建日志编辑框(启用自定义菜单)
  62. m_logEdit = new QTextEdit;
  63. m_logEdit->setReadOnly(true);
  64. m_logEdit->setFont(QFont("Consolas", 10));
  65. m_logEdit->setStyleSheet("background-color: #f8f8f8; border: 1px solid #d9d9d9;");
  66. // 关键修改:启用自定义右键菜单
  67. m_logEdit->setContextMenuPolicy(Qt::CustomContextMenu); // 禁用默认菜单[4,5](@ref)
  68. connect(m_logEdit, &QTextEdit::customContextMenuRequested,
  69. this, &MainWindow::showLogContextMenu); // 连接自定义菜单信号
  70. // 直接以日志编辑框作为面板内容
  71. m_logDock->setWidget(m_logEdit);
  72. addDockWidget(Qt::BottomDockWidgetArea, m_logDock);
  73. }
  74. void MainWindow::showLogContextMenu(const QPoint &pos)
  75. {
  76. QMenu menu; // 无需持久化,每次右键时创建
  77. // 1. 添加“复制”功能(复用系统功能)
  78. QAction* copyAction = menu.addAction("复制");
  79. connect(copyAction, &QAction::triggered, m_logEdit, &QTextEdit::copy); // 直接调用QTextEdit的复制功能[2,5](@ref)
  80. // 2. 添加“清空日志”功能
  81. QAction* clearAction = menu.addAction("清空日志");
  82. connect(clearAction, &QAction::triggered, this, &MainWindow::onClearLogButtonClicked);
  83. // 3. 显示菜单(无其他项)
  84. menu.exec(m_logEdit->viewport()->mapToGlobal(pos)); // 精准显示在点击位置[4](@ref)
  85. }
  86. // 槽函数实现
  87. void MainWindow::onClearLogButtonClicked()
  88. {
  89. m_logEdit->clear();
  90. m_logEdit->append("日志已清空");
  91. }
  92. // 创建菜单栏
  93. void MainWindow::createMenus()
  94. {
  95. // 设置菜单栏字体大小
  96. QFont menuFont = menuBar()->font();
  97. menuFont.setPointSize(15); // 菜单栏文字大小
  98. menuBar()->setFont(menuFont);
  99. // 创建文件菜单
  100. QMenu *fileMenu = menuBar()->addMenu("文件");
  101. QMenu *editMenu = menuBar()->addMenu("操作");
  102. // 设置菜单项字体大小
  103. QFont itemFont = fileMenu->font();
  104. itemFont.setPointSize(12); // 菜单项文字大小
  105. fileMenu->setFont(itemFont);
  106. editMenu->setFont(itemFont);
  107. // 新建HMI动作
  108. QAction *newHmiAction = new QAction("新建HMI(&H)", this);
  109. newHmiAction->setShortcut(tr("Ctrl+H"));
  110. newHmiAction->setFont(itemFont); // 设置动作文字大小
  111. connect(newHmiAction, &QAction::triggered, this, &MainWindow::onNewHMI);
  112. fileMenu->addAction(newHmiAction);
  113. // 新建PLC动作
  114. QAction *newPlcAction = new QAction("新建PLC(&P)", this);
  115. newPlcAction->setShortcut(tr("Ctrl+P"));
  116. newPlcAction->setFont(itemFont);
  117. connect(newPlcAction, &QAction::triggered, this, &MainWindow::onNewPLC);
  118. fileMenu->addAction(newPlcAction);
  119. // 打开动作
  120. m_openAction = new QAction("打开(&O)", this);
  121. m_openAction->setShortcut(QKeySequence::Open);
  122. m_openAction->setStatusTip("打开现有文档");
  123. m_openAction->setFont(itemFont);
  124. connect(m_openAction, &QAction::triggered, this, &MainWindow::onOpen);
  125. fileMenu->addAction(m_openAction);
  126. // 保存动作
  127. m_saveAction = new QAction("保存(&S)", this);
  128. m_saveAction->setShortcut(QKeySequence::Save);
  129. m_saveAction->setStatusTip("保存当前文档");
  130. m_saveAction->setFont(itemFont);
  131. connect(m_saveAction, &QAction::triggered, this, &MainWindow::onSave);
  132. fileMenu->addAction(m_saveAction);
  133. // 另存为动作
  134. m_saveAsAction = new QAction("另存为(&A)", this);
  135. m_saveAsAction->setShortcut(QKeySequence::SaveAs);
  136. m_saveAsAction->setStatusTip("将文档另存为");
  137. m_saveAsAction->setFont(itemFont);
  138. connect(m_saveAsAction, &QAction::triggered, this, &MainWindow::onSaveAs);
  139. fileMenu->addAction(m_saveAsAction);
  140. // 操作菜单 - 添加复制、粘贴、删除功能
  141. QAction *copyAction = new QAction("复制(&C)", this);
  142. copyAction->setShortcut(QKeySequence::Copy);
  143. copyAction->setStatusTip("复制选中的项目");
  144. copyAction->setFont(itemFont);
  145. connect(copyAction, &QAction::triggered, this, [this]() {
  146. if (auto hmiDoc = dynamic_cast<HMIDocument*>(m_tabWidget->currentWidget()))
  147. {
  148. hmiDoc->copySelectedItems();
  149. }
  150. else if (auto plcDoc = dynamic_cast<PLCDocument*>(m_tabWidget->currentWidget()))
  151. {
  152. plcDoc->copySelectedItem();//添加 PLC 文档支持
  153. }
  154. });
  155. QAction *pasteAction = new QAction("粘贴(&V)", this);
  156. pasteAction->setShortcut(QKeySequence::Paste);
  157. pasteAction->setStatusTip("粘贴复制的项目");
  158. pasteAction->setFont(itemFont);
  159. connect(pasteAction, &QAction::triggered, this, [this]() {
  160. if (auto hmiDoc = dynamic_cast<HMIDocument*>(m_tabWidget->currentWidget())) {
  161. hmiDoc->pasteItems();
  162. } else if (auto plcDoc = dynamic_cast<PLCDocument*>(m_tabWidget->currentWidget())) {
  163. plcDoc->pasteItem(); // 添加 PLC 文档支持
  164. }
  165. });
  166. QAction *deleteAction = new QAction("删除(&D)", this);
  167. deleteAction->setShortcut(QKeySequence::Delete);
  168. deleteAction->setStatusTip("删除选中的项目");
  169. deleteAction->setFont(itemFont);
  170. connect(deleteAction, &QAction::triggered, this, [this]() {
  171. if (auto hmiDoc = dynamic_cast<HMIDocument*>(m_tabWidget->currentWidget())) {
  172. hmiDoc->deleteSelectedItems();
  173. } else if (auto plcDoc = dynamic_cast<PLCDocument*>(m_tabWidget->currentWidget())) {
  174. plcDoc->deleteSelectedItems(); // 添加 PLC 文档支持
  175. }
  176. });
  177. // 添加到操作菜单
  178. editMenu->addAction(copyAction);
  179. editMenu->addAction(pasteAction);
  180. editMenu->addAction(deleteAction);
  181. // 添加仿真菜单项
  182. QMenu *simulationMenu = menuBar()->addMenu("仿真");
  183. simulationMenu->setFont(itemFont);
  184. // 运行动作 (暂时留空)
  185. // QAction *runAction = new QAction("运行", this);
  186. // runAction->setFont(itemFont);
  187. // simulationMenu->addAction(runAction);
  188. // 创建仿真运行动作并连接到槽函数
  189. m_runSimulationAction = new QAction("运行", this); // 使用成员变量
  190. m_runSimulationAction->setFont(itemFont);
  191. simulationMenu->addAction(m_runSimulationAction);
  192. // 添加连接:将仿真运行动作连接到 onRunSimulation 槽
  193. connect(m_runSimulationAction, &QAction::triggered, this, &MainWindow::onRunSimulation);
  194. }
  195. void MainWindow::onRunSimulation()
  196. {
  197. if (auto hmiDoc = dynamic_cast<HMIDocument*>(m_tabWidget->currentWidget())) {
  198. if (hmiDoc->isSimulationRunning()) {
  199. hmiDoc->stopSimulation();
  200. } else {
  201. hmiDoc->startSimulation();
  202. }
  203. onSimulationStatusChanged();
  204. }
  205. }
  206. void MainWindow::onSimulationStatusChanged()
  207. {
  208. if (auto hmiDoc = dynamic_cast<HMIDocument*>(m_tabWidget->currentWidget())) {
  209. if (hmiDoc->isSimulationRunning()) {
  210. m_runSimulationAction->setText("停止");
  211. m_runSimulationAction->setIcon(QIcon(":/icons/stop.png"));
  212. statusBar()->showMessage("仿真运行中...", 2000);
  213. } else {
  214. m_runSimulationAction->setText("运行");
  215. m_runSimulationAction->setIcon(QIcon(":/icons/run.png"));
  216. statusBar()->showMessage("仿真已停止", 2000);
  217. }
  218. }
  219. }
  220. // 创建左侧工具栏
  221. void MainWindow::createToolbars()
  222. {
  223. m_leftToolBar = new QToolBar("绘图工具栏", this);
  224. addToolBar(Qt::LeftToolBarArea, m_leftToolBar);
  225. m_leftToolBar->setAllowedAreas(Qt::LeftToolBarArea); // 仅允许在左侧
  226. m_leftToolBar->setFixedWidth(230);
  227. }
  228. // 更新工具栏(根据当前文档类型)
  229. void MainWindow::updateToolBar(BaseDocument *doc)
  230. {
  231. m_leftToolBar->clear();// 清空现有工具
  232. if (!doc) return;
  233. if (doc->type() == BaseDocument::HMI)// HMI文档显示绘图工具
  234. {
  235. HMIDocument *hmiDoc = dynamic_cast<HMIDocument*>(doc);
  236. if (!hmiDoc) return;
  237. // 画指示灯按钮(支持拖拽)
  238. QToolButton *ellipseBtn = new QToolButton;
  239. ellipseBtn->setText("指示灯");
  240. ellipseBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  241. ellipseBtn->setIcon(QIcon("../two/untitled/images/灯泡.png"));//可替换为实际图标
  242. ellipseBtn->installEventFilter(this);//为按钮安装事件过滤器处理拖拽
  243. ellipseBtn->setProperty("toolType", "指示灯");
  244. m_leftToolBar->addWidget(ellipseBtn);
  245. ellipseBtn->setStyleSheet(R"(
  246. QToolButton {
  247. margin: 2 auto;
  248. background-color: #f0f0f0;
  249. border-radius: 10px;
  250. border: 1px solid #ccc;
  251. padding: 10px 15px;
  252. font-size: 25px;
  253. font-weight: bold;
  254. color: #333;
  255. }
  256. QToolButton:hover {
  257. background-color: #e0e0e0;
  258. }
  259. )");
  260. // 画按钮按钮(支持拖拽)
  261. QToolButton *rectBtn = new QToolButton;
  262. rectBtn->setText("按钮");
  263. rectBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  264. rectBtn->setIcon(QIcon("../two/untitled/images/按钮.png"));//可替换为实际图标
  265. rectBtn->installEventFilter(this);
  266. rectBtn->setProperty("toolType", "按钮");
  267. m_leftToolBar->addWidget(rectBtn);
  268. rectBtn->setStyleSheet(R"(
  269. QToolButton {
  270. margin: 2 auto;
  271. background-color: #f0f0f0;
  272. border-radius: 10px;
  273. border: 1px solid #ccc;
  274. padding: 10px 28px;
  275. font-size: 25px;
  276. font-weight: bold;
  277. color: #333;
  278. }
  279. QToolButton:hover {
  280. background-color: #e0e0e0;
  281. }
  282. )");
  283. }
  284. // PLC按钮工具
  285. else if (doc->type() == BaseDocument::PLC)
  286. {
  287. // 常开触点按钮
  288. QToolButton *normallyOpenBtn = new QToolButton;
  289. normallyOpenBtn->setText("常开");
  290. normallyOpenBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  291. normallyOpenBtn->setIcon(QIcon("../two/untitled/images/T-常开触点-01.png")); // 替换为实际图标
  292. normallyOpenBtn->installEventFilter(this);
  293. normallyOpenBtn->setProperty("toolType", "常开");
  294. m_leftToolBar->addWidget(normallyOpenBtn);
  295. normallyOpenBtn->setStyleSheet(R"(
  296. QToolButton {
  297. margin: 2 auto;
  298. background-color: #f0f0f0;
  299. border-radius: 10px;
  300. border: 1px solid #ccc;
  301. padding: 10px 28px;
  302. font-size: 25px;
  303. font-weight: bold;
  304. color: #333;
  305. }
  306. QToolButton:hover {
  307. background-color: #e0e0e0;
  308. }
  309. )");
  310. // 常闭触点按钮
  311. QToolButton *normallyClosedBtn = new QToolButton;
  312. normallyClosedBtn->setText("常闭");
  313. normallyClosedBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  314. normallyClosedBtn->setIcon(QIcon("../two/untitled/images/T-常闭触点-01-01.png")); // 替换为实际图标
  315. normallyClosedBtn->installEventFilter(this);
  316. normallyClosedBtn->setProperty("toolType", "常闭");
  317. m_leftToolBar->addWidget(normallyClosedBtn);
  318. normallyClosedBtn->setStyleSheet(R"(
  319. QToolButton {
  320. margin: 2 auto;
  321. background-color: #f0f0f0;
  322. border-radius: 10px;
  323. border: 1px solid #ccc;
  324. padding: 10px 28px;
  325. font-size: 25px;
  326. font-weight: bold;
  327. color: #333;
  328. }
  329. QToolButton:hover {
  330. background-color: #e0e0e0;
  331. }
  332. )");
  333. // 大于按钮
  334. QToolButton *greaterThanBtn = new QToolButton;
  335. greaterThanBtn->setText("大于");
  336. greaterThanBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  337. greaterThanBtn->setIcon(QIcon("../two/untitled/images/大于号.png")); // 替换为实际图标
  338. greaterThanBtn->installEventFilter(this);
  339. greaterThanBtn->setProperty("toolType", "大于");
  340. m_leftToolBar->addWidget(greaterThanBtn);
  341. greaterThanBtn->setStyleSheet(R"(
  342. QToolButton {
  343. margin: 2 auto;
  344. background-color: #f0f0f0;
  345. border-radius: 10px;
  346. border: 1px solid #ccc;
  347. padding: 10px 28px;
  348. font-size: 25px;
  349. font-weight: bold;
  350. color: #333;
  351. }
  352. QToolButton:hover {
  353. background-color: #e0e0e0;
  354. }
  355. )");
  356. // 大于等于按钮
  357. QToolButton *greaterThanEqualBtn = new QToolButton;
  358. greaterThanEqualBtn->setText("大于等于");
  359. greaterThanEqualBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  360. greaterThanEqualBtn->setIcon(QIcon("../two/untitled/images/大于等于.png")); // 替换为实际图标
  361. greaterThanEqualBtn->installEventFilter(this);
  362. greaterThanEqualBtn->setProperty("toolType", "大于等于");
  363. m_leftToolBar->addWidget(greaterThanEqualBtn);
  364. greaterThanEqualBtn->setStyleSheet(R"(
  365. QToolButton {
  366. margin: 2 auto;
  367. background-color: #f0f0f0;
  368. border-radius: 10px;
  369. border: 1px solid #ccc;
  370. padding: 10px 2px;
  371. font-size: 25px;
  372. font-weight: bold;
  373. color: #333;
  374. }
  375. QToolButton:hover {
  376. background-color: #e0e0e0;
  377. }
  378. )");
  379. // 小于按钮
  380. QToolButton *lessThanBtn = new QToolButton;
  381. lessThanBtn->setText("小于");
  382. lessThanBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  383. lessThanBtn->setIcon(QIcon("../two/untitled/images/小于号.png")); // 替换为实际图标
  384. lessThanBtn->installEventFilter(this);
  385. lessThanBtn->setProperty("toolType", "小于");
  386. m_leftToolBar->addWidget(lessThanBtn);
  387. lessThanBtn->setStyleSheet(R"(
  388. QToolButton {
  389. margin: 2 auto;
  390. background-color: #f0f0f0;
  391. border-radius: 10px;
  392. border: 1px solid #ccc;
  393. padding: 10px 28px;
  394. font-size: 25px;
  395. font-weight: bold;
  396. color: #333;
  397. }
  398. QToolButton:hover {
  399. background-color: #e0e0e0;
  400. }
  401. )");
  402. // 小于等于按钮
  403. QToolButton *lessThanEqualBtn = new QToolButton;
  404. lessThanEqualBtn->setText("小于等于");
  405. lessThanEqualBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  406. lessThanEqualBtn->setIcon(QIcon("../two/untitled/images/小于等于.png")); // 替换为实际图标
  407. lessThanEqualBtn->installEventFilter(this);
  408. lessThanEqualBtn->setProperty("toolType", "小于等于");
  409. m_leftToolBar->addWidget(lessThanEqualBtn);
  410. lessThanEqualBtn->setStyleSheet(R"(
  411. QToolButton {
  412. margin: 2 auto;
  413. background-color: #f0f0f0;
  414. border-radius: 10px;
  415. border: 1px solid #ccc;
  416. padding: 10px 2px;
  417. font-size: 25px;
  418. font-weight: bold;
  419. color: #333;
  420. }
  421. QToolButton:hover {
  422. background-color: #e0e0e0;
  423. }
  424. )");
  425. // 等于按钮
  426. QToolButton *equalBtn = new QToolButton;
  427. equalBtn->setText("等于");
  428. equalBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  429. equalBtn->setIcon(QIcon("../two/untitled/images/等于.png")); // 替换为实际图标
  430. equalBtn->installEventFilter(this);
  431. equalBtn->setProperty("toolType", "等于");
  432. m_leftToolBar->addWidget(equalBtn);
  433. equalBtn->setStyleSheet(R"(
  434. QToolButton {
  435. margin: 2 auto;
  436. background-color: #f0f0f0;
  437. border-radius: 10px;
  438. border: 1px solid #ccc;
  439. padding: 10px 28px;
  440. font-size: 25px;
  441. font-weight: bold;
  442. color: #333;
  443. }
  444. QToolButton:hover {
  445. background-color: #e0e0e0;
  446. }
  447. )");
  448. // 线圈按钮
  449. QToolButton *coilBtn = new QToolButton;
  450. coilBtn->setText("线圈");
  451. coilBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  452. coilBtn->setIcon(QIcon("../two/untitled/images/添加线圈.png")); // 替换为实际图标
  453. coilBtn->installEventFilter(this);
  454. coilBtn->setProperty("toolType", "线圈");
  455. m_leftToolBar->addWidget(coilBtn);
  456. coilBtn->setStyleSheet(R"(
  457. QToolButton {
  458. margin: 2 auto;
  459. background-color: #f0f0f0;
  460. border-radius: 10px;
  461. border: 1px solid #ccc;
  462. padding: 10px 28px;
  463. font-size: 25px;
  464. font-weight: bold;
  465. color: #333;
  466. }
  467. QToolButton:hover {
  468. background-color: #e0e0e0;
  469. }
  470. )");
  471. normallyOpenBtn->installEventFilter(this);
  472. normallyClosedBtn->installEventFilter(this);
  473. greaterThanBtn->installEventFilter(this);
  474. greaterThanEqualBtn->installEventFilter(this);
  475. lessThanBtn->installEventFilter(this);
  476. lessThanEqualBtn->installEventFilter(this);
  477. equalBtn->installEventFilter(this);
  478. coilBtn->installEventFilter(this);
  479. }
  480. }
  481. // 事件过滤器处理拖拽
  482. bool MainWindow::eventFilter(QObject *obj, QEvent *event)
  483. {
  484. QToolButton *toolBtn = qobject_cast<QToolButton*>(obj);
  485. if (toolBtn && event->type() == QEvent::MouseButtonPress)
  486. {
  487. QMouseEvent *me = static_cast<QMouseEvent*>(event);
  488. if (me->button() == Qt::LeftButton)
  489. {
  490. QString toolType = toolBtn->property("toolType").toString();
  491. if (!toolType.isEmpty())
  492. {
  493. BaseDocument* currentDoc = dynamic_cast<BaseDocument*>(m_tabWidget->currentWidget());
  494. if (currentDoc && currentDoc->type() == BaseDocument::PLC)//PLC文档处理
  495. {
  496. PLCDocument* plcDoc = static_cast<PLCDocument*>(currentDoc);
  497. // 设置当前工具
  498. plcDoc->setCurrentTool(toolType);
  499. // 创建拖拽对象
  500. QMimeData *mime = new QMimeData;
  501. mime->setText(toolType);
  502. QDrag *drag = new QDrag(toolBtn);
  503. drag->setMimeData(mime);
  504. drag->exec(Qt::CopyAction);
  505. return true;
  506. }
  507. // HMI文档处理
  508. if (currentDoc && currentDoc->type() == BaseDocument::HMI)
  509. {
  510. HMIDocument* hmiDoc = static_cast<HMIDocument*>(currentDoc);
  511. if (toolType == "指示灯")
  512. {
  513. hmiDoc->startDrawingEllipse();//点击生成标志
  514. }
  515. else if (toolType == "按钮")
  516. {
  517. hmiDoc->startDrawingRectangle();//点击生成标志
  518. }
  519. // 新增拖拽逻辑
  520. QMimeData *mime = new QMimeData;
  521. mime->setText(toolType);//传递工具类型("指示灯"或"按钮")
  522. QDrag *drag = new QDrag(toolBtn);
  523. drag->setMimeData(mime);
  524. drag->exec(Qt::CopyAction);//启动拖拽
  525. return true;
  526. }
  527. }
  528. }
  529. }
  530. return QMainWindow::eventFilter(obj, event);
  531. }
  532. // 新建HMI文档
  533. void MainWindow::onNewHMI()
  534. {
  535. m_hmiCount++;
  536. HMIDocument *doc = new HMIDocument;
  537. doc->setTitle("HMI文档 " + QString::number(m_hmiCount));
  538. m_tabWidget->addTab(doc, doc->title());
  539. m_tabWidget->setCurrentWidget(doc);
  540. updateToolBar(doc); // 更新工具栏为HMI工具
  541. }
  542. // 新建PLC文档
  543. void MainWindow::onNewPLC()
  544. {
  545. m_plcCount++;
  546. PLCDocument *doc = new PLCDocument;
  547. m_tabWidget->addTab(doc, QString("PLC文档 %1").arg(m_plcCount));
  548. m_tabWidget->setCurrentWidget(doc);
  549. updateToolBar(doc); // 更新工具栏为PLC工具
  550. }
  551. // 标签页切换时更新工具栏
  552. void MainWindow::onTabChanged(int idx)
  553. {
  554. if (idx < 0)
  555. {
  556. updateToolBar(nullptr);
  557. return;
  558. }
  559. BaseDocument *doc = dynamic_cast<BaseDocument*>(m_tabWidget->widget(idx));
  560. updateToolBar(doc);
  561. }
  562. // 保存文档
  563. void MainWindow::onSave()
  564. {
  565. BaseDocument *doc = dynamic_cast<BaseDocument*>(m_tabWidget->currentWidget());
  566. if (!doc) return;
  567. if (doc->filePath().isEmpty()) {
  568. saveDocumentAs(doc);
  569. } else {
  570. saveDocument(doc);
  571. }
  572. }
  573. // 另存为文档
  574. void MainWindow::onSaveAs()
  575. {
  576. BaseDocument *doc = dynamic_cast<BaseDocument*>(m_tabWidget->currentWidget());
  577. if (doc) {
  578. saveDocumentAs(doc);
  579. }
  580. }
  581. // 打开文档
  582. void MainWindow::onOpen()
  583. {
  584. QString filePath = QFileDialog::getOpenFileName(
  585. this,
  586. "打开文档",
  587. "",
  588. "HMI文档 (*.hmi);;PLC文档 (*.plc)"
  589. );
  590. if (filePath.isEmpty()) return;
  591. QFileInfo fileInfo(filePath);
  592. BaseDocument *doc = nullptr;
  593. if (fileInfo.suffix().toLower() == "hmi") {
  594. doc = new HMIDocument;
  595. } else if (fileInfo.suffix().toLower() == "plc") {
  596. doc = new PLCDocument;
  597. } else {
  598. QMessageBox::warning(this, "打开文档", "不支持的文件格式");
  599. return;
  600. }
  601. if (doc->loadFromFile(filePath)) {
  602. m_tabWidget->addTab(doc, doc->title());
  603. m_tabWidget->setCurrentWidget(doc);
  604. updateToolBar(doc);
  605. } else {
  606. QMessageBox::critical(this, "打开文档", "无法加载文档");
  607. delete doc;
  608. }
  609. }
  610. // 关闭标签页
  611. void MainWindow::onCloseTab(int index)
  612. {
  613. BaseDocument *doc = dynamic_cast<BaseDocument*>(m_tabWidget->widget(index));
  614. if (!doc) return;
  615. if (doc->isModified())
  616. {
  617. QMessageBox::StandardButton reply = QMessageBox::question(
  618. this,
  619. "保存文档",
  620. QString("文档 '%1' 已修改,是否保存更改?").arg(doc->title()),
  621. QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel
  622. );
  623. if (reply == QMessageBox::Save) {
  624. saveDocument(doc);
  625. } else if (reply == QMessageBox::Cancel) {
  626. return;
  627. }
  628. }
  629. m_tabWidget->removeTab(index);
  630. delete doc;
  631. }
  632. // 保存文档
  633. void MainWindow::saveDocument(BaseDocument *doc)
  634. {
  635. // 如果文件路径为空(新文件),执行“另存为”
  636. if (doc->filePath().isEmpty())
  637. {
  638. // 直接调用另存为函数
  639. saveDocumentAs(doc);
  640. }
  641. else
  642. {
  643. // 如果已有文件路径,直接保存
  644. if (doc->saveToFile(doc->filePath()))
  645. {
  646. doc->setModified(false); // 清除修改状态
  647. QMessageBox::information(this, "保存文档", "文档保存成功");
  648. }
  649. else
  650. {
  651. QMessageBox::critical(this, "保存文档", "无法保存文档");
  652. }
  653. }
  654. }
  655. // 另存为文档
  656. void MainWindow::saveDocumentAs(BaseDocument *doc)
  657. {
  658. QString filePath = QFileDialog::getSaveFileName(
  659. this,
  660. "保存为",
  661. doc->filePath().isEmpty() ? doc->title() : doc->filePath(),
  662. doc->type() == BaseDocument::HMI ?"HMI文档 (*.hmi)" :"PLC文档 (*.plc)"
  663. );
  664. if (filePath.isEmpty()) return;
  665. if (doc->saveToFile(filePath))
  666. {
  667. doc->setModified(false); // 清除修改状态
  668. QMessageBox::information(this, "保存文档", "文档保存成功");
  669. }
  670. else
  671. {
  672. QMessageBox::critical(this, "保存文档", "无法保存文档");
  673. }
  674. }