Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

545 linhas
18 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. MainWindow::MainWindow(QWidget *parent)
  21. : QMainWindow(parent)
  22. {
  23. setWindowTitle("综合平台编程器");
  24. setGeometry(500, 200, 1000, 700);
  25. // 初始化标签页
  26. m_tabWidget = new QTabWidget(this);
  27. m_tabWidget->setTabsClosable(true);
  28. setCentralWidget(m_tabWidget);
  29. connect(m_tabWidget, &QTabWidget::currentChanged, this, &MainWindow::onTabChanged);
  30. connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, &MainWindow::onCloseTab);
  31. // 创建菜单和工具栏
  32. createMenus();
  33. createToolbars();
  34. }
  35. MainWindow::~MainWindow()
  36. {
  37. // 标签页和工具栏由Qt自动销毁
  38. }
  39. // 创建菜单栏
  40. void MainWindow::createMenus()
  41. {
  42. // 创建文件菜单
  43. QMenu *fileMenu = menuBar()->addMenu("文件");
  44. QMenu *editMenu = menuBar()->addMenu("操作");
  45. // 新建HMI动作
  46. QAction *newHmiAction = new QAction("新建HMI(&H)", this);
  47. newHmiAction->setShortcut(tr("Ctrl+H"));
  48. connect(newHmiAction, &QAction::triggered, this, &MainWindow::onNewHMI);
  49. fileMenu->addAction(newHmiAction);
  50. // 新建PLC动作
  51. QAction *newPlcAction = new QAction("新建PLC(&P)", this);
  52. newPlcAction->setShortcut(tr("Ctrl+P"));
  53. connect(newPlcAction, &QAction::triggered, this, &MainWindow::onNewPLC);
  54. fileMenu->addAction(newPlcAction);
  55. // 打开动作
  56. m_openAction = new QAction("打开(&O)", this);
  57. m_openAction->setShortcut(QKeySequence::Open);
  58. m_openAction->setStatusTip("打开现有文档");
  59. connect(m_openAction, &QAction::triggered, this, &MainWindow::onOpen);
  60. fileMenu->addAction(m_openAction);
  61. // 保存动作
  62. m_saveAction = new QAction("保存(&S)", this);
  63. m_saveAction->setShortcut(QKeySequence::Save);
  64. m_saveAction->setStatusTip("保存当前文档");
  65. connect(m_saveAction, &QAction::triggered, this, &MainWindow::onSave);
  66. fileMenu->addAction(m_saveAction);
  67. // 另存为动作
  68. m_saveAsAction = new QAction("另存为(&A)", this);
  69. m_saveAsAction->setShortcut(QKeySequence::SaveAs);
  70. m_saveAsAction->setStatusTip("将文档另存为");
  71. connect(m_saveAsAction, &QAction::triggered, this, &MainWindow::onSaveAs);
  72. fileMenu->addAction(m_saveAsAction);
  73. // 操作菜单 - 添加复制、粘贴、删除功能
  74. QAction *copyAction = new QAction("复制(&C)", this);
  75. copyAction->setShortcut(QKeySequence::Copy); // 标准复制快捷键 Ctrl+C
  76. copyAction->setStatusTip("复制选中的项目");
  77. connect(copyAction, &QAction::triggered, this, [this]() {
  78. // 获取当前活动的HMI文档
  79. if (auto hmiDoc = dynamic_cast<HMIDocument*>(m_tabWidget->currentWidget())) {
  80. hmiDoc->copySelectedItems();
  81. }
  82. });
  83. QAction *pasteAction = new QAction("粘贴(&V)", this);
  84. pasteAction->setShortcut(QKeySequence::Paste); // 标准粘贴快捷键 Ctrl+V
  85. pasteAction->setStatusTip("粘贴复制的项目");
  86. connect(pasteAction, &QAction::triggered, this, [this]() {
  87. if (auto hmiDoc = dynamic_cast<HMIDocument*>(m_tabWidget->currentWidget())) {
  88. hmiDoc->pasteItems();
  89. }
  90. });
  91. QAction *deleteAction = new QAction("删除(&D)", this);
  92. deleteAction->setShortcut(QKeySequence::Delete); // 删除键
  93. deleteAction->setStatusTip("删除选中的项目");
  94. connect(deleteAction, &QAction::triggered, this, [this]() {
  95. if (auto hmiDoc = dynamic_cast<HMIDocument*>(m_tabWidget->currentWidget())) {
  96. hmiDoc->deleteSelectedItems();
  97. }
  98. });
  99. // 添加到操作菜单
  100. editMenu->addAction(copyAction);
  101. editMenu->addAction(pasteAction);
  102. editMenu->addAction(deleteAction);
  103. }
  104. // 创建左侧工具栏
  105. void MainWindow::createToolbars()
  106. {
  107. m_leftToolBar = new QToolBar("绘图工具栏", this);
  108. addToolBar(Qt::LeftToolBarArea, m_leftToolBar);
  109. m_leftToolBar->setAllowedAreas(Qt::LeftToolBarArea); // 仅允许在左侧
  110. m_leftToolBar->setFixedWidth(200);
  111. }
  112. // 更新工具栏(根据当前文档类型)
  113. void MainWindow::updateToolBar(BaseDocument *doc)
  114. {
  115. m_leftToolBar->clear();// 清空现有工具
  116. if (!doc) return;
  117. if (doc->type() == BaseDocument::HMI)// HMI文档显示绘图工具
  118. {
  119. HMIDocument *hmiDoc = dynamic_cast<HMIDocument*>(doc);
  120. if (!hmiDoc) return;
  121. // 画指示灯按钮(支持拖拽)
  122. QToolButton *ellipseBtn = new QToolButton;
  123. ellipseBtn->setText("指示灯");
  124. ellipseBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  125. ellipseBtn->setIcon(QIcon("../two/untitled/images/灯泡.png"));//可替换为实际图标
  126. ellipseBtn->installEventFilter(this);//为按钮安装事件过滤器处理拖拽
  127. ellipseBtn->setProperty("toolType", "指示灯");
  128. m_leftToolBar->addWidget(ellipseBtn);
  129. ellipseBtn->setStyleSheet(R"(
  130. QToolButton {
  131. margin: 2 auto;
  132. background-color: #f0f0f0;
  133. border-radius: 10px;
  134. border: 1px solid #ccc;
  135. padding: 10px 12px;
  136. font-size: 18px;
  137. font-weight: bold;
  138. color: #333;
  139. }
  140. QToolButton:hover {
  141. background-color: #e0e0e0;
  142. }
  143. )");
  144. // 画按钮按钮(支持拖拽)
  145. QToolButton *rectBtn = new QToolButton;
  146. rectBtn->setText("按 钮");
  147. rectBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  148. rectBtn->setIcon(QIcon("../two/untitled/images/按钮.png"));//可替换为实际图标
  149. rectBtn->installEventFilter(this);
  150. rectBtn->setProperty("toolType", "按钮");
  151. m_leftToolBar->addWidget(rectBtn);
  152. rectBtn->setStyleSheet(R"(
  153. QToolButton {
  154. margin: 2 auto;
  155. background-color: #f0f0f0;
  156. border-radius: 10px;
  157. border: 1px solid #ccc;
  158. padding: 10px 15px;
  159. font-size: 18px;
  160. font-weight: bold;
  161. color: #333;
  162. }
  163. QToolButton:hover {
  164. background-color: #e0e0e0;
  165. }
  166. )");
  167. }
  168. // PLC按钮工具
  169. else if (doc->type() == BaseDocument::PLC)
  170. {
  171. // 常开触点按钮
  172. QToolButton *normallyOpenBtn = new QToolButton;
  173. normallyOpenBtn->setText("常开触点");
  174. normallyOpenBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  175. normallyOpenBtn->setIcon(QIcon("../two/untitled/images/T-常开触点-01.png")); // 替换为实际图标
  176. normallyOpenBtn->installEventFilter(this);
  177. normallyOpenBtn->setProperty("toolType", "常开触点");
  178. m_leftToolBar->addWidget(normallyOpenBtn);
  179. normallyOpenBtn->setStyleSheet(R"(
  180. QToolButton {
  181. margin: 2 auto;
  182. background-color: #f0f0f0;
  183. border-radius: 10px;
  184. border: 1px solid #ccc;
  185. padding: 10px 1px;
  186. font-size: 18px;
  187. font-weight: bold;
  188. color: #333;
  189. }
  190. QToolButton:hover {
  191. background-color: #e0e0e0;
  192. }
  193. )");
  194. // 常闭触点按钮
  195. QToolButton *normallyClosedBtn = new QToolButton;
  196. normallyClosedBtn->setText("常闭触点");
  197. normallyClosedBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  198. normallyClosedBtn->setIcon(QIcon("../two/untitled/images/T-常闭触点-01-01.png")); // 替换为实际图标
  199. normallyClosedBtn->installEventFilter(this);
  200. normallyClosedBtn->setProperty("toolType", "常闭触点");
  201. m_leftToolBar->addWidget(normallyClosedBtn);
  202. normallyClosedBtn->setStyleSheet(R"(
  203. QToolButton {
  204. margin: 2 auto;
  205. background-color: #f0f0f0;
  206. border-radius: 10px;
  207. border: 1px solid #ccc;
  208. padding: 10px 1px;
  209. font-size: 18px;
  210. font-weight: bold;
  211. color: #333;
  212. }
  213. QToolButton:hover {
  214. background-color: #e0e0e0;
  215. }
  216. )");
  217. // 大于按钮
  218. QToolButton *greaterThanBtn = new QToolButton;
  219. greaterThanBtn->setText("大于");
  220. greaterThanBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  221. greaterThanBtn->setIcon(QIcon("../two/untitled/images/大于号.png")); // 替换为实际图标
  222. greaterThanBtn->installEventFilter(this);
  223. greaterThanBtn->setProperty("toolType", "大于");
  224. m_leftToolBar->addWidget(greaterThanBtn);
  225. greaterThanBtn->setStyleSheet(R"(
  226. QToolButton {
  227. margin: 2 auto;
  228. background-color: #f0f0f0;
  229. border-radius: 10px;
  230. border: 1px solid #ccc;
  231. padding: 10px 20px;
  232. font-size: 18px;
  233. font-weight: bold;
  234. color: #333;
  235. }
  236. QToolButton:hover {
  237. background-color: #e0e0e0;
  238. }
  239. )");
  240. // 大于等于按钮
  241. QToolButton *greaterThanEqualBtn = new QToolButton;
  242. greaterThanEqualBtn->setText("大于等于");
  243. greaterThanEqualBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  244. greaterThanEqualBtn->setIcon(QIcon("../two/untitled/images/大于等于.png")); // 替换为实际图标
  245. greaterThanEqualBtn->installEventFilter(this);
  246. greaterThanEqualBtn->setProperty("toolType", "大于等于");
  247. m_leftToolBar->addWidget(greaterThanEqualBtn);
  248. greaterThanEqualBtn->setStyleSheet(R"(
  249. QToolButton {
  250. margin: 2 auto;
  251. background-color: #f0f0f0;
  252. border-radius: 10px;
  253. border: 1px solid #ccc;
  254. padding: 10px 1px;
  255. font-size: 18px;
  256. font-weight: bold;
  257. color: #333;
  258. }
  259. QToolButton:hover {
  260. background-color: #e0e0e0;
  261. }
  262. )");
  263. // 小于按钮
  264. QToolButton *lessThanBtn = new QToolButton;
  265. lessThanBtn->setText("小于");
  266. lessThanBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  267. lessThanBtn->setIcon(QIcon("../two/untitled/images/小于号.png")); // 替换为实际图标
  268. lessThanBtn->installEventFilter(this);
  269. lessThanBtn->setProperty("toolType", "小于");
  270. m_leftToolBar->addWidget(lessThanBtn);
  271. lessThanBtn->setStyleSheet(R"(
  272. QToolButton {
  273. margin: 2 auto;
  274. background-color: #f0f0f0;
  275. border-radius: 10px;
  276. border: 1px solid #ccc;
  277. padding: 10px 20px;
  278. font-size: 18px;
  279. font-weight: bold;
  280. color: #333;
  281. }
  282. QToolButton:hover {
  283. background-color: #e0e0e0;
  284. }
  285. )");
  286. // 小于等于按钮
  287. QToolButton *lessThanEqualBtn = new QToolButton;
  288. lessThanEqualBtn->setText("小于等于");
  289. lessThanEqualBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  290. lessThanEqualBtn->setIcon(QIcon("../two/untitled/images/小于等于.png")); // 替换为实际图标
  291. lessThanEqualBtn->installEventFilter(this);
  292. lessThanEqualBtn->setProperty("toolType", "小于等于");
  293. m_leftToolBar->addWidget(lessThanEqualBtn);
  294. lessThanEqualBtn->setStyleSheet(R"(
  295. QToolButton {
  296. margin: 2 auto;
  297. background-color: #f0f0f0;
  298. border-radius: 10px;
  299. border: 1px solid #ccc;
  300. padding: 10px 1px;
  301. font-size: 18px;
  302. font-weight: bold;
  303. color: #333;
  304. }
  305. QToolButton:hover {
  306. background-color: #e0e0e0;
  307. }
  308. )");
  309. // 线圈按钮
  310. QToolButton *coilBtn = new QToolButton;
  311. coilBtn->setText("线圈");
  312. coilBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  313. coilBtn->setIcon(QIcon("../two/untitled/images/线-圈-圈.png")); // 替换为实际图标
  314. coilBtn->installEventFilter(this);
  315. coilBtn->setProperty("toolType", "小于等于");
  316. m_leftToolBar->addWidget(coilBtn);
  317. coilBtn->setStyleSheet(R"(
  318. QToolButton {
  319. margin: 2 auto;
  320. background-color: #f0f0f0;
  321. border-radius: 10px;
  322. border: 1px solid #ccc;
  323. padding: 10px 20px;
  324. font-size: 18px;
  325. font-weight: bold;
  326. color: #333;
  327. }
  328. QToolButton:hover {
  329. background-color: #e0e0e0;
  330. }
  331. )");
  332. }
  333. }
  334. // 事件过滤器处理拖拽
  335. bool MainWindow::eventFilter(QObject *obj, QEvent *event)
  336. {
  337. QToolButton *toolBtn = qobject_cast<QToolButton*>(obj);
  338. if (toolBtn && event->type() == QEvent::MouseButtonPress)
  339. {
  340. QMouseEvent *me = static_cast<QMouseEvent*>(event);
  341. if (me->button() == Qt::LeftButton)
  342. {
  343. QString toolType = toolBtn->property("toolType").toString();
  344. if (!toolType.isEmpty())
  345. {
  346. BaseDocument* currentDoc = dynamic_cast<BaseDocument*>(m_tabWidget->currentWidget());
  347. if (currentDoc && currentDoc->type() == BaseDocument::HMI) {
  348. HMIDocument* hmiDoc = static_cast<HMIDocument*>(currentDoc);
  349. // 设置对应的绘制模式
  350. if (toolType == "指示灯")
  351. {
  352. hmiDoc->startDrawingEllipse();
  353. }
  354. else if (toolType == "按钮")
  355. {
  356. hmiDoc->startDrawingRectangle();
  357. }
  358. }
  359. // 创建拖拽对象
  360. QMimeData *mime = new QMimeData;
  361. mime->setText(toolType);
  362. QDrag *drag = new QDrag(toolBtn);
  363. drag->setMimeData(mime);
  364. drag->exec(Qt::CopyAction);
  365. return true;
  366. }
  367. }
  368. }
  369. return QMainWindow::eventFilter(obj, event);
  370. }
  371. // 新建HMI文档
  372. void MainWindow::onNewHMI()
  373. {
  374. m_hmiCount++;
  375. HMIDocument *doc = new HMIDocument;
  376. doc->setTitle("HMI文档 " + QString::number(m_hmiCount));
  377. m_tabWidget->addTab(doc, doc->title());
  378. m_tabWidget->setCurrentWidget(doc);
  379. updateToolBar(doc); // 更新工具栏为HMI工具
  380. }
  381. // 新建PLC文档
  382. void MainWindow::onNewPLC()
  383. {
  384. m_plcCount++;
  385. PLCDocument *doc = new PLCDocument;
  386. m_tabWidget->addTab(doc, QString("PLC文档 %1").arg(m_plcCount));
  387. m_tabWidget->setCurrentWidget(doc);
  388. updateToolBar(doc); // 更新工具栏为PLC工具
  389. }
  390. // 标签页切换时更新工具栏
  391. void MainWindow::onTabChanged(int idx)
  392. {
  393. if (idx < 0)
  394. {
  395. updateToolBar(nullptr);
  396. return;
  397. }
  398. BaseDocument *doc = dynamic_cast<BaseDocument*>(m_tabWidget->widget(idx));
  399. updateToolBar(doc);
  400. }
  401. // 保存文档
  402. void MainWindow::onSave()
  403. {
  404. BaseDocument *doc = dynamic_cast<BaseDocument*>(m_tabWidget->currentWidget());
  405. if (!doc) return;
  406. if (doc->filePath().isEmpty()) {
  407. saveDocumentAs(doc);
  408. } else {
  409. saveDocument(doc);
  410. }
  411. }
  412. // 另存为文档
  413. void MainWindow::onSaveAs()
  414. {
  415. BaseDocument *doc = dynamic_cast<BaseDocument*>(m_tabWidget->currentWidget());
  416. if (doc) {
  417. saveDocumentAs(doc);
  418. }
  419. }
  420. // 打开文档
  421. void MainWindow::onOpen()
  422. {
  423. QString filePath = QFileDialog::getOpenFileName(
  424. this,
  425. "打开文档",
  426. "",
  427. "HMI文档 (*.hmi);;PLC文档 (*.plc)"
  428. );
  429. if (filePath.isEmpty()) return;
  430. QFileInfo fileInfo(filePath);
  431. BaseDocument *doc = nullptr;
  432. if (fileInfo.suffix().toLower() == "hmi") {
  433. doc = new HMIDocument;
  434. } else if (fileInfo.suffix().toLower() == "plc") {
  435. doc = new PLCDocument;
  436. } else {
  437. QMessageBox::warning(this, "打开文档", "不支持的文件格式");
  438. return;
  439. }
  440. if (doc->loadFromFile(filePath)) {
  441. m_tabWidget->addTab(doc, doc->title());
  442. m_tabWidget->setCurrentWidget(doc);
  443. updateToolBar(doc);
  444. } else {
  445. QMessageBox::critical(this, "打开文档", "无法加载文档");
  446. delete doc;
  447. }
  448. }
  449. // 关闭标签页
  450. void MainWindow::onCloseTab(int index)
  451. {
  452. BaseDocument *doc = dynamic_cast<BaseDocument*>(m_tabWidget->widget(index));
  453. if (!doc) return;
  454. if (doc->isModified())
  455. {
  456. QMessageBox::StandardButton reply = QMessageBox::question(
  457. this,
  458. "保存文档",
  459. QString("文档 '%1' 已修改,是否保存更改?").arg(doc->title()),
  460. QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel
  461. );
  462. if (reply == QMessageBox::Save) {
  463. saveDocument(doc);
  464. } else if (reply == QMessageBox::Cancel) {
  465. return;
  466. }
  467. }
  468. m_tabWidget->removeTab(index);
  469. delete doc;
  470. }
  471. // 保存文档
  472. void MainWindow::saveDocument(BaseDocument *doc)
  473. {
  474. if (doc->saveToFile(doc->filePath()))
  475. {
  476. doc->setModified(false); // 清除修改状态
  477. QMessageBox::information(this, "保存文档", "文档保存成功");
  478. } else {
  479. QMessageBox::critical(this, "保存文档", "无法保存文档");
  480. }
  481. }
  482. // 另存为文档
  483. void MainWindow::saveDocumentAs(BaseDocument *doc)
  484. {
  485. QString filePath = QFileDialog::getSaveFileName(
  486. this,
  487. "另存为",
  488. doc->filePath().isEmpty() ? doc->title() : doc->filePath(),
  489. doc->type() == BaseDocument::HMI ?"HMI文档 (*.hmi)" :"PLC文档 (*.plc)"
  490. );
  491. if (filePath.isEmpty()) return;
  492. if (doc->saveToFile(filePath)) {
  493. doc->setModified(false); // 清除修改状态
  494. QMessageBox::information(this, "保存文档", "文档保存成功");
  495. } else {
  496. QMessageBox::critical(this, "保存文档", "无法保存文档");
  497. }
  498. }