@@ -4,6 +4,14 @@ | |||
#include <QMenu> | |||
#include <QGraphicsScene> | |||
#include <QColorDialog> | |||
#include <QInputDialog> | |||
#include <QDialog> | |||
#include <QLabel> | |||
#include <QSpinBox> | |||
#include <QHBoxLayout> | |||
#include <QVBoxLayout> | |||
#include <QPushButton> | |||
#include <QGraphicsView> | |||
// HmiComponent 基类实现 | |||
HmiComponent::HmiComponent(QGraphicsItem *parent) : QGraphicsObject(parent) | |||
@@ -47,6 +55,19 @@ void HmiComponent::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti | |||
} | |||
} | |||
void HmiComponent::setAddress(int address) | |||
{ | |||
if (m_address != address) { | |||
m_address = address; | |||
update(); | |||
} | |||
} | |||
int HmiComponent::address() const | |||
{ | |||
return m_address; | |||
} | |||
void HmiComponent::mousePressEvent(QGraphicsSceneMouseEvent *event) | |||
{ | |||
// 右键不触发选中信号,留给 contextMenuEvent 处理 | |||
@@ -58,38 +79,212 @@ void HmiComponent::mousePressEvent(QGraphicsSceneMouseEvent *event) | |||
void HmiComponent::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) | |||
{ | |||
// 右键点击时,先清空场景中的其他选中项,然后选中当前项 | |||
scene()->clearSelection(); | |||
setSelected(true); | |||
emit selected(this); // 同样可以发出选中信号,以便更新属性面板等 | |||
emit selected(this); | |||
QMenu menu; | |||
QAction *propertyAction = menu.addAction("属性"); | |||
QAction *copyAction = menu.addAction("复制"); | |||
QAction *deleteAction = menu.addAction("删除"); | |||
QAction *appearanceAction = menu.addAction("改变外观"); | |||
// 使用 connect 将菜单动作的触发连接到信号的发射,复制和删除 | |||
connect(propertyAction, &QAction::triggered, this, [this]() { | |||
// 弹出属性对话框 | |||
QDialog dialog; | |||
dialog.setWindowTitle("属性"); | |||
QLabel* addressLabel = new QLabel("地址: "); | |||
QSpinBox* addressSpin = new QSpinBox(); | |||
addressSpin->setRange(0, 4000); | |||
addressSpin->setValue(m_address); // 使用当前组件地址初始化 | |||
// ON状态颜色设置 | |||
QLabel* onColorLabel = new QLabel("ON状态外观: "); | |||
// 颜色显示,用QLabel设置背景色简单示范 | |||
QLabel* onColorDisplay = new QLabel; | |||
onColorDisplay->setFixedSize(40, 20); | |||
onColorDisplay->setAutoFillBackground(true); | |||
QPalette onPal = onColorDisplay->palette(); | |||
onPal.setColor(QPalette::Window, m_onColor); | |||
onColorDisplay->setPalette(onPal); | |||
onColorDisplay->setFrameShape(QFrame::Box); | |||
QPushButton* onColorBtn = new QPushButton("选择颜色"); | |||
// OFF状态颜色设置 | |||
QLabel* offColorLabel = new QLabel("OFF状态外观: "); | |||
QLabel* offColorDisplay = new QLabel; | |||
offColorDisplay->setFixedSize(40, 20); | |||
offColorDisplay->setAutoFillBackground(true); | |||
QPalette offPal = offColorDisplay->palette(); | |||
offPal.setColor(QPalette::Window, m_offColor); | |||
offColorDisplay->setPalette(offPal); | |||
offColorDisplay->setFrameShape(QFrame::Box); | |||
QPushButton* offColorBtn = new QPushButton("选择颜色"); | |||
QObject::connect(offColorBtn, &QPushButton::clicked, [&]() { | |||
QColor color = QColorDialog::getColor(m_offColor, nullptr, "选择 OFF 状态颜色"); | |||
if (color.isValid()) { | |||
m_offColor = color; | |||
QPalette pal = offColorDisplay->palette(); | |||
pal.setColor(QPalette::Window, color); | |||
offColorDisplay->setPalette(pal); | |||
offColorDisplay->update(); | |||
setColor(color); // 默认显示OFF状态颜色 | |||
} | |||
}); | |||
// 地址布局 | |||
QHBoxLayout* addressLayout = new QHBoxLayout(); | |||
addressLayout->addWidget(addressLabel); | |||
addressLayout->addWidget(addressSpin); | |||
// ON颜色布局 | |||
QHBoxLayout* onColorLayout = new QHBoxLayout(); | |||
onColorLayout->addWidget(onColorLabel); | |||
onColorLayout->addWidget(onColorDisplay); | |||
onColorLayout->addWidget(onColorBtn); | |||
// OFF颜色布局 | |||
QHBoxLayout* offColorLayout = new QHBoxLayout(); | |||
offColorLayout->addWidget(offColorLabel); | |||
offColorLayout->addWidget(offColorDisplay); | |||
offColorLayout->addWidget(offColorBtn); | |||
// 确定/取消按钮 | |||
QPushButton* okBtn = new QPushButton("确定"); | |||
QPushButton* cancelBtn = new QPushButton("取消"); | |||
QHBoxLayout* btnLayout = new QHBoxLayout(); | |||
btnLayout->addStretch(); | |||
btnLayout->addWidget(okBtn); | |||
btnLayout->addWidget(cancelBtn); | |||
// 颜色选择按钮点击槽 | |||
QObject::connect(onColorBtn, &QPushButton::clicked, [&]() { | |||
QColor color = QColorDialog::getColor(m_onColor, nullptr, "选择 ON 状态颜色"); | |||
if (color.isValid()) { | |||
m_onColor = color; | |||
QPalette pal = onColorDisplay->palette(); | |||
pal.setColor(QPalette::Window, color); | |||
onColorDisplay->setPalette(pal); | |||
onColorDisplay->update(); | |||
} | |||
}); | |||
QVBoxLayout* mainLayout = new QVBoxLayout(); | |||
mainLayout->addLayout(addressLayout); | |||
mainLayout->addLayout(onColorLayout); | |||
mainLayout->addLayout(offColorLayout); | |||
mainLayout->addLayout(btnLayout); | |||
dialog.setLayout(mainLayout); | |||
// 关闭逻辑 | |||
QObject::connect(okBtn, &QPushButton::clicked, [&]() { | |||
// 保存地址 | |||
int newAddress = addressSpin->value(); | |||
setAddress(newAddress); | |||
// 已经在onColorBtn / offColorBtn中修改了m_onColor / m_offColor,需要触发界面更新 | |||
update(); | |||
dialog.accept(); | |||
}); | |||
QObject::connect(cancelBtn, &QPushButton::clicked, &dialog, &QDialog::reject); | |||
dialog.exec(); | |||
}); | |||
connect(copyAction, &QAction::triggered, this, [this]() { | |||
emit copyRequested(this); | |||
}); | |||
connect(deleteAction, &QAction::triggered, this, [this]() { | |||
emit deleteRequested(this); | |||
}); | |||
connect(appearanceAction, &QAction::triggered, this, &HmiComponent::changeAppearance); | |||
// 在鼠标光标位置显示菜单 | |||
menu.exec(event->screenPos()); | |||
} | |||
void HmiComponent::changeAppearance() | |||
void HmiComponent::mouseMoveEvent(QGraphicsSceneMouseEvent *event) | |||
{ | |||
emit appearanceChangedRequested(this); | |||
if (!(flags() & QGraphicsItem::ItemIsMovable)) { | |||
// 如果项不可移动,直接调用基类处理 | |||
QGraphicsObject::mouseMoveEvent(event); | |||
return; | |||
} | |||
// 计算拖动后的位置 | |||
QPointF delta = event->scenePos() - event->lastScenePos(); | |||
QPointF newPos = pos() + delta; | |||
// 获取视图(假设只有1个视图) | |||
QList<QGraphicsView*> views = scene()->views(); | |||
if (views.isEmpty()) { | |||
// 没有视图则默认处理 | |||
QGraphicsObject::mouseMoveEvent(event); | |||
return; | |||
} | |||
QGraphicsView* view = views.first(); | |||
// 获取视口矩形(像素坐标) | |||
QRect viewportRect = view->viewport()->rect(); | |||
// 将视口矩形映射到场景坐标 | |||
QPointF topLeftScene = view->mapToScene(viewportRect.topLeft()); | |||
QPointF bottomRightScene = view->mapToScene(viewportRect.bottomRight()); | |||
QRectF visibleSceneRect(topLeftScene, bottomRightScene); | |||
// 组件的边界矩形(局部坐标) | |||
QRectF bounds = boundingRect(); | |||
// 计算移动后组件边界矩形(在场景坐标) | |||
QRectF newBounds = bounds.translated(newPos); | |||
// 限制组件边界必须完全在视图可见区域内 | |||
qreal limitedX = newPos.x(); | |||
qreal limitedY = newPos.y(); | |||
if (newBounds.left() < visibleSceneRect.left()) | |||
limitedX += visibleSceneRect.left() - newBounds.left(); | |||
if (newBounds.top() < visibleSceneRect.top()) | |||
limitedY += visibleSceneRect.top() - newBounds.top(); | |||
if (newBounds.right() > visibleSceneRect.right()) | |||
limitedX -= newBounds.right() - visibleSceneRect.right(); | |||
if (newBounds.bottom() > visibleSceneRect.bottom()) | |||
limitedY -= newBounds.bottom() - visibleSceneRect.bottom(); | |||
setPos(QPointF(limitedX, limitedY)); | |||
event->accept(); | |||
} | |||
void HmiComponent::setOnColor(const QColor& color) { | |||
m_onColor = color; | |||
} | |||
void HmiComponent::setOffColor(const QColor& color) { | |||
m_offColor = color; | |||
setColor(color); // 默认展示 OFF 状态颜色 | |||
} | |||
QColor HmiComponent::onColor() const { | |||
return m_onColor; | |||
} | |||
QColor HmiComponent::offColor() const { | |||
return m_offColor; | |||
} | |||
HmiButton::HmiButton(QGraphicsItem *parent) : HmiComponent(parent) | |||
{ | |||
m_color = Qt::gray; | |||
m_offColor = m_color; // OFF状态颜色设为默认颜色 | |||
m_onColor = Qt::green; // ON状态颜色为绿色 | |||
m_componentName = "Button"; | |||
setColor(m_offColor); // 当前显示OFF颜色 | |||
} | |||
QRectF HmiButton::boundingRect() const | |||
@@ -106,8 +301,11 @@ void HmiButton::paintShape(QPainter *painter) | |||
HmiIndicator::HmiIndicator(QGraphicsItem *parent) : HmiComponent(parent) | |||
{ | |||
m_color = Qt::green; | |||
m_color = Qt::red; | |||
m_offColor = m_color; // OFF状态颜色设为默认颜色 | |||
m_onColor = Qt::green; // ON状态颜色为绿色 | |||
m_componentName = "Indicator"; | |||
setColor(m_offColor); // 当前显示OFF颜色 | |||
} | |||
QRectF HmiIndicator::boundingRect() const | |||
@@ -2,6 +2,7 @@ | |||
#define CUSTOMGRAPHICS_H | |||
#include <QGraphicsObject> | |||
#include <QColor> | |||
// 只需要前向声明,因为头文件中只用到了指针 | |||
class QPainter; | |||
class QGraphicsSceneMouseEvent; | |||
@@ -16,41 +17,56 @@ enum class ComponentType { | |||
class HmiComponent : public QGraphicsObject | |||
{ | |||
Q_OBJECT | |||
Q_PROPERTY(QColor color READ color WRITE setColor) | |||
Q_PROPERTY(QColor color READ color WRITE setColor) // 当前颜色(默认使用 OFF 状态) | |||
Q_PROPERTY(QString componentName READ componentName WRITE setComponentName) | |||
// 新增address属性 | |||
Q_PROPERTY(int address READ address WRITE setAddress) | |||
signals: | |||
void selected(HmiComponent* item); | |||
// 为复制和删除请求添加信号 | |||
void copyRequested(HmiComponent* item); | |||
void deleteRequested(HmiComponent* item); | |||
void appearanceChangedRequested(HmiComponent* item); | |||
// 添加信号用于改变状态颜色 | |||
void changeOnColorRequested(HmiComponent* item); | |||
void changeOffColorRequested(HmiComponent* item); | |||
public: | |||
explicit HmiComponent(QGraphicsItem *parent = nullptr); | |||
void setColor(const QColor& color); | |||
void setColor(const QColor& color); // 当前显示颜色 | |||
QColor color() const; | |||
void setComponentName(const QString& name); | |||
QString componentName() const; | |||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; | |||
// 设置 ON / OFF 状态颜色 | |||
void setOnColor(const QColor& color); | |||
void setOffColor(const QColor& color); | |||
QColor onColor() const; | |||
QColor offColor() const; | |||
public slots: | |||
void changeAppearance(); | |||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; | |||
// 地址相关 | |||
void setAddress(int address); | |||
int address() const; | |||
protected: | |||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override; | |||
// 重写上下文菜单事件 | |||
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; | |||
virtual void paintShape(QPainter* painter) = 0; | |||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; | |||
protected: | |||
QColor m_color; | |||
QColor m_color; // 当前显示颜色(编辑器中为 OFF) | |||
QColor m_onColor = Qt::green; | |||
QColor m_offColor; | |||
QString m_componentName; | |||
int m_address = 0; | |||
}; | |||
// 按钮类 | |||
class HmiButton : public HmiComponent | |||
{ | |||
@@ -7,6 +7,11 @@ | |||
#include <QVBoxLayout> | |||
#include <algorithm> | |||
#include <QColorDialog> | |||
#include <QFile> | |||
#include <QJsonDocument> | |||
#include <QJsonArray> | |||
#include <QJsonObject> | |||
#include <QDebug> | |||
HMIModule::HMIModule(Ui::MainWindow* ui, QObject *parent) | |||
: QObject{parent}, ui_(ui), m_scene(nullptr) | |||
@@ -56,6 +61,236 @@ void HMIModule::init() { | |||
connect(this, &HMIModule::pageRemoved, this, &HMIModule::onPageRemoved); | |||
} | |||
bool HMIModule::saveToFile(const QString& filePath) | |||
{ | |||
QTabWidget* tabWidget = ui_->tabWidget_2; | |||
QJsonArray pagesArray; | |||
for (int i = 0; i < tabWidget->count(); ++i) { | |||
QWidget* page = tabWidget->widget(i); | |||
QString pageName = tabWidget->tabText(i); | |||
QGraphicsView* graphicsView = page->findChild<QGraphicsView*>(); | |||
if (!graphicsView) continue; | |||
QGraphicsScene* scene = graphicsView->scene(); | |||
if (!scene) continue; | |||
QJsonObject pageObject; | |||
pageObject["pageName"] = pageName; | |||
QJsonArray componentsArray; | |||
for (QGraphicsItem* item : scene->items()) { | |||
HmiComponent* component = dynamic_cast<HmiComponent*>(item); | |||
if (!component) | |||
continue; | |||
QJsonObject compObj; | |||
// 组件类型 | |||
if (dynamic_cast<HmiButton*>(component)) { | |||
compObj["type"] = "Button"; | |||
} else if (dynamic_cast<HmiIndicator*>(component)) { | |||
compObj["type"] = "Indicator"; | |||
} else { | |||
continue; // 忽略未知类型 | |||
} | |||
// 位置 | |||
QPointF pos = component->pos(); | |||
compObj["x"] = pos.x(); | |||
compObj["y"] = pos.y(); | |||
// 颜色 (保存在HEX) | |||
compObj["color"] = component->color().name(); | |||
// On / Off颜色 | |||
compObj["onColor"] = component->onColor().name(); | |||
compObj["offColor"] = component->offColor().name(); | |||
// 组件名称 | |||
compObj["componentName"] = component->componentName(); | |||
// 新增地址属性 | |||
compObj["address"] = component->address(); | |||
componentsArray.append(compObj); | |||
} | |||
pageObject["components"] = componentsArray; | |||
pagesArray.append(pageObject); | |||
} | |||
QJsonObject rootObject; | |||
rootObject["pages"] = pagesArray; | |||
QJsonDocument doc(rootObject); | |||
QFile file(filePath); | |||
if (!file.open(QIODevice::WriteOnly)) { | |||
emit logMessageGenerated(QString("无法打开文件进行保存: %1").arg(filePath)); | |||
return false; | |||
} | |||
file.write(doc.toJson(QJsonDocument::Indented)); | |||
file.close(); | |||
emit logMessageGenerated(QString("[%1] 保存成功: %2") | |||
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) | |||
.arg(filePath)); | |||
return true; | |||
} | |||
// 清空所有页面,重建页面并加载组件 | |||
bool HMIModule::openFromFile(const QString& filePath) | |||
{ | |||
QFile file(filePath); | |||
if (!file.open(QIODevice::ReadOnly)) { | |||
emit logMessageGenerated(QString("无法打开文件进行加载: %1").arg(filePath)); | |||
return false; | |||
} | |||
QByteArray data = file.readAll(); | |||
file.close(); | |||
QJsonParseError parseError; | |||
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError); | |||
if (parseError.error != QJsonParseError::NoError) { | |||
emit logMessageGenerated(QString("JSON解析错误: %1").arg(parseError.errorString())); | |||
return false; | |||
} | |||
if (!doc.isObject()) { | |||
emit logMessageGenerated("JSON格式错误,不是对象"); | |||
return false; | |||
} | |||
QJsonObject rootObj = doc.object(); | |||
if (!rootObj.contains("pages") || !rootObj["pages"].isArray()) { | |||
emit logMessageGenerated("JSON缺少pages数组"); | |||
return false; | |||
} | |||
QJsonArray pagesArray = rootObj["pages"].toArray(); | |||
QTabWidget* tabWidget = ui_->tabWidget_2; | |||
// 清空所有现有页面 | |||
while (tabWidget->count() > 0) { | |||
QWidget* page = tabWidget->widget(0); | |||
tabWidget->removeTab(0); | |||
delete page; | |||
} | |||
m_availablePageNumbers.clear(); | |||
m_pageOrder.clear(); | |||
for (const QJsonValue& pageVal : pagesArray) { | |||
if (!pageVal.isObject()) | |||
continue; | |||
QJsonObject pageObj = pageVal.toObject(); | |||
QString pageName = pageObj["pageName"].toString("Unnamed"); | |||
int pageNumber = 0; | |||
if (pageName.startsWith("Page ")) { | |||
pageNumber = pageName.mid(5).toInt(); | |||
} | |||
// 新建页面 | |||
QWidget* newPage = new QWidget(tabWidget); | |||
newPage->setObjectName(pageName); | |||
QGraphicsView* newGraphicsView = new QGraphicsView(newPage); | |||
CustomGraphicsScene* newScene = new CustomGraphicsScene(newGraphicsView, this); | |||
// 设置大小,与默认页面相同 | |||
QSize defaultSize(691, 381); | |||
newGraphicsView->resize(defaultSize); | |||
newScene->setSceneRect(0, 0, 800, 600); | |||
newGraphicsView->setScene(newScene); | |||
QVBoxLayout* layout = new QVBoxLayout(newPage); | |||
layout->addWidget(newGraphicsView); | |||
newPage->setLayout(layout); | |||
int tabIndex = tabWidget->addTab(newPage, pageName); | |||
// 连接信号 | |||
connect(newScene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated); | |||
connect(newScene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested); | |||
connect(newScene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested); | |||
connect(newScene, &CustomGraphicsScene::deleteRequestFromScene, this, &HMIModule::onDeleteRequested); | |||
m_pageOrder.append(pageNumber); | |||
QJsonArray compArray = pageObj["components"].toArray(); | |||
for (const QJsonValue& compVal : compArray) { | |||
if (!compVal.isObject()) | |||
continue; | |||
QJsonObject compObj = compVal.toObject(); | |||
QString typeStr = compObj["type"].toString(); | |||
double x = compObj["x"].toDouble(); | |||
double y = compObj["y"].toDouble(); | |||
QString colorName = compObj["color"].toString(); | |||
QString onColorName = compObj["onColor"].toString(); | |||
QString offColorName = compObj["offColor"].toString(); | |||
QString componentName = compObj["componentName"].toString(); | |||
int address = compObj["address"].toInt(0); | |||
HmiComponent* newItem = nullptr; | |||
if (typeStr == "Button") { | |||
newItem = new HmiButton(); | |||
} else if (typeStr == "Indicator") { | |||
newItem = new HmiIndicator(); | |||
} else { | |||
continue; | |||
} | |||
if (newItem) { | |||
newItem->setPos(QPointF(x, y)); | |||
QColor color(colorName); | |||
if (color.isValid()) { | |||
newItem->setColor(color); | |||
} | |||
QColor onColor(onColorName); | |||
if (onColor.isValid()) | |||
newItem->setOnColor(onColor); | |||
QColor offColor(offColorName); | |||
if (offColor.isValid()) | |||
newItem->setOffColor(offColor); | |||
QColor currentColor(colorName); | |||
if (currentColor.isValid()) { | |||
// 可以根据实际业务逻辑判断,是否恢复为onColor或offColor | |||
// 这里直接恢复当前颜色 | |||
newItem->setColor(currentColor); | |||
} else { | |||
// 如果当前颜色无效,则使用 offColor 作为默认颜色 | |||
newItem->setColor(newItem->offColor()); | |||
} | |||
newItem->setComponentName(componentName); | |||
// 设置地址 | |||
newItem->setAddress(address); | |||
newScene->addItem(newItem); | |||
setupNewComponent(newItem); | |||
} | |||
} | |||
} | |||
// 自动切换到第一页 | |||
if (tabWidget->count() > 0) { | |||
tabWidget->setCurrentIndex(0); | |||
} | |||
emit logMessageGenerated(QString("[%1] 打开文件成功: %2") | |||
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) | |||
.arg(filePath)); | |||
return true; | |||
} | |||
void HMIModule::setupNewComponent(HmiComponent* item) | |||
{ | |||
if (!item) return; | |||
@@ -63,7 +298,9 @@ void HMIModule::setupNewComponent(HmiComponent* item) | |||
connect(item, &HmiComponent::selected, this, &HMIModule::onComponentSelected); | |||
connect(item, &HmiComponent::copyRequested, this, &HMIModule::onCopyRequested); | |||
connect(item, &HmiComponent::deleteRequested, this, &HMIModule::onDeleteRequested); | |||
connect(item, &HmiComponent::appearanceChangedRequested, this, &HMIModule::onChangeAppearanceRequested); // 连接信号 | |||
connect(item, &HmiComponent::changeOnColorRequested, this, &HMIModule::onChangeOnColorRequested); | |||
connect(item, &HmiComponent::changeOffColorRequested, this, &HMIModule::onChangeOffColorRequested); | |||
QString currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); | |||
QString log = QString("[%1] 创建 %2 组件").arg(currentTime).arg(item->componentName()); | |||
@@ -177,13 +414,6 @@ void HMIModule::onDeleteRequested() | |||
} | |||
} | |||
void HMIModule::onChangeAppearanceRequested(HmiComponent* item) | |||
{ | |||
QColor color = QColorDialog::getColor(item->color(), nullptr, "选择颜色"); | |||
if (color.isValid()) { | |||
item->setColor(color); | |||
} | |||
} | |||
// 添加页面后的槽函数 | |||
void HMIModule::onPageAdded(int pageNumber, int index) | |||
@@ -203,6 +433,30 @@ void HMIModule::onPageRemoved(int pageNumber, int index) | |||
} | |||
} | |||
void HMIModule::onChangeOnColorRequested(HmiComponent* item) | |||
{ | |||
QColor color = QColorDialog::getColor(item->onColor(), nullptr, "选择 ON 状态颜色"); | |||
if (color.isValid()) { | |||
item->setOnColor(color); | |||
emit logMessageGenerated(QString("[%1] 设置 %2 的 ON 状态颜色为 %3") | |||
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) | |||
.arg(item->componentName()) | |||
.arg(color.name())); | |||
} | |||
} | |||
void HMIModule::onChangeOffColorRequested(HmiComponent* item) | |||
{ | |||
QColor color = QColorDialog::getColor(item->offColor(), nullptr, "选择 OFF 状态颜色"); | |||
if (color.isValid()) { | |||
item->setOffColor(color); // 同时更新当前显示颜色 | |||
emit logMessageGenerated(QString("[%1] 设置 %2 的 OFF 状态颜色为 %3") | |||
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) | |||
.arg(item->componentName()) | |||
.arg(color.name())); | |||
} | |||
} | |||
void HMIModule::onComponentSelected(HmiComponent* item) | |||
{ | |||
// 不需要任何操作,可以留空 | |||
@@ -266,7 +520,7 @@ void HMIModule::addPage() | |||
tabIndex = tabWidget->addTab(newPage, pageName); | |||
} | |||
// 连接信号和槽 ******************************************************************* | |||
// 连接信号和槽 | |||
connect(newScene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated); | |||
connect(newScene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested); | |||
connect(newScene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested); | |||
@@ -15,6 +15,8 @@ public: | |||
explicit HMIModule(Ui::MainWindow* ui, QObject *parent = nullptr); | |||
void setButtonIcon(QAbstractButton* button, const QString& iconPath); | |||
void init(); | |||
bool saveToFile(const QString& filePath); | |||
bool openFromFile(const QString& filePath); | |||
signals: | |||
void pageAdded(int pageNumber, int index); | |||
@@ -29,13 +31,14 @@ private slots: | |||
void onCopyRequested(); | |||
void onPasteRequested(const QPointF& scenePos); | |||
void onDeleteRequested(); | |||
void onChangeAppearanceRequested(HmiComponent* item); | |||
void addPage(); | |||
void deletePage(); | |||
void prePage(); | |||
void nextPage(); | |||
void onPageAdded(int pageNumber, int index); | |||
void onPageRemoved(int pageNumber, int index); | |||
void onChangeOnColorRequested(HmiComponent* item); | |||
void onChangeOffColorRequested(HmiComponent* item); | |||
private: | |||
void setupNewComponent(HmiComponent* item); | |||
@@ -3,7 +3,8 @@ | |||
#include <QToolButton> | |||
#include <QVBoxLayout> | |||
#include <QButtonGroup> | |||
#include <QFileDialog> | |||
#include <QMessageBox> | |||
MainWindow::MainWindow(QWidget *parent) | |||
: QMainWindow(parent) | |||
@@ -16,6 +17,24 @@ MainWindow::MainWindow(QWidget *parent) | |||
initMainWindow(); | |||
// 连接 HMIModule 的信号到 MainWindow 的槽 | |||
connect(hmi_, &HMIModule::logMessageGenerated, this, &MainWindow::appendLog); | |||
connect(ui_->action_3, &QAction::triggered, this, [this]() { | |||
QString fileName = QFileDialog::getSaveFileName(this, "保存HMI设计", "", "JSON文件 (*.json)"); | |||
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文件 (*.json)"); | |||
if (!fileName.isEmpty()) { | |||
if (!hmi_->openFromFile(fileName)) { | |||
QMessageBox::warning(this, "打开失败", "文件打开失败或格式不正确!"); | |||
} | |||
} | |||
}); | |||
} | |||
MainWindow::~MainWindow() | |||