综合平台编辑器
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.

359 lines
10 KiB

  1. #include "customgraphics.h"
  2. #include <QPainter>
  3. #include <QGraphicsSceneMouseEvent>
  4. #include <QMenu>
  5. #include <QGraphicsScene>
  6. #include <QColorDialog>
  7. #include <QInputDialog>
  8. #include <QDialog>
  9. #include <QLabel>
  10. #include <QSpinBox>
  11. #include <QHBoxLayout>
  12. #include <QVBoxLayout>
  13. #include <QPushButton>
  14. #include <QGraphicsView>
  15. // HmiComponent 基类实现
  16. HmiComponent::HmiComponent(QGraphicsItem *parent) : QGraphicsObject(parent)
  17. {
  18. setFlag(QGraphicsItem::ItemIsMovable, true);
  19. setFlag(QGraphicsItem::ItemIsSelectable, true);
  20. setAcceptHoverEvents(true);
  21. }
  22. void HmiComponent::setColor(const QColor& color) {
  23. if (m_color != color) {
  24. m_color = color;
  25. update();
  26. }
  27. }
  28. QColor HmiComponent::color() const {
  29. return m_color;
  30. }
  31. void HmiComponent::setComponentName(const QString& name) {
  32. m_componentName = name;
  33. }
  34. QString HmiComponent::componentName() const {
  35. return m_componentName;
  36. }
  37. void HmiComponent::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  38. {
  39. Q_UNUSED(option);
  40. Q_UNUSED(widget);
  41. painter->setRenderHint(QPainter::Antialiasing);
  42. paintShape(painter);
  43. if (isSelected()) {
  44. painter->setBrush(Qt::NoBrush);
  45. painter->setPen(QPen(Qt::darkRed, 2, Qt::DashLine));
  46. painter->drawRect(boundingRect());
  47. }
  48. }
  49. void HmiComponent::setAddress(int address)
  50. {
  51. if (m_address != address) {
  52. m_address = address;
  53. update();
  54. }
  55. }
  56. int HmiComponent::address() const
  57. {
  58. return m_address;
  59. }
  60. void HmiComponent::mousePressEvent(QGraphicsSceneMouseEvent *event)
  61. {
  62. // 右键不触发选中信号,留给 contextMenuEvent 处理
  63. if (event->button() == Qt::LeftButton) {
  64. emit selected(this);
  65. }
  66. QGraphicsObject::mousePressEvent(event);
  67. }
  68. void HmiComponent::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
  69. {
  70. scene()->clearSelection();
  71. setSelected(true);
  72. emit selected(this);
  73. QMenu menu;
  74. QAction *propertyAction = menu.addAction("属性");
  75. QAction *setOnAction = nullptr;
  76. QAction *setOffAction = nullptr;
  77. // 只有按钮才添加“置ON”和“置OFF”
  78. if (auto btn = dynamic_cast<HmiButton*>(this)) {
  79. setOnAction = menu.addAction("置ON");
  80. setOffAction = menu.addAction("置OFF");
  81. connect(setOnAction, &QAction::triggered, this, [btn]() {
  82. btn->setOn(true);
  83. });
  84. connect(setOffAction, &QAction::triggered, this, [btn]() {
  85. btn->setOn(false);
  86. });
  87. }
  88. menu.addSeparator();
  89. QAction *copyAction = menu.addAction("复制");
  90. QAction *deleteAction = menu.addAction("删除");
  91. connect(propertyAction, &QAction::triggered, this, [this]() {
  92. // 弹出属性对话框
  93. QDialog dialog;
  94. dialog.setWindowTitle("属性");
  95. QLabel* addressLabel = new QLabel("地址: ");
  96. QSpinBox* addressSpin = new QSpinBox();
  97. addressSpin->setRange(0, 4000);
  98. addressSpin->setValue(m_address); // 使用当前组件地址初始化
  99. // ON状态颜色设置
  100. QLabel* onColorLabel = new QLabel("ON状态外观: ");
  101. // 颜色显示,用QLabel设置背景色简单示范
  102. QLabel* onColorDisplay = new QLabel;
  103. onColorDisplay->setFixedSize(40, 20);
  104. onColorDisplay->setAutoFillBackground(true);
  105. QPalette onPal = onColorDisplay->palette();
  106. onPal.setColor(QPalette::Window, m_onColor);
  107. onColorDisplay->setPalette(onPal);
  108. onColorDisplay->setFrameShape(QFrame::Box);
  109. QPushButton* onColorBtn = new QPushButton("选择颜色");
  110. // OFF状态颜色设置
  111. QLabel* offColorLabel = new QLabel("OFF状态外观: ");
  112. QLabel* offColorDisplay = new QLabel;
  113. offColorDisplay->setFixedSize(40, 20);
  114. offColorDisplay->setAutoFillBackground(true);
  115. QPalette offPal = offColorDisplay->palette();
  116. offPal.setColor(QPalette::Window, m_offColor);
  117. offColorDisplay->setPalette(offPal);
  118. offColorDisplay->setFrameShape(QFrame::Box);
  119. QPushButton* offColorBtn = new QPushButton("选择颜色");
  120. QObject::connect(offColorBtn, &QPushButton::clicked, [&]() {
  121. QColor color = QColorDialog::getColor(m_offColor, nullptr, "选择 OFF 状态颜色");
  122. if (color.isValid()) {
  123. m_offColor = color;
  124. QPalette pal = offColorDisplay->palette();
  125. pal.setColor(QPalette::Window, color);
  126. offColorDisplay->setPalette(pal);
  127. offColorDisplay->update();
  128. setColor(color); // 默认显示OFF状态颜色
  129. }
  130. });
  131. // 地址布局
  132. QHBoxLayout* addressLayout = new QHBoxLayout();
  133. addressLayout->addWidget(addressLabel);
  134. addressLayout->addWidget(addressSpin);
  135. // ON颜色布局
  136. QHBoxLayout* onColorLayout = new QHBoxLayout();
  137. onColorLayout->addWidget(onColorLabel);
  138. onColorLayout->addWidget(onColorDisplay);
  139. onColorLayout->addWidget(onColorBtn);
  140. // OFF颜色布局
  141. QHBoxLayout* offColorLayout = new QHBoxLayout();
  142. offColorLayout->addWidget(offColorLabel);
  143. offColorLayout->addWidget(offColorDisplay);
  144. offColorLayout->addWidget(offColorBtn);
  145. // 确定/取消按钮
  146. QPushButton* okBtn = new QPushButton("确定");
  147. QPushButton* cancelBtn = new QPushButton("取消");
  148. QHBoxLayout* btnLayout = new QHBoxLayout();
  149. btnLayout->addStretch();
  150. btnLayout->addWidget(okBtn);
  151. btnLayout->addWidget(cancelBtn);
  152. // 颜色选择按钮点击槽
  153. QObject::connect(onColorBtn, &QPushButton::clicked, [&]() {
  154. QColor color = QColorDialog::getColor(m_onColor, nullptr, "选择 ON 状态颜色");
  155. if (color.isValid()) {
  156. m_onColor = color;
  157. QPalette pal = onColorDisplay->palette();
  158. pal.setColor(QPalette::Window, color);
  159. onColorDisplay->setPalette(pal);
  160. onColorDisplay->update();
  161. }
  162. });
  163. QVBoxLayout* mainLayout = new QVBoxLayout();
  164. mainLayout->addLayout(addressLayout);
  165. mainLayout->addLayout(onColorLayout);
  166. mainLayout->addLayout(offColorLayout);
  167. mainLayout->addLayout(btnLayout);
  168. dialog.setLayout(mainLayout);
  169. // 关闭逻辑
  170. QObject::connect(okBtn, &QPushButton::clicked, [&]() {
  171. // 保存地址
  172. int newAddress = addressSpin->value();
  173. setAddress(newAddress);
  174. // 已经在onColorBtn / offColorBtn中修改了m_onColor / m_offColor,需要触发界面更新
  175. update();
  176. dialog.accept();
  177. });
  178. QObject::connect(cancelBtn, &QPushButton::clicked, &dialog, &QDialog::reject);
  179. dialog.exec();
  180. });
  181. connect(copyAction, &QAction::triggered, this, [this]() {
  182. emit copyRequested(this);
  183. });
  184. connect(deleteAction, &QAction::triggered, this, [this]() {
  185. emit deleteRequested(this);
  186. });
  187. menu.exec(event->screenPos());
  188. }
  189. void HmiComponent::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
  190. {
  191. if (!(flags() & QGraphicsItem::ItemIsMovable)) {
  192. // 如果项不可移动,直接调用基类处理
  193. QGraphicsObject::mouseMoveEvent(event);
  194. return;
  195. }
  196. // 计算拖动后的位置
  197. QPointF delta = event->scenePos() - event->lastScenePos();
  198. QPointF newPos = pos() + delta;
  199. // 获取视图(假设只有1个视图)
  200. QList<QGraphicsView*> views = scene()->views();
  201. if (views.isEmpty()) {
  202. // 没有视图则默认处理
  203. QGraphicsObject::mouseMoveEvent(event);
  204. return;
  205. }
  206. QGraphicsView* view = views.first();
  207. // 获取视口矩形(像素坐标)
  208. QRect viewportRect = view->viewport()->rect();
  209. // 将视口矩形映射到场景坐标
  210. QPointF topLeftScene = view->mapToScene(viewportRect.topLeft());
  211. QPointF bottomRightScene = view->mapToScene(viewportRect.bottomRight());
  212. QRectF visibleSceneRect(topLeftScene, bottomRightScene);
  213. // 组件的边界矩形(局部坐标)
  214. QRectF bounds = boundingRect();
  215. // 计算移动后组件边界矩形(在场景坐标)
  216. QRectF newBounds = bounds.translated(newPos);
  217. // 限制组件边界必须完全在视图可见区域内
  218. qreal limitedX = newPos.x();
  219. qreal limitedY = newPos.y();
  220. if (newBounds.left() < visibleSceneRect.left())
  221. limitedX += visibleSceneRect.left() - newBounds.left();
  222. if (newBounds.top() < visibleSceneRect.top())
  223. limitedY += visibleSceneRect.top() - newBounds.top();
  224. if (newBounds.right() > visibleSceneRect.right())
  225. limitedX -= newBounds.right() - visibleSceneRect.right();
  226. if (newBounds.bottom() > visibleSceneRect.bottom())
  227. limitedY -= newBounds.bottom() - visibleSceneRect.bottom();
  228. setPos(QPointF(limitedX, limitedY));
  229. event->accept();
  230. }
  231. void HmiComponent::setOnColor(const QColor& color) {
  232. m_onColor = color;
  233. }
  234. void HmiComponent::setOffColor(const QColor& color) {
  235. m_offColor = color;
  236. setColor(color); // 默认展示 OFF 状态颜色
  237. }
  238. QColor HmiComponent::onColor() const {
  239. return m_onColor;
  240. }
  241. QColor HmiComponent::offColor() const {
  242. return m_offColor;
  243. }
  244. HmiButton::HmiButton(QGraphicsItem *parent) : HmiComponent(parent), m_isOn(false)
  245. {
  246. m_color = Qt::gray;
  247. m_offColor = m_color; // OFF状态颜色设为默认颜色
  248. m_onColor = Qt::green; // ON状态颜色为绿色
  249. m_componentName = "Button";
  250. setColor(m_offColor); // 当前显示OFF颜色
  251. }
  252. bool HmiButton::isOn() const
  253. {
  254. return m_isOn;
  255. }
  256. void HmiButton::setOn(bool on)
  257. {
  258. if (m_isOn != on) {
  259. m_isOn = on;
  260. if (m_isOn)
  261. setColor(m_onColor);
  262. else
  263. setColor(m_offColor);
  264. update();
  265. }
  266. }
  267. QRectF HmiButton::boundingRect() const
  268. {
  269. return QRectF(0, 0, 65, 30);
  270. }
  271. void HmiButton::paintShape(QPainter *painter)
  272. {
  273. painter->setPen(Qt::NoPen);
  274. painter->setBrush(m_color);
  275. painter->drawRect(boundingRect());
  276. }
  277. HmiIndicator::HmiIndicator(QGraphicsItem *parent) : HmiComponent(parent)
  278. {
  279. m_color = Qt::red;
  280. m_offColor = m_color; // OFF状态颜色设为默认颜色
  281. m_onColor = Qt::green; // ON状态颜色为绿色
  282. m_componentName = "Indicator";
  283. setColor(m_offColor); // 当前显示OFF颜色
  284. }
  285. QRectF HmiIndicator::boundingRect() const
  286. {
  287. return QRectF(0, 0, 30, 30);
  288. }
  289. void HmiIndicator::paintShape(QPainter *painter)
  290. {
  291. painter->setPen(Qt::NoPen);
  292. painter->setBrush(m_color);
  293. painter->drawEllipse(boundingRect());
  294. }