Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

385 строки
14 KiB

  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include"hmiwidget.h"
  4. #include<QDebug>
  5. #include<QDir>
  6. #include <QGraphicsView>
  7. #include <QGraphicsScene>
  8. #include <QPushButton>
  9. #include <QColorDialog>
  10. #include <QLineEdit>
  11. #include <QLabel>
  12. #include <QDialogButtonBox>
  13. #include <QFormLayout>
  14. MainWindow::MainWindow(QWidget *parent)
  15. : QMainWindow(parent)
  16. , ui(new Ui::MainWindow)
  17. ,canDrawEllipse(false)
  18. ,canDrawRectangle(false)
  19. {
  20. ui->setupUi(this);
  21. addDockWidget(Qt::BottomDockWidgetArea, ui->dockWidget_3);//将dockWidget_3添加到主窗口的下方
  22. scene = new QGraphicsScene(this);
  23. scene->setSceneRect(0, 0, 800, 600);//因为场景初始无内容时,QGraphicsView 自动将场景中心与视图中心对齐
  24. scene->setBackgroundBrush(QBrush(Qt::lightGray));
  25. ui->graphicsView_2->setScene(scene);
  26. ui->graphicsView_2->setRenderHint(QPainter::Antialiasing);
  27. ui->graphicsView_2->setDragMode(QGraphicsView::RubberBandDrag);
  28. ui->graphicsView_2->setAcceptDrops(true);// 启用视图的拖放功能(接收拖拽)
  29. ui->graphicsView_2->viewport()->installEventFilter(this);
  30. ui->treeWidget_2->setDragEnabled(true);// 允许拖拽
  31. ui->treeWidget_2->setDragDropMode(QAbstractItemView::DragOnly);// 仅拖拽
  32. ui->actiondelete->setShortcut(QKeySequence::Delete);//设置快捷键
  33. ui->actioncopy->setShortcut(QKeySequence::Copy);
  34. ui->actionpaste->setShortcut(QKeySequence::Paste);
  35. ui->treeWidget->topLevelItem(0)->setIcon(0, QIcon("../two/IntegratedPlatform/images/T-常开触点-01.png"));
  36. ui->treeWidget->topLevelItem(1)->setIcon(0, QIcon("../two/IntegratedPlatform/images/T-常闭触点-01-01.png"));
  37. ui->treeWidget->topLevelItem(2)->setIcon(0, QIcon("../two/IntegratedPlatform/images/大于等于.png"));
  38. ui->treeWidget->topLevelItem(3)->setIcon(0, QIcon("../two/IntegratedPlatform/images/线-圈-圈.png"));
  39. ui->treeWidget_2->topLevelItem(0)->setIcon(0, QIcon("../two/IntegratedPlatform/images/灯泡.png"));
  40. ui->treeWidget_2->topLevelItem(1)->setIcon(0, QIcon("../two/IntegratedPlatform/images/按钮.png"));
  41. connect(ui->treeWidget_2, &QTreeWidget::itemClicked, this, &MainWindow::onHmiItemClicked);
  42. connect(ui->actiondelete, &QAction::triggered, this, &MainWindow::onActionDeleteTriggered);
  43. connect(ui->actioncopy, &QAction::triggered, this, &MainWindow::onActionCopyTriggered);
  44. connect(ui->actionpaste, &QAction::triggered, this, &MainWindow::onActionPasteTriggered);
  45. }
  46. MainWindow::~MainWindow()
  47. {
  48. delete ui;
  49. }
  50. void MainWindow::onHmiItemClicked(QTreeWidgetItem *item)
  51. {
  52. if (item->text(0) == "指示灯")
  53. {
  54. canDrawEllipse = true;
  55. canDrawRectangle = false;
  56. }
  57. else if (item->text(0) == "按钮")
  58. {
  59. canDrawEllipse = false;
  60. canDrawRectangle = true;
  61. }
  62. else
  63. {
  64. canDrawEllipse = false;
  65. canDrawRectangle = false;
  66. }
  67. }
  68. bool MainWindow::eventFilter(QObject *obj, QEvent *event)
  69. {
  70. if (obj != ui->graphicsView_2->viewport())
  71. {
  72. return QMainWindow::eventFilter(obj, event);
  73. }
  74. if (event->type() == QEvent::MouseButtonPress)//点击生成
  75. {
  76. QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
  77. if (mouseEvent->button() == Qt::RightButton)//打开右键菜单
  78. {
  79. QPointF scenePos = ui->graphicsView_2->mapToScene(mouseEvent->pos());
  80. QGraphicsItem *item = scene->itemAt(scenePos, ui->graphicsView_2->transform());
  81. if (item && !item->isSelected())//如果有项在点击位置,选中它并清除其他选择
  82. {
  83. scene->clearSelection();//清除所有当前选择
  84. item->setSelected(true);//选中当前项
  85. }
  86. QPoint globalPos = mouseEvent->globalPos();
  87. showContextMenu(globalPos);
  88. return true;
  89. }
  90. if (mouseEvent->button() == Qt::LeftButton)
  91. {
  92. QPointF scenePos = ui->graphicsView_2->mapToScene(mouseEvent->pos());
  93. QGraphicsItem *item = scene->itemAt(scenePos, ui->graphicsView_2->transform());
  94. if (item)
  95. {
  96. return QMainWindow::eventFilter(obj, event);
  97. }
  98. if (canDrawEllipse)
  99. {
  100. createEllipse(scenePos); // 封装为函数,避免重复代码
  101. resetDrawFlags();
  102. }
  103. else if (canDrawRectangle)
  104. {
  105. createRectangle(scenePos); // 封装为函数
  106. resetDrawFlags();
  107. }
  108. if (!item)
  109. {
  110. scene->clearSelection();
  111. if (ui->treeWidget_2->currentItem())
  112. {
  113. ui->treeWidget_2->currentItem()->setSelected(false);
  114. }
  115. }
  116. return true;
  117. }
  118. }
  119. if (event->type() == QEvent::DragEnter)//拖拽生成
  120. {
  121. QDragEnterEvent *dragEvent = static_cast<QDragEnterEvent*>(event);
  122. if (dragEvent->source() == ui->treeWidget_2)//检查拖拽源是否为树控件,并接受拖拽
  123. {
  124. dragEvent->acceptProposedAction();
  125. return true;
  126. }
  127. }
  128. // 拖拽移动(可选:显示拖拽反馈)
  129. if (event->type() == QEvent::DragMove)
  130. {
  131. QDragMoveEvent *dragEvent = static_cast<QDragMoveEvent*>(event);
  132. dragEvent->acceptProposedAction();
  133. return true;
  134. }
  135. // 拖拽释放(生成图形)
  136. if (event->type() == QEvent::Drop)
  137. {
  138. QDropEvent *dropEvent = static_cast<QDropEvent*>(event);
  139. QModelIndex index = ui->treeWidget_2->currentIndex();// 获取拖拽的树项
  140. if (!index.isValid()) return true;
  141. QTreeWidgetItem *item = ui->treeWidget_2->currentItem();
  142. if (!item) return true;
  143. QPointF scenePos = ui->graphicsView_2->mapToScene(dropEvent->pos());// 计算释放位置(转换为场景坐标)
  144. if (item->text(0) == "指示灯")
  145. {
  146. createEllipse(scenePos);
  147. }
  148. else if (item->text(0) == "按钮")
  149. {
  150. createRectangle(scenePos);
  151. }
  152. dropEvent->acceptProposedAction();
  153. return true;
  154. }
  155. return QMainWindow::eventFilter(obj, event);
  156. }
  157. //删除
  158. void MainWindow::onActionDeleteTriggered()
  159. {
  160. QList<QGraphicsItem*> selectedItems = scene->selectedItems();//获取场景中所有选中的项
  161. foreach (QGraphicsItem *item, selectedItems)//遍历并删除所有选中的项
  162. {
  163. scene->removeItem(item);
  164. delete item;//删除对象
  165. }
  166. }
  167. // 复制功能
  168. void MainWindow::onActionCopyTriggered()
  169. {
  170. copiedItemsData.clear();
  171. QList<QGraphicsItem*> selectedItems = scene->selectedItems();
  172. if (selectedItems.isEmpty()) return;
  173. foreach (QGraphicsItem *item, selectedItems)
  174. {
  175. QByteArray itemData;
  176. QDataStream stream(&itemData, QIODevice::WriteOnly);
  177. stream << item->type();// 基础属性
  178. stream << item->pos();
  179. stream << item->flags();
  180. stream << item->transform();
  181. stream << item->isVisible();
  182. if (auto shapeItem = dynamic_cast<QAbstractGraphicsShapeItem*>(item))//处理所有图形形状项
  183. {
  184. stream << shapeItem->pen();
  185. stream << shapeItem->brush();
  186. stream << shapeItem->boundingRect();
  187. }
  188. if (auto resizableRect = dynamic_cast<ResizableRectangle*>(item))//处理矩形圆形两项,存储几何信息
  189. {
  190. stream << resizableRect->rect();//实际存储的矩形
  191. }
  192. else if (auto resizableEllipse = dynamic_cast<ResizableEllipse*>(item))
  193. {
  194. stream << resizableEllipse->rect();
  195. }
  196. copiedItemsData.append(itemData);
  197. }
  198. lastPastePos = selectedItems.first()->pos();
  199. }
  200. // 粘贴功能
  201. void MainWindow::onActionPasteTriggered()
  202. {
  203. if (copiedItemsData.isEmpty()) return;
  204. QPointF offset(20,20);
  205. lastPastePos+=offset;
  206. scene->clearSelection();
  207. foreach (const QByteArray &itemData, copiedItemsData)
  208. {
  209. QDataStream stream(itemData);
  210. int itemType;
  211. QPointF pos;
  212. QGraphicsItem::GraphicsItemFlags flags;
  213. QTransform transform;
  214. bool visible;
  215. stream >> itemType >> pos >> flags >> transform >> visible;
  216. QGraphicsItem *newItem = nullptr;
  217. switch (itemType)
  218. {
  219. case QGraphicsRectItem::Type:
  220. {
  221. QPen pen;
  222. QBrush brush;
  223. QRectF rect;
  224. stream >> pen >> brush >> rect;
  225. ResizableRectangle *rectItem = new ResizableRectangle(rect.x(), rect.y(), rect.width(), rect.height());
  226. rectItem->setPen(pen);
  227. rectItem->setBrush(brush);
  228. newItem = rectItem;
  229. break;
  230. }
  231. case QGraphicsEllipseItem::Type:
  232. {
  233. QPen pen;
  234. QBrush brush;
  235. QRectF rect;
  236. stream >> pen >> brush >> rect;
  237. ResizableEllipse *ellipseItem = new ResizableEllipse(rect.x(), rect.y(), rect.width(), rect.height());
  238. ellipseItem->setPen(pen);
  239. ellipseItem->setBrush(brush);
  240. newItem = ellipseItem;
  241. break;
  242. }
  243. }
  244. if (newItem) {
  245. scene->addItem(newItem);
  246. newItem->setPos(lastPastePos);
  247. newItem->setFlags(flags);
  248. newItem->setTransform(transform);
  249. newItem->setVisible(visible);
  250. newItem->setSelected(true);
  251. }
  252. }
  253. }
  254. //属性功能
  255. void MainWindow::onActionPropertiesTriggered()
  256. {
  257. QList<QGraphicsItem*> selectedItems = scene->selectedItems();
  258. if (selectedItems.isEmpty()) return;
  259. QGraphicsItem* selectedItem = selectedItems.first();
  260. QDialog dialog(this);// 创建对话框
  261. dialog.setWindowTitle("属性设置");
  262. QFormLayout* formLayout = new QFormLayout(&dialog);
  263. QColor tempOnColor = Qt::green;//临时变量存储选择的颜色
  264. QColor tempOffColor = Qt::red;//临时变量存储选择的颜色
  265. QLineEdit* nameEdit = new QLineEdit(&dialog);//对象输入框
  266. if (auto namedItem = dynamic_cast<NamedItem*>(selectedItem))
  267. {
  268. nameEdit->setText(namedItem->name());
  269. }
  270. // 开状态颜色选择
  271. QPushButton* onColorBtn = new QPushButton("", &dialog);
  272. onColorBtn->setStyleSheet("background-color:" + tempOnColor.name());;
  273. connect(onColorBtn, &QPushButton::clicked, [&]()
  274. {
  275. QColor newColor = QColorDialog::getColor(tempOnColor, &dialog, "选择ON状态颜色");
  276. tempOnColor = newColor;
  277. onColorBtn->setStyleSheet("background-color:" + tempOnColor.name());;
  278. });
  279. // 关状态颜色选择
  280. QPushButton* offColorBtn = new QPushButton("", &dialog);
  281. offColorBtn->setStyleSheet("background-color:"+tempOffColor.name());
  282. connect(offColorBtn, &QPushButton::clicked, [&]()
  283. {
  284. QColor newColor = QColorDialog::getColor(tempOffColor, &dialog, "选择OFF状态颜色");
  285. tempOffColor = newColor;
  286. offColorBtn->setStyleSheet("background-color:"+tempOffColor.name());
  287. });
  288. formLayout->addRow("对象:", nameEdit);
  289. formLayout->addRow("ON颜色:", onColorBtn);
  290. formLayout->addRow("OFF颜色:", offColorBtn);
  291. QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
  292. formLayout->addRow(buttonBox);
  293. connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
  294. connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
  295. if (dialog.exec() == QDialog::Accepted)//显示对话框并应用更改
  296. {
  297. QString newName = nameEdit->text();// 应用新属性到图形项
  298. if (auto ellipse = dynamic_cast<ResizableEllipse*>(selectedItem))
  299. {
  300. ellipse->setOnColor(tempOnColor);
  301. ellipse->setOffColor(tempOffColor);
  302. ellipse->setName(newName);
  303. ellipse->setBrush(tempOnColor); // 应用开状态颜色
  304. }
  305. else if (auto rect = dynamic_cast<ResizableRectangle*>(selectedItem))
  306. {
  307. rect->setPressedColor(tempOnColor);
  308. rect->setReleasedColor(tempOffColor);
  309. rect->setName(newName);
  310. rect->setBrush(tempOffColor); // 应用关状态颜色
  311. }
  312. selectedItem->update();
  313. }
  314. }
  315. void MainWindow::createEllipse(const QPointF &pos)
  316. {
  317. ResizableEllipse *ellipse = new ResizableEllipse(pos.x(), pos.y(), 50, 50);
  318. ellipse->setBrush(QBrush(Qt::red));
  319. ellipse->setPen(QPen(Qt::black, 1));
  320. scene->addItem(ellipse);
  321. ellipse->setSelected(true);
  322. }
  323. void MainWindow::createRectangle(const QPointF &pos)
  324. {
  325. ResizableRectangle *rectangle = new ResizableRectangle(pos.x(), pos.y(), 100, 50);
  326. rectangle->setBrush(QBrush(Qt::yellow));
  327. rectangle->setPen(QPen(Qt::black, 1));
  328. scene->addItem(rectangle);
  329. rectangle->setSelected(true);
  330. }
  331. void MainWindow::resetDrawFlags()
  332. {
  333. canDrawEllipse = false;
  334. canDrawRectangle = false;
  335. if (ui->treeWidget_2->currentItem())
  336. {
  337. ui->treeWidget_2->currentItem()->setSelected(false);
  338. }
  339. }
  340. void MainWindow::showContextMenu(QPoint pos)
  341. {
  342. QPoint viewportPos = ui->graphicsView_2->mapFromGlobal(pos);
  343. QPointF scenePos = ui->graphicsView_2->mapToScene(viewportPos);
  344. QGraphicsItem* clickedItem = scene->itemAt(scenePos, ui->graphicsView_2->transform());//检查是否有图形项在点击位置
  345. QMenu contextMenu(this);
  346. if (!clickedItem)
  347. {
  348. QAction* pasteAction = contextMenu.addAction("粘贴");// 空白处右键:只添加粘贴选项
  349. pasteAction->setEnabled(!copiedItemsData.isEmpty());
  350. connect(pasteAction, &QAction::triggered, this, &MainWindow::onActionPasteTriggered);
  351. contextMenu.exec(pos+QPoint(10, 10));
  352. return;
  353. }
  354. // 添加动作
  355. QAction* propertiesAction = contextMenu.addAction("属性");
  356. QAction* copyAction = contextMenu.addAction("复制");
  357. QAction* pasteAction = contextMenu.addAction("粘贴");
  358. QAction* deleteAction = contextMenu.addAction("删除");
  359. QAction* onAction = contextMenu.addAction("置为ON");
  360. QAction* offAction = contextMenu.addAction("置为OFF");
  361. pasteAction->setEnabled(!copiedItemsData.isEmpty());
  362. // 连接动作到现有功能
  363. connect(deleteAction, &QAction::triggered, this, &MainWindow::onActionDeleteTriggered);
  364. connect(copyAction, &QAction::triggered, this, &MainWindow::onActionCopyTriggered);
  365. connect(pasteAction, &QAction::triggered, this, &MainWindow::onActionPasteTriggered);
  366. connect(propertiesAction, &QAction::triggered, this, &MainWindow::onActionPropertiesTriggered);
  367. contextMenu.exec(pos+QPoint(10, 10));
  368. }