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.

386 satır
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. //拖拽生成
  120. if (event->type() == QEvent::DragEnter)
  121. {
  122. QDragEnterEvent *dragEvent = static_cast<QDragEnterEvent*>(event);
  123. if (dragEvent->source() == ui->treeWidget_2)//检查拖拽源是否为树控件,并接受拖拽
  124. {
  125. dragEvent->acceptProposedAction();
  126. return true;
  127. }
  128. }
  129. // 拖拽移动(可选:显示拖拽反馈)
  130. if (event->type() == QEvent::DragMove)
  131. {
  132. QDragMoveEvent *dragEvent = static_cast<QDragMoveEvent*>(event);
  133. dragEvent->acceptProposedAction();
  134. return true;
  135. }
  136. // 拖拽释放(生成图形)
  137. if (event->type() == QEvent::Drop)
  138. {
  139. QDropEvent *dropEvent = static_cast<QDropEvent*>(event);
  140. QModelIndex index = ui->treeWidget_2->currentIndex();// 获取拖拽的树项
  141. if (!index.isValid()) return true;
  142. QTreeWidgetItem *item = ui->treeWidget_2->currentItem();
  143. if (!item) return true;
  144. QPointF scenePos = ui->graphicsView_2->mapToScene(dropEvent->pos());// 计算释放位置(转换为场景坐标)
  145. if (item->text(0) == "指示灯")
  146. {
  147. createEllipse(scenePos);
  148. }
  149. else if (item->text(0) == "按钮")
  150. {
  151. createRectangle(scenePos);
  152. }
  153. dropEvent->acceptProposedAction();
  154. return true;
  155. }
  156. return QMainWindow::eventFilter(obj, event);
  157. }
  158. //删除
  159. void MainWindow::onActionDeleteTriggered()
  160. {
  161. QList<QGraphicsItem*> selectedItems = scene->selectedItems();//获取场景中所有选中的项
  162. foreach (QGraphicsItem *item, selectedItems)//遍历并删除所有选中的项
  163. {
  164. scene->removeItem(item);
  165. delete item;//删除对象
  166. }
  167. }
  168. // 复制功能
  169. void MainWindow::onActionCopyTriggered()
  170. {
  171. copiedItemsData.clear();
  172. QList<QGraphicsItem*> selectedItems = scene->selectedItems();
  173. if (selectedItems.isEmpty()) return;
  174. foreach (QGraphicsItem *item, selectedItems)
  175. {
  176. QByteArray itemData;
  177. QDataStream stream(&itemData, QIODevice::WriteOnly);
  178. stream << item->type();// 基础属性
  179. stream << item->pos();
  180. stream << item->flags();
  181. stream << item->transform();
  182. stream << item->isVisible();
  183. if (auto shapeItem = dynamic_cast<QAbstractGraphicsShapeItem*>(item))//处理所有图形形状项
  184. {
  185. stream << shapeItem->pen();
  186. stream << shapeItem->brush();
  187. stream << shapeItem->boundingRect();
  188. }
  189. if (auto resizableRect = dynamic_cast<ResizableRectangle*>(item))//处理矩形圆形两项,存储几何信息
  190. {
  191. stream << resizableRect->rect();//实际存储的矩形
  192. }
  193. else if (auto resizableEllipse = dynamic_cast<ResizableEllipse*>(item))
  194. {
  195. stream << resizableEllipse->rect();
  196. }
  197. copiedItemsData.append(itemData);
  198. }
  199. lastPastePos = selectedItems.first()->pos();
  200. }
  201. // 粘贴功能
  202. void MainWindow::onActionPasteTriggered()
  203. {
  204. if (copiedItemsData.isEmpty()) return;
  205. QPointF offset(20,20);
  206. lastPastePos+=offset;
  207. scene->clearSelection();
  208. foreach (const QByteArray &itemData, copiedItemsData)
  209. {
  210. QDataStream stream(itemData);
  211. int itemType;
  212. QPointF pos;
  213. QGraphicsItem::GraphicsItemFlags flags;
  214. QTransform transform;
  215. bool visible;
  216. stream >> itemType >> pos >> flags >> transform >> visible;
  217. QGraphicsItem *newItem = nullptr;
  218. switch (itemType)
  219. {
  220. case QGraphicsRectItem::Type:
  221. {
  222. QPen pen;
  223. QBrush brush;
  224. QRectF rect;
  225. stream >> pen >> brush >> rect;
  226. ResizableRectangle *rectItem = new ResizableRectangle(rect.x(), rect.y(), rect.width(), rect.height());
  227. rectItem->setPen(pen);
  228. rectItem->setBrush(brush);
  229. newItem = rectItem;
  230. break;
  231. }
  232. case QGraphicsEllipseItem::Type:
  233. {
  234. QPen pen;
  235. QBrush brush;
  236. QRectF rect;
  237. stream >> pen >> brush >> rect;
  238. ResizableEllipse *ellipseItem = new ResizableEllipse(rect.x(), rect.y(), rect.width(), rect.height());
  239. ellipseItem->setPen(pen);
  240. ellipseItem->setBrush(brush);
  241. newItem = ellipseItem;
  242. break;
  243. }
  244. }
  245. if (newItem) {
  246. scene->addItem(newItem);
  247. newItem->setPos(lastPastePos);
  248. newItem->setFlags(flags);
  249. newItem->setTransform(transform);
  250. newItem->setVisible(visible);
  251. newItem->setSelected(true);
  252. }
  253. }
  254. }
  255. //属性功能
  256. void MainWindow::onActionPropertiesTriggered()
  257. {
  258. QList<QGraphicsItem*> selectedItems = scene->selectedItems();
  259. if (selectedItems.isEmpty()) return;
  260. QGraphicsItem* selectedItem = selectedItems.first();
  261. QDialog dialog(this);// 创建对话框
  262. dialog.setWindowTitle("属性设置");
  263. QFormLayout* formLayout = new QFormLayout(&dialog);
  264. QColor tempOnColor = Qt::green;//临时变量存储选择的颜色
  265. QColor tempOffColor = Qt::red;//临时变量存储选择的颜色
  266. QLineEdit* nameEdit = new QLineEdit(&dialog);//对象输入框
  267. if (auto namedItem = dynamic_cast<NamedItem*>(selectedItem))
  268. {
  269. nameEdit->setText(namedItem->name());
  270. }
  271. // 开状态颜色选择
  272. QPushButton* onColorBtn = new QPushButton("", &dialog);
  273. onColorBtn->setStyleSheet("background-color:" + tempOnColor.name());;
  274. connect(onColorBtn, &QPushButton::clicked, [&]()
  275. {
  276. QColor newColor = QColorDialog::getColor(tempOnColor, &dialog, "选择ON状态颜色");
  277. tempOnColor = newColor;
  278. onColorBtn->setStyleSheet("background-color:" + tempOnColor.name());;
  279. });
  280. // 关状态颜色选择
  281. QPushButton* offColorBtn = new QPushButton("", &dialog);
  282. offColorBtn->setStyleSheet("background-color:"+tempOffColor.name());
  283. connect(offColorBtn, &QPushButton::clicked, [&]()
  284. {
  285. QColor newColor = QColorDialog::getColor(tempOffColor, &dialog, "选择OFF状态颜色");
  286. tempOffColor = newColor;
  287. offColorBtn->setStyleSheet("background-color:"+tempOffColor.name());
  288. });
  289. formLayout->addRow("对象:", nameEdit);
  290. formLayout->addRow("ON颜色:", onColorBtn);
  291. formLayout->addRow("OFF颜色:", offColorBtn);
  292. QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
  293. formLayout->addRow(buttonBox);
  294. connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
  295. connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
  296. if (dialog.exec() == QDialog::Accepted)//显示对话框并应用更改
  297. {
  298. QString newName = nameEdit->text();// 应用新属性到图形项
  299. if (auto ellipse = dynamic_cast<ResizableEllipse*>(selectedItem))
  300. {
  301. ellipse->setOnColor(tempOnColor);
  302. ellipse->setOffColor(tempOffColor);
  303. ellipse->setName(newName);
  304. ellipse->setBrush(tempOnColor); // 应用开状态颜色
  305. }
  306. else if (auto rect = dynamic_cast<ResizableRectangle*>(selectedItem))
  307. {
  308. rect->setPressedColor(tempOnColor);
  309. rect->setReleasedColor(tempOffColor);
  310. rect->setName(newName);
  311. rect->setBrush(tempOffColor); // 应用关状态颜色
  312. }
  313. selectedItem->update();
  314. }
  315. }
  316. void MainWindow::createEllipse(const QPointF &pos)
  317. {
  318. ResizableEllipse *ellipse = new ResizableEllipse(pos.x(), pos.y(), 50, 50);
  319. ellipse->setBrush(QBrush(Qt::red));
  320. ellipse->setPen(QPen(Qt::black, 1));
  321. scene->addItem(ellipse);
  322. ellipse->setSelected(true);
  323. }
  324. void MainWindow::createRectangle(const QPointF &pos)
  325. {
  326. ResizableRectangle *rectangle = new ResizableRectangle(pos.x(), pos.y(), 100, 50);
  327. rectangle->setBrush(QBrush(Qt::yellow));
  328. rectangle->setPen(QPen(Qt::black, 1));
  329. scene->addItem(rectangle);
  330. rectangle->setSelected(true);
  331. }
  332. void MainWindow::resetDrawFlags()
  333. {
  334. canDrawEllipse = false;
  335. canDrawRectangle = false;
  336. if (ui->treeWidget_2->currentItem())
  337. {
  338. ui->treeWidget_2->currentItem()->setSelected(false);
  339. }
  340. }
  341. void MainWindow::showContextMenu(QPoint pos)
  342. {
  343. QPoint viewportPos = ui->graphicsView_2->mapFromGlobal(pos);
  344. QPointF scenePos = ui->graphicsView_2->mapToScene(viewportPos);
  345. QGraphicsItem* clickedItem = scene->itemAt(scenePos, ui->graphicsView_2->transform());//检查是否有图形项在点击位置
  346. QMenu contextMenu(this);
  347. if (!clickedItem)
  348. {
  349. QAction* pasteAction = contextMenu.addAction("粘贴");// 空白处右键:只添加粘贴选项
  350. pasteAction->setEnabled(!copiedItemsData.isEmpty());
  351. connect(pasteAction, &QAction::triggered, this, &MainWindow::onActionPasteTriggered);
  352. contextMenu.exec(pos+QPoint(10, 10));
  353. return;
  354. }
  355. // 添加动作
  356. QAction* propertiesAction = contextMenu.addAction("属性");
  357. QAction* copyAction = contextMenu.addAction("复制");
  358. QAction* pasteAction = contextMenu.addAction("粘贴");
  359. QAction* deleteAction = contextMenu.addAction("删除");
  360. QAction* onAction = contextMenu.addAction("置为ON");
  361. QAction* offAction = contextMenu.addAction("置为OFF");
  362. pasteAction->setEnabled(!copiedItemsData.isEmpty());
  363. // 连接动作到现有功能
  364. connect(deleteAction, &QAction::triggered, this, &MainWindow::onActionDeleteTriggered);
  365. connect(copyAction, &QAction::triggered, this, &MainWindow::onActionCopyTriggered);
  366. connect(pasteAction, &QAction::triggered, this, &MainWindow::onActionPasteTriggered);
  367. connect(propertiesAction, &QAction::triggered, this, &MainWindow::onActionPropertiesTriggered);
  368. contextMenu.exec(pos+QPoint(10, 10));
  369. }