您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

263 行
9.3 KiB

  1. #include "hmicontrolitem.h"
  2. #include <QPainter>
  3. #include <QGraphicsScene>
  4. #include <QCursor>
  5. #include <QMenu>
  6. #include <QAction>
  7. #include <QGraphicsView>
  8. #include <QColorDialog>
  9. #include <QDebug>
  10. #include <QInputDialog>
  11. #include "hmibutton.h"
  12. #include "hmiled.h"
  13. #include <QMessageBox>
  14. // 静态剪贴板数据,初始化为空
  15. QVariantMap HmiControlItem::m_clipboardData;
  16. // 构造函数:初始化控件基本属性
  17. HmiControlItem::HmiControlItem(QGraphicsItem* parent)
  18. : QObject(nullptr), QGraphicsItem(parent), m_registerAddress(-1)
  19. {
  20. // 设置控件属性:可移动、可选择、发送几何变化通知
  21. setFlags(QGraphicsItem::ItemIsMovable |
  22. QGraphicsItem::ItemIsSelectable |
  23. QGraphicsItem::ItemSendsGeometryChanges);
  24. // 启用鼠标悬停事件
  25. setAcceptHoverEvents(true);
  26. // 设置变换原点为控件左上角
  27. setTransformOriginPoint(0, 0);
  28. }
  29. // 检查鼠标是否在右下角缩放区域
  30. // 返回:true(在缩放区域内),false(不在)
  31. bool HmiControlItem::isInScaleArea(const QPointF& pos) {
  32. QRectF contentRect = boundingRect().adjusted(1, 1, -1, -1);
  33. return (pos.x() >= contentRect.width() - m_scaleAreaSize &&
  34. pos.x() <= contentRect.width()) &&
  35. (pos.y() >= contentRect.height() - m_scaleAreaSize &&
  36. pos.y() <= contentRect.height());
  37. }
  38. // 鼠标悬停事件处理:根据鼠标位置设置光标样式
  39. void HmiControlItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event) {
  40. if (isSelected()) {
  41. // 如果控件被选中
  42. if (isInScaleArea(event->pos())) {
  43. // 鼠标在右下角缩放区域,显示缩放光标
  44. setCursor(Qt::SizeFDiagCursor);
  45. } else {
  46. // 鼠标在控件其他区域,显示移动光标
  47. setCursor(Qt::SizeAllCursor);
  48. }
  49. } else {
  50. // 控件未选中,显示默认光标
  51. setCursor(Qt::ArrowCursor);
  52. }
  53. QGraphicsItem::hoverMoveEvent(event);
  54. }
  55. // 鼠标按下事件处理:开始拖动或缩放
  56. void HmiControlItem::mousePressEvent(QGraphicsSceneMouseEvent* event) {
  57. if (isSelected() && isInScaleArea(event->pos())) {
  58. // 选中控件且点击缩放区域,进入缩放模式
  59. m_isScaling = true;
  60. m_originalRect = boundingRect().adjusted(1, 1, -1, -1);
  61. m_scaleStartPos = event->pos();
  62. event->accept();
  63. return;
  64. }
  65. // 记录拖动开始位置
  66. m_dragStartPos = event->pos();
  67. QGraphicsItem::mousePressEvent(event);
  68. }
  69. // 鼠标移动事件处理:处理控件拖动或缩放
  70. void HmiControlItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
  71. if (m_isScaling) {
  72. // 缩放模式:根据鼠标移动调整控件大小
  73. qreal deltaX = event->pos().x() - m_scaleStartPos.x();
  74. QRectF currentRect = transform().mapRect(m_originalRect);
  75. qreal newWidth = currentRect.width() + deltaX;
  76. newWidth = qMax(m_minWidth, qMin(newWidth, m_maxWidth));
  77. qreal aspectRatio = getAspectRatio();
  78. qreal newHeight = newWidth / aspectRatio;
  79. newHeight = qMax(m_minHeight, qMin(newHeight, m_maxHeight));
  80. newWidth = newHeight * aspectRatio;
  81. if (qAbs(newWidth - currentRect.width()) > 1 ||
  82. qAbs(newHeight - currentRect.height()) > 1) {
  83. // 更新控件大小,应用缩放变换
  84. prepareGeometryChange();
  85. qreal scaleX = newWidth / m_originalRect.width();
  86. qreal scaleY = newHeight / m_originalRect.height();
  87. resetTransform();
  88. setTransform(QTransform::fromScale(scaleX, scaleY), false);
  89. update();
  90. }
  91. event->accept();
  92. return;
  93. }
  94. if (isSelected()) {
  95. // 拖动模式:移动控件位置
  96. QPointF delta = event->pos() - m_dragStartPos;
  97. QPointF newPos = pos() + delta;
  98. QRectF itemRect = transform().mapRect(boundingRect());
  99. QRectF sceneRect = scene()->sceneRect();
  100. // 限制控件在场景边界内
  101. newPos.setX(qMax(sceneRect.left(), qMin(newPos.x(), sceneRect.right() - itemRect.width())));
  102. newPos.setY(qMax(sceneRect.top(), qMin(newPos.y(), sceneRect.bottom() - itemRect.height())));
  103. if (newPos.x() + itemRect.width() > sceneRect.right()) {
  104. newPos.setX(sceneRect.right() - itemRect.width());
  105. }
  106. if (newPos.y() + itemRect.height() > sceneRect.bottom()) {
  107. newPos.setY(sceneRect.bottom() - itemRect.height());
  108. }
  109. if (newPos.x() < sceneRect.left()) {
  110. newPos.setX(sceneRect.left());
  111. }
  112. if (newPos.y() < sceneRect.top()) {
  113. newPos.setY(sceneRect.top());
  114. }
  115. setPos(newPos);
  116. if (scene()) {
  117. // 更新场景和视图
  118. scene()->update();
  119. if (scene()->views().size() > 0) {
  120. scene()->views().first()->viewport()->update();
  121. }
  122. }
  123. event->accept();
  124. return;
  125. }
  126. QGraphicsItem::mouseMoveEvent(event);
  127. }
  128. // 鼠标释放事件处理:结束缩放或拖动
  129. void HmiControlItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) {
  130. m_isScaling = false;
  131. QGraphicsItem::mouseReleaseEvent(event);
  132. }
  133. // 右键菜单事件处理:显示控件特定的上下文菜单
  134. void HmiControlItem::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) {
  135. QMenu menu;
  136. createContextMenu(menu); // 子类实现具体菜单项
  137. menu.exec(event->screenPos());
  138. event->accept();
  139. }
  140. // 删除控件:从场景中移除并释放内存
  141. void HmiControlItem::deleteItem() {
  142. if (scene()) {
  143. scene()->removeItem(this);
  144. }
  145. delete this;
  146. }
  147. // 更改控件颜色:弹出颜色对话框选择ON或OFF状态颜色
  148. void HmiControlItem::changeAppearanceColor(bool isOnState, QColor& onColor, QColor& offColor) {
  149. QColor newColor = QColorDialog::getColor(
  150. Qt::white,
  151. nullptr,
  152. isOnState ? "选择ON状态颜色" : "选择OFF状态颜色"
  153. );
  154. if (newColor.isValid()) {
  155. if (isOnState) {
  156. onColor = newColor;
  157. } else {
  158. offColor = newColor;
  159. }
  160. update();
  161. }
  162. }
  163. // 设置寄存器绑定
  164. // 设置寄存器绑定
  165. bool HmiControlItem::setRegisterBinding(int address) {
  166. if (address >= 0 && address <= 4000) {
  167. m_registerAddress = address;
  168. return true;
  169. } else {
  170. qDebug() << "Invalid register binding: address=" << address;
  171. return false;
  172. }
  173. }
  174. // 存储数据到剪贴板
  175. void HmiControlItem::copyToClipboard(const QVariantMap& data) {
  176. m_clipboardData = data;
  177. qDebug() << "Copied to clipboard:" << data;
  178. }
  179. // 获取剪贴板数据
  180. QVariantMap HmiControlItem::getClipboardData() {
  181. return m_clipboardData;
  182. }
  183. // 检查剪贴板是否有数据
  184. bool HmiControlItem::hasClipboardData() {
  185. return !m_clipboardData.isEmpty();
  186. }
  187. // 从剪贴板数据创建控件,指定粘贴位置
  188. HmiControlItem* HmiControlItem::createFromClipboard(const QVariantMap& data, const QPointF& pos, QGraphicsItem* parent) {
  189. QString type = data.value("type").toString();
  190. HmiControlItem* item = nullptr;
  191. if (type == "按钮") {
  192. // 创建按钮控件并恢复属性
  193. item = new HmiButton(parent);
  194. HmiButton* button = static_cast<HmiButton*>(item);
  195. button->setButtonState(data.value("isButtonOn", false).toBool());
  196. button->setOnColor(QColor(data.value("onColor").toString()));
  197. button->setOffColor(QColor(data.value("offColor").toString()));
  198. } else if (type == "指示灯") {
  199. // 创建指示灯控件并恢复属性
  200. item = new HmiLed(parent);
  201. HmiLed* led = static_cast<HmiLed*>(item);
  202. led->setOnColor(QColor(data.value("onColor").toString()));
  203. led->setOffColor(QColor(data.value("offColor").toString()));
  204. }
  205. if (item) {
  206. // 设置粘贴位置
  207. item->setPos(pos);
  208. // 恢复缩放
  209. qreal scaleX = data.value("scaleX", 1.0).toDouble();
  210. qreal scaleY = data.value("scaleY", 1.0).toDouble();
  211. item->setTransform(QTransform::fromScale(scaleX, scaleY));
  212. // 恢复寄存器绑定
  213. item->setRegisterBinding(data.value("registerAddress", -1).toInt());
  214. }
  215. return item;
  216. }
  217. // 创建右键菜单(默认实现,子类可扩展)
  218. void HmiControlItem::createContextMenu(QMenu& menu) {
  219. // 默认添加"设置寄存器"选项
  220. QAction* setRegisterAction = new QAction("设置寄存器", &menu);
  221. QObject::connect(setRegisterAction, &QAction::triggered, [this]() {
  222. bool ok;
  223. // 显示当前绑定的寄存器地址作为默认值
  224. int currentAddress = m_registerAddress >= 0 ? m_registerAddress : 0;
  225. int address = QInputDialog::getInt(nullptr,
  226. "输入寄存器地址",
  227. QString("地址 (0-4000):\n当前地址: %1").arg(currentAddress),
  228. currentAddress, 0, 4000, 1, &ok);
  229. if (ok) {
  230. if (!setRegisterBinding(address)) {
  231. QMessageBox::warning(nullptr, "错误", "无效的寄存器地址");
  232. }
  233. }
  234. });
  235. menu.addAction(setRegisterAction);
  236. }
  237. // 存储控件数据到剪贴板(默认实现)
  238. QVariantMap HmiControlItem::saveToClipboard() const
  239. {
  240. QVariantMap data;
  241. data["type"] = getItemType();
  242. data["posX"] = pos().x();
  243. data["posY"] = pos().y();
  244. data["scaleX"] = transform().m11();
  245. data["scaleY"] = transform().m22();
  246. data["registerAddress"] = m_registerAddress;
  247. return data;
  248. }