|
|
@@ -1,653 +0,0 @@ |
|
|
|
#include "document.h" |
|
|
|
#include "graphicsitems.h" |
|
|
|
#include <QGraphicsItem> |
|
|
|
#include <QGraphicsSceneHoverEvent> |
|
|
|
#include <QMouseEvent> |
|
|
|
#include <QMenu> |
|
|
|
#include <QAction> |
|
|
|
#include <QDataStream> |
|
|
|
#include <QColorDialog> |
|
|
|
#include <QDialog> |
|
|
|
#include <QFormLayout> |
|
|
|
#include <QLineEdit> |
|
|
|
#include <QPushButton> |
|
|
|
#include <QDialogButtonBox> |
|
|
|
#include <QMimeData> |
|
|
|
#include <QDragEnterEvent> |
|
|
|
#include <QDropEvent> |
|
|
|
#include <QDebug> |
|
|
|
#include<QFileInfo> |
|
|
|
HMIDocument::HMIDocument(QWidget *parent) |
|
|
|
: BaseDocument(HMI, parent), |
|
|
|
m_title("未命名HMI"), |
|
|
|
m_canDrawEllipse(false), |
|
|
|
m_canDrawRectangle(false), |
|
|
|
m_lastPastePos(0, 0) |
|
|
|
{ |
|
|
|
// 创建绘图场景 |
|
|
|
m_scene = new QGraphicsScene(this); |
|
|
|
m_scene->setSceneRect(0, 0, 800, 600); |
|
|
|
m_scene->setBackgroundBrush(QBrush(Qt::lightGray)); |
|
|
|
// 更粗的网格线示例 |
|
|
|
// QImage gridImage(40, 40, QImage::Format_ARGB32); |
|
|
|
// gridImage.fill(Qt::white); |
|
|
|
|
|
|
|
// QPainter painter(&gridImage); |
|
|
|
// painter.setPen(QPen(QColor(200, 200, 200), 1)); // 浅灰色 |
|
|
|
|
|
|
|
// // 绘制水平线 |
|
|
|
// painter.drawLine(0, 39, 39, 39); |
|
|
|
// // 绘制垂直线 |
|
|
|
// painter.drawLine(39, 0, 39, 39); |
|
|
|
|
|
|
|
// // 每隔4个小网格绘制一条稍粗的线 |
|
|
|
// painter.setPen(QPen(QColor(180, 180, 180), 1.5)); |
|
|
|
// painter.drawLine(0, 39, 39, 39); |
|
|
|
// painter.drawLine(39, 0, 39, 39); |
|
|
|
|
|
|
|
// m_scene->setBackgroundBrush(QBrush(gridImage)); |
|
|
|
|
|
|
|
// 创建视图 |
|
|
|
m_view = new QGraphicsView(m_scene, this); |
|
|
|
m_view->setRenderHint(QPainter::Antialiasing); |
|
|
|
m_view->setDragMode(QGraphicsView::RubberBandDrag); |
|
|
|
m_view->setAcceptDrops(true); |
|
|
|
m_view->viewport()->installEventFilter(this); |
|
|
|
|
|
|
|
// 布局(让视图占满文档区域) |
|
|
|
auto layout = new QVBoxLayout(this); |
|
|
|
layout->setContentsMargins(0, 0, 0, 0); |
|
|
|
layout->addWidget(m_view); |
|
|
|
setLayout(layout); |
|
|
|
} |
|
|
|
|
|
|
|
HMIDocument::~HMIDocument() |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
// 事件过滤器(处理绘图、拖拽等事件) |
|
|
|
bool HMIDocument::eventFilter(QObject *obj, QEvent *event) |
|
|
|
{ |
|
|
|
if (obj != m_view->viewport()) { |
|
|
|
return QWidget::eventFilter(obj, event); |
|
|
|
} |
|
|
|
// 鼠标按下事件(绘制图形) |
|
|
|
if (event->type() == QEvent::MouseButtonPress) |
|
|
|
{ |
|
|
|
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); |
|
|
|
setModified(true); |
|
|
|
if (mouseEvent->button() == Qt::RightButton) |
|
|
|
{ |
|
|
|
showContextMenu(mouseEvent->globalPos());// 右键菜单 |
|
|
|
return true; |
|
|
|
} |
|
|
|
if (mouseEvent->button() == Qt::LeftButton) |
|
|
|
{ |
|
|
|
QPointF scenePos = m_view->mapToScene(mouseEvent->pos()); |
|
|
|
QGraphicsItem *item = m_scene->itemAt(scenePos, m_view->transform()); |
|
|
|
|
|
|
|
// 如果点击空白区域且有绘制标志,创建图形 |
|
|
|
if (!item) { |
|
|
|
if (m_canDrawEllipse) |
|
|
|
{ |
|
|
|
createShape("ellipse", scenePos); |
|
|
|
resetDrawFlags(); |
|
|
|
} |
|
|
|
else if (m_canDrawRectangle) |
|
|
|
{ |
|
|
|
createShape("rectangle", scenePos); |
|
|
|
resetDrawFlags(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 拖拽事件(从工具栏拖拽绘制) |
|
|
|
if (event->type() == QEvent::DragEnter) |
|
|
|
{ |
|
|
|
QDragEnterEvent *dragEvent = static_cast<QDragEnterEvent*>(event); |
|
|
|
dragEvent->acceptProposedAction(); |
|
|
|
return true; |
|
|
|
} |
|
|
|
if (event->type() == QEvent::DragMove) |
|
|
|
{ |
|
|
|
static_cast<QDragMoveEvent*>(event)->acceptProposedAction(); |
|
|
|
return true; |
|
|
|
} |
|
|
|
if (event->type() == QEvent::Drop) |
|
|
|
{ |
|
|
|
QDropEvent *dropEvent = static_cast<QDropEvent*>(event); |
|
|
|
const QMimeData *mimeData = dropEvent->mimeData(); |
|
|
|
QPointF scenePos = m_view->mapToScene(dropEvent->pos()); |
|
|
|
|
|
|
|
// 使用QMimeData |
|
|
|
if (mimeData && mimeData->hasText()) |
|
|
|
{ |
|
|
|
createShape(mimeData->text(), scenePos); |
|
|
|
resetDrawFlags();//重置防止拖拽后再次点击生成 |
|
|
|
} |
|
|
|
dropEvent->acceptProposedAction(); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
return QWidget::eventFilter(obj, event); |
|
|
|
} |
|
|
|
|
|
|
|
void HMIDocument::createShape(const QString& type, const QPointF &pos) |
|
|
|
{ |
|
|
|
if (type == "指示灯" || type == "ellipse") { |
|
|
|
ResizableEllipse *ellipse = new ResizableEllipse(pos.x(), pos.y(), 50, 50); |
|
|
|
ellipse->setBrush(QBrush(Qt::red)); |
|
|
|
ellipse->setPen(QPen(Qt::black, 1)); |
|
|
|
m_scene->addItem(ellipse); |
|
|
|
ellipse->setSelected(true); |
|
|
|
} |
|
|
|
else if (type == "按钮" || type == "rectangle") { |
|
|
|
ResizableRectangle *rect = new ResizableRectangle(pos.x(), pos.y(), 100, 50); |
|
|
|
rect->setBrush(QBrush(Qt::yellow)); |
|
|
|
rect->setPen(QPen(Qt::black, 1)); |
|
|
|
m_scene->addItem(rect); |
|
|
|
rect->setSelected(true); |
|
|
|
} |
|
|
|
setModified(true); |
|
|
|
} |
|
|
|
// 重置绘制标志 |
|
|
|
void HMIDocument::resetDrawFlags() |
|
|
|
{ |
|
|
|
m_canDrawEllipse = false; |
|
|
|
m_canDrawRectangle = false; |
|
|
|
} |
|
|
|
|
|
|
|
// 右键菜单 |
|
|
|
void HMIDocument::showContextMenu(QPoint globalPos) |
|
|
|
{ |
|
|
|
QPoint viewportPos = m_view->mapFromGlobal(globalPos); |
|
|
|
QPointF scenePos = m_view->mapToScene(viewportPos); |
|
|
|
QGraphicsItem *clickedItem = m_scene->itemAt(scenePos, m_view->transform()); |
|
|
|
|
|
|
|
QMenu menu(this); |
|
|
|
|
|
|
|
if (!clickedItem) |
|
|
|
{ |
|
|
|
// 空白区域:仅显示粘贴 |
|
|
|
QAction *pasteAction = menu.addAction("粘贴"); |
|
|
|
pasteAction->setEnabled(!m_copiedItemsData.isEmpty()); |
|
|
|
connect(pasteAction, &QAction::triggered, this, &HMIDocument::pasteItems); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// 选中图形:显示完整菜单 |
|
|
|
QAction *propAction = menu.addAction("属性"); |
|
|
|
QAction *copyAction = menu.addAction("复制"); |
|
|
|
QAction *pasteAction = menu.addAction("粘贴"); |
|
|
|
QAction *deleteAction = menu.addAction("删除"); |
|
|
|
QAction *onAction = menu.addAction("置为ON"); |
|
|
|
QAction *offAction = menu.addAction("置为OFF"); |
|
|
|
|
|
|
|
pasteAction->setEnabled(!m_copiedItemsData.isEmpty()); |
|
|
|
|
|
|
|
connect(propAction, &QAction::triggered, this, &HMIDocument::showItemProperties); |
|
|
|
connect(copyAction, &QAction::triggered, this, &HMIDocument::copySelectedItems); |
|
|
|
connect(pasteAction, &QAction::triggered, this, &HMIDocument::pasteItems); |
|
|
|
connect(deleteAction, &QAction::triggered, this, &HMIDocument::deleteSelectedItems); |
|
|
|
|
|
|
|
// ON/OFF动作(针对指示灯和按钮) |
|
|
|
connect(onAction, &QAction::triggered, [=]() { |
|
|
|
if (auto ellipse = dynamic_cast<ResizableEllipse*>(clickedItem)) { |
|
|
|
ellipse->setBrush(ellipse->onColor()); |
|
|
|
} else if (auto rect = dynamic_cast<ResizableRectangle*>(clickedItem)) { |
|
|
|
rect->setBrush(rect->pressedColor()); |
|
|
|
} |
|
|
|
}); |
|
|
|
connect(offAction, &QAction::triggered, [=]() { |
|
|
|
if (auto ellipse = dynamic_cast<ResizableEllipse*>(clickedItem)) { |
|
|
|
ellipse->setBrush(ellipse->offColor()); |
|
|
|
} else if (auto rect = dynamic_cast<ResizableRectangle*>(clickedItem)) { |
|
|
|
rect->setBrush(rect->releasedColor()); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
menu.exec(globalPos + QPoint(10, 10)); |
|
|
|
} |
|
|
|
|
|
|
|
// 复制选中项 |
|
|
|
void HMIDocument::copySelectedItems() |
|
|
|
{ |
|
|
|
m_copiedItemsData.clear(); |
|
|
|
QList<QGraphicsItem*> selectedItems = m_scene->selectedItems(); |
|
|
|
if (selectedItems.isEmpty()) return; |
|
|
|
|
|
|
|
foreach (QGraphicsItem *item, selectedItems) |
|
|
|
{ |
|
|
|
m_copiedItemsData.append(serializeItem(item)); |
|
|
|
} |
|
|
|
m_lastPastePos = selectedItems.first()->pos(); |
|
|
|
setModified(true); |
|
|
|
} |
|
|
|
|
|
|
|
// 粘贴项 |
|
|
|
void HMIDocument::pasteItems() |
|
|
|
{ |
|
|
|
if (m_copiedItemsData.isEmpty()) return; |
|
|
|
|
|
|
|
QPointF offset(20, 20); |
|
|
|
m_lastPastePos += offset; |
|
|
|
m_scene->clearSelection(); |
|
|
|
|
|
|
|
foreach (const QByteArray &itemData, m_copiedItemsData) |
|
|
|
{ |
|
|
|
QGraphicsItem *newItem = deserializeItem(itemData); |
|
|
|
if (newItem) |
|
|
|
{ |
|
|
|
m_scene->addItem(newItem); |
|
|
|
newItem->setPos(m_lastPastePos); |
|
|
|
newItem->setSelected(true); |
|
|
|
} |
|
|
|
} |
|
|
|
setModified(true); |
|
|
|
} |
|
|
|
|
|
|
|
// 删除选中项 |
|
|
|
void HMIDocument::deleteSelectedItems() |
|
|
|
{ |
|
|
|
QList<QGraphicsItem*> selectedItems = m_scene->selectedItems(); |
|
|
|
foreach (QGraphicsItem *item, selectedItems) { |
|
|
|
m_scene->removeItem(item); |
|
|
|
delete item; |
|
|
|
} |
|
|
|
setModified(true); |
|
|
|
} |
|
|
|
|
|
|
|
// 显示属性对话框 |
|
|
|
void HMIDocument::showItemProperties() |
|
|
|
{ |
|
|
|
QList<QGraphicsItem*> selectedItems = m_scene->selectedItems(); |
|
|
|
if (selectedItems.isEmpty()) return; |
|
|
|
QGraphicsItem *item = selectedItems.first(); |
|
|
|
|
|
|
|
// 将QGraphicsItem转换为NamedItem |
|
|
|
NamedItem *namedItem = dynamic_cast<NamedItem*>(item); |
|
|
|
if (!namedItem) return; |
|
|
|
|
|
|
|
QDialog dialog(this); |
|
|
|
dialog.setWindowTitle("属性设置"); |
|
|
|
QFormLayout *form = new QFormLayout(&dialog); |
|
|
|
|
|
|
|
// 名称输入 - 使用NamedItem接口 |
|
|
|
QLineEdit *nameEdit = new QLineEdit(namedItem->name()); |
|
|
|
|
|
|
|
// 颜色选择(根据图形类型) |
|
|
|
QColor tempColor1, tempColor2; |
|
|
|
QPushButton *colorBtn1 = new QPushButton; |
|
|
|
QPushButton *colorBtn2 = new QPushButton; |
|
|
|
|
|
|
|
if (auto ellipse = dynamic_cast<ResizableEllipse*>(item)) { |
|
|
|
tempColor1 = ellipse->onColor(); |
|
|
|
tempColor2 = ellipse->offColor(); |
|
|
|
form->addRow("ON颜色:", colorBtn1); |
|
|
|
form->addRow("OFF颜色:", colorBtn2); |
|
|
|
} else if (auto rect = dynamic_cast<ResizableRectangle*>(item)) { |
|
|
|
tempColor1 = rect->pressedColor(); |
|
|
|
tempColor2 = rect->releasedColor(); |
|
|
|
form->addRow("按下颜色:", colorBtn1); |
|
|
|
form->addRow("释放颜色:", colorBtn2); |
|
|
|
} |
|
|
|
|
|
|
|
// 初始化颜色按钮 |
|
|
|
colorBtn1->setStyleSheet("background-color:" + tempColor1.name()); |
|
|
|
colorBtn2->setStyleSheet("background-color:" + tempColor2.name()); |
|
|
|
|
|
|
|
// 颜色选择对话框 |
|
|
|
connect(colorBtn1, &QPushButton::clicked, [&]() { |
|
|
|
QColor c = QColorDialog::getColor(tempColor1, &dialog); |
|
|
|
if (c.isValid()) { |
|
|
|
tempColor1 = c; |
|
|
|
colorBtn1->setStyleSheet("background-color:" + c.name()); |
|
|
|
} |
|
|
|
}); |
|
|
|
connect(colorBtn2, &QPushButton::clicked, [&]() { |
|
|
|
QColor c = QColorDialog::getColor(tempColor2, &dialog); |
|
|
|
if (c.isValid()) { |
|
|
|
tempColor2 = c; |
|
|
|
colorBtn2->setStyleSheet("background-color:" + c.name()); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 布局组装 |
|
|
|
form->addRow("对象:", nameEdit); |
|
|
|
QDialogButtonBox *btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); |
|
|
|
form->addRow(btnBox); |
|
|
|
connect(btnBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); |
|
|
|
connect(btnBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); |
|
|
|
|
|
|
|
// 应用属性 |
|
|
|
if (dialog.exec() == QDialog::Accepted) { |
|
|
|
setModified(true); |
|
|
|
// 使用NamedItem接口设置名称 |
|
|
|
namedItem->setName(nameEdit->text()); |
|
|
|
|
|
|
|
if (auto ellipse = dynamic_cast<ResizableEllipse*>(item)) { |
|
|
|
ellipse->setOnColor(tempColor1); |
|
|
|
ellipse->setOffColor(tempColor2); |
|
|
|
} else if (auto rect = dynamic_cast<ResizableRectangle*>(item)) { |
|
|
|
rect->setPressedColor(tempColor1); |
|
|
|
rect->setReleasedColor(tempColor2); |
|
|
|
} |
|
|
|
item->update(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 序列化图形项(用于复制粘贴) |
|
|
|
QByteArray HMIDocument::serializeItem(QGraphicsItem *item) |
|
|
|
{ |
|
|
|
QByteArray data; |
|
|
|
QDataStream stream(&data, QIODevice::WriteOnly); |
|
|
|
|
|
|
|
// 基础信息 |
|
|
|
stream << item->type(); |
|
|
|
stream << item->pos(); |
|
|
|
stream << item->flags(); |
|
|
|
stream << item->transform(); |
|
|
|
stream << item->isVisible(); |
|
|
|
// 形状信息 |
|
|
|
if (auto shape = dynamic_cast<QAbstractGraphicsShapeItem*>(item)) |
|
|
|
{ |
|
|
|
stream << shape->pen(); |
|
|
|
stream << shape->brush(); |
|
|
|
stream << shape->boundingRect(); |
|
|
|
} |
|
|
|
// 具体图形信息 |
|
|
|
if (auto rect = dynamic_cast<ResizableRectangle*>(item)) |
|
|
|
{ |
|
|
|
stream << rect->rect(); |
|
|
|
stream << rect->pressedColor(); |
|
|
|
stream << rect->releasedColor(); |
|
|
|
stream << rect->name(); |
|
|
|
} else if (auto ellipse = dynamic_cast<ResizableEllipse*>(item)) |
|
|
|
{ |
|
|
|
stream << ellipse->rect(); |
|
|
|
stream << ellipse->onColor(); |
|
|
|
stream << ellipse->offColor(); |
|
|
|
stream << ellipse->name(); |
|
|
|
} |
|
|
|
return data; |
|
|
|
} |
|
|
|
|
|
|
|
// 反序列化图形项(用于粘贴) |
|
|
|
QGraphicsItem *HMIDocument::deserializeItem(const QByteArray &data) |
|
|
|
{ |
|
|
|
QDataStream stream(data); |
|
|
|
int type; |
|
|
|
QPointF pos; |
|
|
|
QGraphicsItem::GraphicsItemFlags flags; |
|
|
|
QTransform transform; |
|
|
|
bool visible; |
|
|
|
|
|
|
|
stream >> type >> pos >> flags >> transform >> visible; |
|
|
|
|
|
|
|
QGraphicsItem *item = nullptr; |
|
|
|
if (type == QGraphicsRectItem::Type) { |
|
|
|
QPen pen; |
|
|
|
QBrush brush; |
|
|
|
QRectF boundRect; |
|
|
|
QRectF rect; |
|
|
|
QColor pressedColor, releasedColor; |
|
|
|
QString name; |
|
|
|
|
|
|
|
stream >> pen >> brush >> boundRect >> rect >> pressedColor >> releasedColor >> name; |
|
|
|
|
|
|
|
ResizableRectangle *rectItem = new ResizableRectangle(0, 0, rect.width(), rect.height()); |
|
|
|
rectItem->setPen(pen); |
|
|
|
rectItem->setBrush(brush); |
|
|
|
rectItem->setPressedColor(pressedColor); |
|
|
|
rectItem->setReleasedColor(releasedColor); |
|
|
|
rectItem->setName(name); |
|
|
|
item = rectItem; |
|
|
|
} else if (type == QGraphicsEllipseItem::Type) { |
|
|
|
QPen pen; |
|
|
|
QBrush brush; |
|
|
|
QRectF boundRect; |
|
|
|
QRectF rect; |
|
|
|
QColor onColor, offColor; |
|
|
|
QString name; |
|
|
|
|
|
|
|
stream >> pen >> brush >> boundRect >> rect >> onColor >> offColor >> name; |
|
|
|
|
|
|
|
ResizableEllipse *ellipseItem = new ResizableEllipse(0, 0, rect.width(), rect.height()); |
|
|
|
ellipseItem->setPen(pen); |
|
|
|
ellipseItem->setBrush(brush); |
|
|
|
ellipseItem->setOnColor(onColor); |
|
|
|
ellipseItem->setOffColor(offColor); |
|
|
|
ellipseItem->setName(name); |
|
|
|
item = ellipseItem; |
|
|
|
} |
|
|
|
|
|
|
|
if (item) { |
|
|
|
item->setFlags(flags); |
|
|
|
item->setTransform(transform); |
|
|
|
item->setVisible(visible); |
|
|
|
} |
|
|
|
|
|
|
|
return item; |
|
|
|
} |
|
|
|
void HMIDocument::startDrawingEllipse() |
|
|
|
{ |
|
|
|
m_canDrawEllipse = true; |
|
|
|
m_canDrawRectangle = false; |
|
|
|
} |
|
|
|
|
|
|
|
void HMIDocument::startDrawingRectangle() |
|
|
|
{ |
|
|
|
m_canDrawEllipse = false; |
|
|
|
m_canDrawRectangle = true; |
|
|
|
} |
|
|
|
|
|
|
|
bool HMIDocument::saveToFile(const QString &filePath) |
|
|
|
{ |
|
|
|
QFile file(filePath); |
|
|
|
if (!file.open(QIODevice::WriteOnly)) { |
|
|
|
qWarning() << "无法打开文件进行写入:" << filePath; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// 创建JSON文档结构 |
|
|
|
QJsonObject docObject; |
|
|
|
docObject["title"] = m_title; |
|
|
|
docObject["sceneRect"] = QJsonArray({ |
|
|
|
m_scene->sceneRect().x(), |
|
|
|
m_scene->sceneRect().y(), |
|
|
|
m_scene->sceneRect().width(), |
|
|
|
m_scene->sceneRect().height() |
|
|
|
}); |
|
|
|
docObject["backgroundColor"] = m_scene->backgroundBrush().color().name(); |
|
|
|
|
|
|
|
// 序列化所有图形项 |
|
|
|
QJsonArray itemsArray; |
|
|
|
foreach (QGraphicsItem *item, m_scene->items()) { |
|
|
|
QJsonObject itemJson = itemToJson(item); |
|
|
|
if (!itemJson.isEmpty()) { |
|
|
|
itemsArray.append(itemJson); |
|
|
|
} |
|
|
|
} |
|
|
|
docObject["items"] = itemsArray; |
|
|
|
|
|
|
|
// 写入文件 |
|
|
|
QJsonDocument doc(docObject); |
|
|
|
file.write(doc.toJson()); |
|
|
|
file.close(); |
|
|
|
|
|
|
|
// 更新文档状态 |
|
|
|
setFilePath(filePath); |
|
|
|
setModified(false); |
|
|
|
QFileInfo fileInfo(filePath); |
|
|
|
setTitle(fileInfo.baseName()); |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// 新增:从文件加载文档 |
|
|
|
bool HMIDocument::loadFromFile(const QString &filePath) |
|
|
|
{ |
|
|
|
QFile file(filePath); |
|
|
|
if (!file.open(QIODevice::ReadOnly)) { |
|
|
|
qWarning() << "无法打开文件进行读取:" << filePath; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// 读取JSON文档 |
|
|
|
QByteArray data = file.readAll(); |
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(data); |
|
|
|
if (doc.isNull()) { |
|
|
|
qWarning() << "无效的JSON文档:" << filePath; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// 解析文档 |
|
|
|
QJsonObject docObject = doc.object(); |
|
|
|
m_title = docObject["title"].toString(); |
|
|
|
|
|
|
|
// 设置场景属性 |
|
|
|
QJsonArray sceneRectArray = docObject["sceneRect"].toArray(); |
|
|
|
if (sceneRectArray.size() == 4) { |
|
|
|
QRectF sceneRect( |
|
|
|
sceneRectArray[0].toDouble(), |
|
|
|
sceneRectArray[1].toDouble(), |
|
|
|
sceneRectArray[2].toDouble(), |
|
|
|
sceneRectArray[3].toDouble() |
|
|
|
); |
|
|
|
m_scene->setSceneRect(sceneRect); |
|
|
|
} |
|
|
|
|
|
|
|
if (docObject.contains("backgroundColor")) { |
|
|
|
QColor bgColor(docObject["backgroundColor"].toString()); |
|
|
|
m_scene->setBackgroundBrush(QBrush(bgColor)); |
|
|
|
} |
|
|
|
|
|
|
|
// 清除现有内容 |
|
|
|
m_scene->clear(); |
|
|
|
|
|
|
|
// 加载所有图形项 |
|
|
|
QJsonArray itemsArray = docObject["items"].toArray(); |
|
|
|
foreach (QJsonValue itemValue, itemsArray) { |
|
|
|
QJsonObject itemJson = itemValue.toObject(); |
|
|
|
QGraphicsItem *item = jsonToItem(itemJson); |
|
|
|
if (item) { |
|
|
|
m_scene->addItem(item); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 更新文档状态 |
|
|
|
setFilePath(filePath); |
|
|
|
setModified(false); |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// 新增:将图形项转换为JSON对象 |
|
|
|
QJsonObject HMIDocument::itemToJson(QGraphicsItem *item) |
|
|
|
{ |
|
|
|
QJsonObject json; |
|
|
|
|
|
|
|
// 基础属性 |
|
|
|
json["type"] = item->type(); |
|
|
|
json["x"] = item->x(); |
|
|
|
json["y"] = item->y(); |
|
|
|
json["zValue"] = item->zValue(); |
|
|
|
json["visible"] = item->isVisible(); |
|
|
|
|
|
|
|
// 具体图形项属性 |
|
|
|
if (auto ellipse = dynamic_cast<ResizableEllipse*>(item)) { |
|
|
|
json["itemType"] = "ellipse"; |
|
|
|
json["rect"] = QJsonArray({ |
|
|
|
ellipse->rect().x(), |
|
|
|
ellipse->rect().y(), |
|
|
|
ellipse->rect().width(), |
|
|
|
ellipse->rect().height() |
|
|
|
}); |
|
|
|
json["onColor"] = ellipse->onColor().name(); |
|
|
|
json["offColor"] = ellipse->offColor().name(); |
|
|
|
json["currentColor"] = ellipse->brush().color().name(); |
|
|
|
json["penColor"] = ellipse->pen().color().name(); |
|
|
|
json["penWidth"] = ellipse->pen().width(); |
|
|
|
json["name"] = ellipse->name(); |
|
|
|
} |
|
|
|
else if (auto rect = dynamic_cast<ResizableRectangle*>(item)) { |
|
|
|
json["itemType"] = "rectangle"; |
|
|
|
json["rect"] = QJsonArray({ |
|
|
|
rect->rect().x(), |
|
|
|
rect->rect().y(), |
|
|
|
rect->rect().width(), |
|
|
|
rect->rect().height() |
|
|
|
}); |
|
|
|
json["pressedColor"] = rect->pressedColor().name(); |
|
|
|
json["releasedColor"] = rect->releasedColor().name(); |
|
|
|
json["currentColor"] = rect->brush().color().name(); |
|
|
|
json["penColor"] = rect->pen().color().name(); |
|
|
|
json["penWidth"] = rect->pen().width(); |
|
|
|
json["name"] = rect->name(); |
|
|
|
} |
|
|
|
|
|
|
|
return json; |
|
|
|
} |
|
|
|
|
|
|
|
// 新增:从JSON对象创建图形项 |
|
|
|
QGraphicsItem *HMIDocument::jsonToItem(const QJsonObject &json) |
|
|
|
{ |
|
|
|
QString itemType = json["itemType"].toString(); |
|
|
|
QGraphicsItem *item = nullptr; |
|
|
|
|
|
|
|
if (itemType == "ellipse") { |
|
|
|
QJsonArray rectArray = json["rect"].toArray(); |
|
|
|
if (rectArray.size() != 4) return nullptr; |
|
|
|
|
|
|
|
ResizableEllipse *ellipse = new ResizableEllipse( |
|
|
|
rectArray[0].toDouble(), |
|
|
|
rectArray[1].toDouble(), |
|
|
|
rectArray[2].toDouble(), |
|
|
|
rectArray[3].toDouble() |
|
|
|
); |
|
|
|
|
|
|
|
ellipse->setOnColor(QColor(json["onColor"].toString())); |
|
|
|
ellipse->setOffColor(QColor(json["offColor"].toString())); |
|
|
|
ellipse->setBrush(QColor(json["currentColor"].toString())); |
|
|
|
ellipse->setPen(QPen( |
|
|
|
QColor(json["penColor"].toString()), |
|
|
|
json["penWidth"].toDouble() |
|
|
|
)); |
|
|
|
ellipse->setName(json["name"].toString()); |
|
|
|
|
|
|
|
item = ellipse; |
|
|
|
} |
|
|
|
else if (itemType == "rectangle") { |
|
|
|
QJsonArray rectArray = json["rect"].toArray(); |
|
|
|
if (rectArray.size() != 4) return nullptr; |
|
|
|
|
|
|
|
ResizableRectangle *rect = new ResizableRectangle( |
|
|
|
rectArray[0].toDouble(), |
|
|
|
rectArray[1].toDouble(), |
|
|
|
rectArray[2].toDouble(), |
|
|
|
rectArray[3].toDouble() |
|
|
|
); |
|
|
|
rect->setPressedColor(QColor(json["pressedColor"].toString())); |
|
|
|
rect->setReleasedColor(QColor(json["releasedColor"].toString())); |
|
|
|
rect->setBrush(QColor(json["currentColor"].toString())); |
|
|
|
rect->setPen(QPen( |
|
|
|
QColor(json["penColor"].toString()), |
|
|
|
json["penWidth"].toDouble() |
|
|
|
)); |
|
|
|
rect->setName(json["name"].toString()); |
|
|
|
|
|
|
|
item = rect; |
|
|
|
} |
|
|
|
|
|
|
|
// 设置基础属性 |
|
|
|
if (item) { |
|
|
|
item->setX(json["x"].toDouble()); |
|
|
|
item->setY(json["y"].toDouble()); |
|
|
|
item->setZValue(json["zValue"].toDouble()); |
|
|
|
item->setVisible(json["visible"].toBool()); |
|
|
|
} |
|
|
|
|
|
|
|
return item; |
|
|
|
} |