Selaa lähdekoodia

实现编辑区中能够缩放按钮和指示灯的功能

master
付春阳 1 päivä sitten
vanhempi
commit
2bfe3ac7f9
6 muutettua tiedostoa jossa 187 lisäystä ja 39 poistoa
  1. +96
    -5
      customgraphics.cpp
  2. +20
    -1
      customgraphics.h
  3. +16
    -1
      hmimodule.cpp
  4. +3
    -0
      hmimodule.h
  5. +47
    -30
      mainwindow.cpp
  6. +5
    -2
      mainwindow.h

+ 96
- 5
customgraphics.cpp Näytä tiedosto

@@ -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);


+ 20
- 1
customgraphics.h Näytä tiedosto

@@ -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;


+ 16
- 1
hmimodule.cpp Näytä tiedosto

@@ -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<HmiButton*>(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);


+ 3
- 0
hmimodule.h Näytä tiedosto

@@ -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; // 初始化页面计数器


+ 47
- 30
mainwindow.cpp Näytä tiedosto

@@ -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, "保存失败", "文件保存失败!");
}
}
}


+ 5
- 2
mainwindow.h Näytä tiedosto

@@ -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_;


Ladataan…
Peruuta
Tallenna