diff --git a/customgraphics.cpp b/customgraphics.cpp index d867b2f..167f8ca 100644 --- a/customgraphics.cpp +++ b/customgraphics.cpp @@ -53,6 +53,16 @@ void HmiComponent::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter->setPen(QPen(Qt::darkRed, 2, Qt::DashLine)); painter->drawRect(boundingRect()); } + + // 如果被选中,绘制缩放控制点 + if (isSelected()) { + QRectF rect = boundingRect(); + + // 绘制右下角缩放控制点 + painter->setBrush(Qt::white); + painter->setPen(QPen(Qt::black, 1)); + painter->drawRect(rect.right() - 8, rect.bottom() - 8, 8, 8); + } } void HmiComponent::setAddress(int address) @@ -68,9 +78,31 @@ int HmiComponent::address() const return m_address; } +void HmiComponent::setSize(double width, double height) +{ + prepareGeometryChange(); + m_width = width; + m_height = height; + update(); +} + void HmiComponent::mousePressEvent(QGraphicsSceneMouseEvent *event) { - // 右键不触发选中信号,留给 contextMenuEvent 处理 + // 检查是否点击了缩放控制点 + if (event->button() == Qt::LeftButton && isSelected()) { + QRectF rect = boundingRect(); + QRectF handleRect(rect.right() - 8, rect.bottom() - 8, 8, 8); + + if (handleRect.contains(event->pos())) { + m_resizing = true; + m_resizeStartPos = event->scenePos(); + m_resizeStartSize = QSizeF(rect.width(), rect.height()); + event->accept(); + return; + } + } + + // 原有的选中处理 if (event->button() == Qt::LeftButton) { emit selected(this); } @@ -229,6 +261,24 @@ void HmiComponent::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) void HmiComponent::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + if (m_resizing) { + // 计算尺寸变化 + QPointF delta = event->scenePos() - m_resizeStartPos; + double newWidth = qMax(20.0, m_resizeStartSize.width() + delta.x()); + double newHeight = qMax(20.0, m_resizeStartSize.height() + delta.y()); + + // 更新组件大小 + prepareGeometryChange(); + + // 子类需要实现setSize函数 + setSize(newWidth, newHeight); + + // 更新缩放控制点位置 + update(); + event->accept(); + return; + } + if (!(flags() & QGraphicsItem::ItemIsMovable)) { // 如果项不可移动,直接调用基类处理 QGraphicsObject::mouseMoveEvent(event); @@ -263,8 +313,8 @@ void HmiComponent::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QRectF newBounds = bounds.translated(newPos); // 限制组件边界必须完全在视图可见区域内 - qreal limitedX = newPos.x(); - qreal limitedY = newPos.y(); + double limitedX = newPos.x(); + double limitedY = newPos.y(); if (newBounds.left() < visibleSceneRect.left()) limitedX += visibleSceneRect.left() - newBounds.left(); @@ -279,6 +329,30 @@ void HmiComponent::mouseMoveEvent(QGraphicsSceneMouseEvent *event) event->accept(); } +void HmiComponent::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + if (m_resizing && event->button() == Qt::LeftButton) { + m_resizing = false; + event->accept(); + return; + } + QGraphicsObject::mouseReleaseEvent(event); +} + +void HmiComponent::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +{ + QRectF rect = boundingRect(); + QRectF handleRect(rect.right() - 8, rect.bottom() - 8, 8, 8); + + if (isSelected() && handleRect.contains(event->pos())) { + setCursor(Qt::SizeFDiagCursor); + m_resizeHandle = BottomRight; + } else { + setCursor(Qt::ArrowCursor); + m_resizeHandle = None; + } + QGraphicsObject::hoverMoveEvent(event); +} void HmiComponent::setOnColor(const QColor& color) { m_onColor = color; @@ -300,6 +374,9 @@ QColor HmiComponent::offColor() const { HmiButton::HmiButton(QGraphicsItem *parent) : HmiComponent(parent), m_isOn(false) { + // 按钮保持矩形形状 + m_width = 65.0; + m_height = 30.0; m_color = Qt::gray; m_offColor = m_color; // OFF状态颜色设为默认颜色 m_onColor = Qt::green; // ON状态颜色为绿色 @@ -307,6 +384,11 @@ HmiButton::HmiButton(QGraphicsItem *parent) : HmiComponent(parent), m_isOn(false setColor(m_offColor); // 当前显示OFF颜色 } +void HmiButton::setSize(double width, double height) +{ + HmiComponent::setSize(width, height); +} + bool HmiButton::isOn() const { return m_isOn; @@ -326,7 +408,7 @@ void HmiButton::setOn(bool on) QRectF HmiButton::boundingRect() const { - return QRectF(0, 0, 65, 30); + return QRectF(0, 0, m_width, m_height); } void HmiButton::paintShape(QPainter *painter) @@ -338,6 +420,9 @@ void HmiButton::paintShape(QPainter *painter) HmiIndicator::HmiIndicator(QGraphicsItem *parent) : HmiComponent(parent) { + // 指示灯初始为圆形 + m_width = 30.0; + m_height = 30.0; m_color = Qt::red; m_offColor = m_color; // OFF状态颜色设为默认颜色 m_onColor = Qt::green; // ON状态颜色为绿色 @@ -345,11 +430,17 @@ HmiIndicator::HmiIndicator(QGraphicsItem *parent) : HmiComponent(parent) setColor(m_offColor); // 当前显示OFF颜色 } +void HmiIndicator::setSize(double width, double height) +{ + HmiComponent::setSize(width, height); +} + QRectF HmiIndicator::boundingRect() const { - return QRectF(0, 0, 30, 30); + return QRectF(0, 0, m_width, m_height); } + void HmiIndicator::paintShape(QPainter *painter) { painter->setPen(Qt::NoPen); diff --git a/customgraphics.h b/customgraphics.h index 93d1fb8..e5fd22f 100644 --- a/customgraphics.h +++ b/customgraphics.h @@ -7,8 +7,10 @@ class QPainter; class QGraphicsSceneMouseEvent; class QGraphicsSceneContextMenuEvent; +class QGraphicsSceneHoverEvent; -enum class ComponentType { +enum class ComponentType +{ Button, Indicator }; @@ -51,11 +53,16 @@ public: void setAddress(int address); int address() const; + void setSize(double width, double height); + QSizeF size() const { return QSizeF(m_width, m_height); } + protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; virtual void paintShape(QPainter* painter) = 0; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override; + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; protected: QColor m_color; // 当前显示颜色(编辑器中为 OFF) @@ -63,6 +70,16 @@ protected: QColor m_offColor; QString m_componentName; int m_address = 0; + + // 新增尺寸成员 + double m_width = 65.0; + double m_height = 30.0; + + enum ResizeHandle { None, BottomRight }; // 缩放控制点位置 + ResizeHandle m_resizeHandle = None; + bool m_resizing = false; + QPointF m_resizeStartPos; + QSizeF m_resizeStartSize; }; @@ -73,6 +90,7 @@ class HmiButton : public HmiComponent public: HmiButton(QGraphicsItem *parent = nullptr); QRectF boundingRect() const override; + void setSize(double width, double height); // 新增状态标志,true = ON,false = OFF bool isOn() const; @@ -91,6 +109,7 @@ class HmiIndicator : public HmiComponent public: HmiIndicator(QGraphicsItem *parent = nullptr); QRectF boundingRect() const override; + void setSize(double width, double height); protected: void paintShape(QPainter *painter) override; diff --git a/hmimodule.cpp b/hmimodule.cpp index 9ebd5b2..b74e501 100644 --- a/hmimodule.cpp +++ b/hmimodule.cpp @@ -113,6 +113,10 @@ bool HMIModule::saveToFile(const QString& filePath) compObj["address"] = component->address(); // 添加按钮状态 compObj["isOn"] = false; // 默认false + + // 保存尺寸 + compObj["width"] = component->boundingRect().width(); + compObj["height"] = component->boundingRect().height(); if (auto btn = dynamic_cast(component)) { compObj["isOn"] = btn->isOn(); } @@ -255,7 +259,13 @@ bool HMIModule::openFromFile(const QString& filePath) continue; } + // 加载尺寸 + double width = compObj["width"].toDouble(65); // 默认值 + double height = compObj["height"].toDouble(30); // 默认值 + if (newItem) { + // 设置尺寸 + newItem->setSize(width, height); newItem->setPos(QPointF(x, y)); QColor color(colorName); if (color.isValid()) { @@ -452,11 +462,14 @@ void HMIModule::onCopyRequested() } m_copiedColor = itemToCopy->color(); - // 新增复制以下属性 + // 复制以下属性 m_copiedOnColor = itemToCopy->onColor(); m_copiedOffColor = itemToCopy->offColor(); m_copiedComponentName = itemToCopy->componentName(); m_copiedAddress = itemToCopy->address(); + // 复制尺寸 + m_copiedWidth = itemToCopy->size().width(); + m_copiedHeight = itemToCopy->size().height(); m_hasCopiedItem = true; @@ -488,6 +501,8 @@ void HMIModule::onPasteRequested(const QPointF& scenePos) newItem->setOffColor(m_copiedOffColor); newItem->setComponentName(m_copiedComponentName); newItem->setAddress(m_copiedAddress); + // 设置尺寸 + newItem->setSize(m_copiedWidth, m_copiedHeight); newItem->setPos(scenePos); currentScene->addItem(newItem); // 使用当前页面的 scene setupNewComponent(newItem); diff --git a/hmimodule.h b/hmimodule.h index d6fa741..e1ccc99 100644 --- a/hmimodule.h +++ b/hmimodule.h @@ -57,6 +57,9 @@ private: QColor m_copiedOffColor; QString m_copiedComponentName; int m_copiedAddress = 0; + // 新增复制尺寸变量 + double m_copiedWidth = 0.0; + double m_copiedHeight = 0.0; bool m_hasCopiedItem = false; // 指示当前是否已经有组件被复制 int m_pageCount = 1; // 初始化页面计数器 diff --git a/mainwindow.cpp b/mainwindow.cpp index 6f5e0f0..f0d5cf7 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -19,26 +19,10 @@ MainWindow::MainWindow(QWidget *parent) // 连接 HMIModule 的信号到 MainWindow 的槽 connect(hmi_, &HMIModule::logMessageGenerated, this, &MainWindow::appendLog); - // 新建菜单 - connect(ui_->action, &QAction::triggered, this, &MainWindow::onNewFile); - - connect(ui_->action_3, &QAction::triggered, this, [this]() { - QString fileName = QFileDialog::getSaveFileName(this, "保存HMI文件", "", "JSON文件 (*.hmi)"); - if (!fileName.isEmpty()) { - if (!hmi_->saveToFile(fileName)) { - QMessageBox::warning(this, "保存失败", "文件保存失败!"); - } - } - }); - - connect(ui_->action_2, &QAction::triggered, this, [this]() { - QString fileName = QFileDialog::getOpenFileName(this, "打开HMI文件", "", "JSON文件 (*.hmi)"); - if (!fileName.isEmpty()) { - if (!hmi_->openFromFile(fileName)) { - QMessageBox::warning(this, "打开失败", "文件打开失败或格式不正确!"); - } - } - }); + // 新建/打开/保存文件 + connect(ui_->actionNew, &QAction::triggered, this, &MainWindow::onNewFile); + connect(ui_->actionOpen, &QAction::triggered, this, &MainWindow::onOpenFile); + connect(ui_->actionSave, &QAction::triggered, this, &MainWindow::onSaveFile); } MainWindow::~MainWindow() @@ -64,31 +48,64 @@ void MainWindow::appendLog(const QString& message) void MainWindow::onNewFile() { if (!hmi_) + { return; + } - if (hmi_->isModified()) { + if (hmi_->isModified()) + { auto ret = QMessageBox::warning(this, "提示", "当前文件有未保存的更改,是否保存?", - QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, - QMessageBox::Save); + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); - if (ret == QMessageBox::Save) { - QString fileName = QFileDialog::getSaveFileName(this, "保存HMI设计", "", "JSON文件 (*.json)"); - if (!fileName.isEmpty()) { - if (!hmi_->saveToFile(fileName)) { + if (ret == QMessageBox::Save) + { + QString fileName = QFileDialog::getSaveFileName(this, "保存HMI文件", "", "HMI文件 (*.json)"); + if (!fileName.isEmpty()) + { + if (!hmi_->saveToFile(fileName)) + { QMessageBox::warning(this, "保存失败", "文件保存失败!"); return; // 不新建,保存失败 } - } else { + } + else + { return; // 取消保存,取消新建 } - } else if (ret == QMessageBox::Cancel) { + } + else if (ret == QMessageBox::Cancel) + { return; // 取消新建 } // 如果是Discard,直接继续新建,丢弃当前修改 } - // 清空编辑区,新建页面 hmi_->resetPages(); } +void MainWindow::onOpenFile() +{ + QString fileName = QFileDialog::getOpenFileName(this, "打开HMI文件", "", "HMI文件 (*.hmi)"); + if (!fileName.isEmpty()) + { + if (!hmi_->openFromFile(fileName)) + { + QMessageBox::warning(this, "打开失败", "文件打开失败或格式不正确!"); + } + } +} + +void MainWindow::onSaveFile() +{ + + QString fileName = QFileDialog::getSaveFileName(this, "保存HMI文件", "", "HMI文件 (*.hmi)"); + if (!fileName.isEmpty()) + { + if (!hmi_->saveToFile(fileName)) + { + QMessageBox::warning(this, "保存失败", "文件保存失败!"); + } + } +} + diff --git a/mainwindow.h b/mainwindow.h index 32cab95..a298546 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -5,7 +5,8 @@ #include "hmimodule.h" QT_BEGIN_NAMESPACE -namespace Ui { +namespace Ui +{ class MainWindow; } QT_END_NAMESPACE @@ -23,7 +24,9 @@ private: private slots: void appendLog(const QString& message); - void onNewFile(); // 新增槽函数,处理“新建”菜单 + void onNewFile(); + void onOpenFile(); + void onSaveFile(); private: Ui::MainWindow *ui_;