@@ -8,7 +8,7 @@ Connection::Connection(Item* from, Item::AnchorType fromType, | |||||
: QGraphicsLineItem(parent), | : QGraphicsLineItem(parent), | ||||
from_(from), to_(to), fromType_(fromType), toType_(toType) | from_(from), to_(to), fromType_(fromType), toType_(toType) | ||||
{ | { | ||||
setZValue(-1); // 在图元之下 | |||||
setZValue(-1); | |||||
setPen(QPen(Qt::black, 2)); | setPen(QPen(Qt::black, 2)); | ||||
setFlags(QGraphicsItem::ItemIsSelectable); | setFlags(QGraphicsItem::ItemIsSelectable); | ||||
from_->addConnection(this); | from_->addConnection(this); | ||||
@@ -28,7 +28,8 @@ SOURCES += \ | |||||
main.cpp \ | main.cpp \ | ||||
mainwindow.cpp \ | mainwindow.cpp \ | ||||
mygraphicsview.cpp \ | mygraphicsview.cpp \ | ||||
plc.cpp | |||||
plc.cpp \ | |||||
project.cpp | |||||
HEADERS += \ | HEADERS += \ | ||||
button.h \ | button.h \ | ||||
@@ -42,7 +43,8 @@ HEADERS += \ | |||||
light.h \ | light.h \ | ||||
mainwindow.h \ | mainwindow.h \ | ||||
mygraphicsview.h \ | mygraphicsview.h \ | ||||
plc.h | |||||
plc.h \ | |||||
project.h | |||||
FORMS += \ | FORMS += \ | ||||
hmi.ui \ | hmi.ui \ | ||||
@@ -1,6 +1,6 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||
<!DOCTYPE QtCreatorProject> | <!DOCTYPE QtCreatorProject> | ||||
<!-- Written by QtCreator 4.11.1, 2025-08-07T09:52:05. --> | |||||
<!-- Written by QtCreator 4.11.1, 2025-08-07T18:51:27. --> | |||||
<qtcreator> | <qtcreator> | ||||
<data> | <data> | ||||
<variable>EnvironmentId</variable> | <variable>EnvironmentId</variable> | ||||
@@ -16,8 +16,8 @@ HMI::HMI(QWidget *parent) : | |||||
{ | { | ||||
ui->setupUi(this); | ui->setupUi(this); | ||||
/* 1. 场景 */ | /* 1. 场景 */ | ||||
m_scene = new QGraphicsScene(this); | |||||
ui->graphicsView->setScene(m_scene); | |||||
hmi_scene_ = new QGraphicsScene(this); | |||||
ui->graphicsView->setScene(hmi_scene_); | |||||
ui->graphicsView->setSceneRect(0, 0, 800, 600); | ui->graphicsView->setSceneRect(0, 0, 800, 600); | ||||
ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag); | ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag); | ||||
@@ -100,6 +100,66 @@ void HMI::createComponents() | |||||
} | } | ||||
} | } | ||||
void HMI::clearScene() | |||||
{ | |||||
hmi_scene_->clear(); | |||||
} | |||||
void HMI::applyProjectToScene(const Project& proj) | |||||
{ | |||||
clearScene(); | |||||
QVector<Item*> itemObjs; | |||||
for (const auto& d : proj.items_) { | |||||
Item* item = creatItem(d.type); | |||||
if (!item) continue; | |||||
item->setPos(d.x, d.y); | |||||
connect(item, &Item::requestCopy, ui->graphicsView, &MyGraphicsView::onItemRequestCopy); | |||||
connect(item, &Item::requestDelete, ui->graphicsView, &MyGraphicsView::onItemRequestDelete); | |||||
hmi_scene_->addItem(item); | |||||
itemObjs.append(item); | |||||
} | |||||
// for (const auto& c : proj.connections_) { | |||||
// if (c.from >= 0 && c.from < itemObjs.size() && c.to >= 0 && c.to < itemObjs.size()) { | |||||
// Connection* conn = new Connection( | |||||
// itemObjs[c.from], static_cast<Item::AnchorType>(c.fromType), | |||||
// itemObjs[c.to], static_cast<Item::AnchorType>(c.toType)); | |||||
// hmi_scene_->addItem(conn); | |||||
// } | |||||
// } | |||||
} | |||||
void HMI::extractSceneToProject(Project& proj) | |||||
{ | |||||
proj.clear(); | |||||
QList<Item*> items; | |||||
for (QGraphicsItem* gi : hmi_scene_->items()) { | |||||
if (Item* it = dynamic_cast<Item*>(gi)) { | |||||
items.append(it); | |||||
} | |||||
} | |||||
for (Item* it : items) { | |||||
Project::ItemData d; | |||||
d.type = it->itemType(); | |||||
d.x = it->pos().x(); | |||||
d.y = it->pos().y(); | |||||
proj.items_.append(d); | |||||
} | |||||
for (QGraphicsItem* gi : hmi_scene_->items()) { | |||||
if (Connection* conn = dynamic_cast<Connection*>(gi)) { | |||||
int fromIdx = items.indexOf(conn->from_); | |||||
int toIdx = items.indexOf(conn->to_); | |||||
if (fromIdx >= 0 && toIdx >= 0) { | |||||
Project::ConnectionData c; | |||||
c.from = fromIdx; | |||||
c.to = toIdx; | |||||
c.fromType = static_cast<int>(conn->fromType_); | |||||
c.toType = static_cast<int>(conn->toType_); | |||||
proj.connections_.append(c); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
void HMI::onListwidgetCurrenttextchanged(const QString &text) | void HMI::onListwidgetCurrenttextchanged(const QString &text) | ||||
{ | { | ||||
selectedComponentType = text; | selectedComponentType = text; | ||||
@@ -3,6 +3,7 @@ | |||||
#include <QGraphicsScene> | #include <QGraphicsScene> | ||||
#include <QWidget> | #include <QWidget> | ||||
#include <project.h> | |||||
namespace Ui { | namespace Ui { | ||||
class HMI; | class HMI; | ||||
@@ -17,6 +18,10 @@ public: | |||||
~HMI(); | ~HMI(); | ||||
void createComponents(); | void createComponents(); | ||||
void clearScene(); | |||||
void applyProjectToScene(const Project& proj); | |||||
void extractSceneToProject(Project& proj); | |||||
protected: | protected: | ||||
bool eventFilter(QObject *obj, QEvent *event) override; | bool eventFilter(QObject *obj, QEvent *event) override; | ||||
@@ -25,7 +30,7 @@ private slots: | |||||
private: | private: | ||||
Ui::HMI *ui; | Ui::HMI *ui; | ||||
QGraphicsScene *m_scene; | |||||
QGraphicsScene *hmi_scene_; | |||||
QString selectedComponentType; | QString selectedComponentType; | ||||
}; | }; | ||||
@@ -62,6 +62,7 @@ void Item::MenuActions(QMenu *menu) | |||||
{ | { | ||||
menu->addAction("复制"); | menu->addAction("复制"); | ||||
menu->addAction("删除"); | menu->addAction("删除"); | ||||
menu->addAction("对象"); | |||||
} | } | ||||
void Item::addMenuActions(QMenu *menu) | void Item::addMenuActions(QMenu *menu) | ||||
@@ -74,9 +75,12 @@ void Item::handleMenuAction(QAction *action) | |||||
if (action->text() == "复制") { | if (action->text() == "复制") { | ||||
emit requestCopy(this); | emit requestCopy(this); | ||||
} | } | ||||
else if (action->text() == "删除") { | |||||
if (action->text() == "删除") { | |||||
emit requestDelete(this); | emit requestDelete(this); | ||||
} | } | ||||
if (action->text() == "对象"){ | |||||
emit requestBindRegister(this); | |||||
} | |||||
} | } | ||||
QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value) | QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value) | ||||
@@ -90,16 +94,6 @@ QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value) | |||||
void Item::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) | void Item::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) | ||||
{ | { | ||||
// QMenu menu; | |||||
// QAction* copyAct = menu.addAction("复制"); | |||||
// QAction* deleteAct = menu.addAction("删除"); | |||||
// QAction* selected = menu.exec(event->screenPos()); | |||||
// if (selected == copyAct) { | |||||
// emit requestCopy(this); | |||||
// } | |||||
// if (selected == deleteAct) { | |||||
// emit requestDelete(this); | |||||
// } | |||||
QMenu menu; | QMenu menu; | ||||
// 创建菜单 | // 创建菜单 | ||||
@@ -21,19 +21,24 @@ public: | |||||
void removeConnection(Connection* conn); | void removeConnection(Connection* conn); | ||||
QList<Connection*> connections(); | QList<Connection*> connections(); | ||||
QString itemType(); | QString itemType(); | ||||
virtual void MenuActions(QMenu *menu); // 添加基本菜单项 | |||||
virtual void addMenuActions(QMenu *menu); // 添加额外菜单项 | |||||
virtual void handleMenuAction(QAction *action); // 处理菜单动作 | |||||
void setRegisterId(const QString& id) { registerId_ = id; } | |||||
QString registerId() const { return registerId_; } | |||||
signals: | signals: | ||||
void requestCopy(Item*); | void requestCopy(Item*); | ||||
void requestDelete(Item*); | void requestDelete(Item*); | ||||
void requestBindRegister(Item*); | |||||
protected: | protected: | ||||
virtual void MenuActions(QMenu *menu); | |||||
virtual void addMenuActions(QMenu *menu); | |||||
virtual void handleMenuAction(QAction *action); | |||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; | QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; | ||||
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; | void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; | ||||
QString type_; | QString type_; | ||||
QList<Connection*> connections_; | QList<Connection*> connections_; | ||||
QString registerId_; | |||||
}; | }; | ||||
#endif // ITEM_H | #endif // ITEM_H |
@@ -11,6 +11,7 @@ | |||||
#include <QGraphicsView> | #include <QGraphicsView> | ||||
#include <QMessageBox> | #include <QMessageBox> | ||||
#include <QAction> | #include <QAction> | ||||
#include <QFileDialog> | |||||
#include "creatitem.h" | #include "creatitem.h" | ||||
MainWindow::MainWindow(QWidget *parent) | MainWindow::MainWindow(QWidget *parent) | ||||
@@ -24,6 +25,13 @@ MainWindow::MainWindow(QWidget *parent) | |||||
hmi_->hide(); | hmi_->hide(); | ||||
connect(ui->action_plc,&QAction::triggered,this,&MainWindow::plcChange); | connect(ui->action_plc,&QAction::triggered,this,&MainWindow::plcChange); | ||||
connect(ui->action_hmi,&QAction::triggered,this,&MainWindow::hmiChange); | connect(ui->action_hmi,&QAction::triggered,this,&MainWindow::hmiChange); | ||||
connect(ui->action_new, &QAction::triggered, this, &MainWindow::newProject); | |||||
connect(ui->action_save, &QAction::triggered, this, &MainWindow::saveProject); | |||||
connect(ui->action_open, &QAction::triggered, this, &MainWindow::openProject); | |||||
plc_->applyProjectToScene(plcProject_); // 初始空 | |||||
hmi_->applyProjectToScene(hmiProject_); | |||||
} | } | ||||
MainWindow::~MainWindow() | MainWindow::~MainWindow() | ||||
@@ -35,11 +43,92 @@ void MainWindow::plcChange() | |||||
{ | { | ||||
plc_->show(); | plc_->show(); | ||||
hmi_->hide(); | hmi_->hide(); | ||||
currentIsPLC_ = true; | |||||
setWindowTitle((plcFilePath_.isEmpty() ? "未命名项目" : QFileInfo(plcFilePath_).fileName()) + " - PLC编辑器"); | |||||
} | } | ||||
void MainWindow::hmiChange() | void MainWindow::hmiChange() | ||||
{ | { | ||||
hmi_->show(); | hmi_->show(); | ||||
plc_->hide(); | plc_->hide(); | ||||
currentIsPLC_ = false; | |||||
setWindowTitle((hmiFilePath_.isEmpty() ? "未命名项目" : QFileInfo(hmiFilePath_).fileName()) + " - HMI编辑器"); | |||||
} | |||||
void MainWindow::newProject() | |||||
{ | |||||
if (currentIsPLC_) { | |||||
plcProject_.clear(); | |||||
plcFilePath_.clear(); | |||||
plc_->clearScene(); | |||||
setWindowTitle("未命名项目 - PLC编辑器"); | |||||
} else { | |||||
hmiProject_.clear(); | |||||
hmiFilePath_.clear(); | |||||
hmi_->clearScene(); | |||||
setWindowTitle("未命名项目 - HMI编辑器"); | |||||
} | |||||
} | } | ||||
void MainWindow::openProject() | |||||
{ | |||||
if (currentIsPLC_) | |||||
{ | |||||
QString filePath = QFileDialog::getOpenFileName(this, "打开项目", "", "项目文件 (*.plcproj)"); | |||||
if (filePath.isEmpty()) return; | |||||
if (plcProject_.loadFromFile(filePath)) | |||||
{ | |||||
plcFilePath_ = filePath; | |||||
plc_->applyProjectToScene(plcProject_); | |||||
setWindowTitle(QFileInfo(plcFilePath_).fileName() + " - PLC编辑器"); | |||||
} | |||||
else | |||||
{ | |||||
QMessageBox::critical(this, "错误", "无法打开PLC项目文件"); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
QString filePath = QFileDialog::getOpenFileName(this, "打开项目", "", "项目文件 (*.hmiproj)"); | |||||
if (filePath.isEmpty()) return; | |||||
if (hmiProject_.loadFromFile(filePath)) | |||||
{ | |||||
hmiFilePath_ = filePath; | |||||
hmi_->applyProjectToScene(hmiProject_); | |||||
setWindowTitle(QFileInfo(hmiFilePath_).fileName() + " - HMI编辑器"); | |||||
} | |||||
else | |||||
{ | |||||
QMessageBox::critical(this, "错误", "无法打开HMI项目文件"); | |||||
} | |||||
} | |||||
} | |||||
void MainWindow::saveProject() | |||||
{ | |||||
if (currentIsPLC_) { | |||||
if (plcFilePath_.isEmpty()) { | |||||
QString filePath = QFileDialog::getSaveFileName(this, "保存项目", "", "PLC项目文件 (*.plcproj)"); | |||||
if (filePath.isEmpty()) return; | |||||
if (!filePath.endsWith(".plcproj", Qt::CaseInsensitive)) | |||||
filePath += ".plcproj"; | |||||
plcFilePath_ = filePath; | |||||
} | |||||
plc_->extractSceneToProject(plcProject_); | |||||
if (!plcProject_.saveToFile(plcFilePath_)) { | |||||
QMessageBox::critical(this, "错误", "保存项目失败"); | |||||
} | |||||
} else { | |||||
if (hmiFilePath_.isEmpty()) { | |||||
QString filePath = QFileDialog::getSaveFileName(this, "保存项目", "", "HMI项目文件 (*.hmiproj)"); | |||||
if (filePath.isEmpty()) return; | |||||
if (!filePath.endsWith(".hmiproj", Qt::CaseInsensitive)) | |||||
filePath += ".hmiproj"; | |||||
hmiFilePath_ = filePath; | |||||
} | |||||
hmi_->extractSceneToProject(hmiProject_); | |||||
if (!hmiProject_.saveToFile(hmiFilePath_)) { | |||||
QMessageBox::critical(this, "错误", "保存项目失败"); | |||||
} | |||||
} | |||||
} |
@@ -21,11 +21,19 @@ public: | |||||
private slots: | private slots: | ||||
void plcChange(); | void plcChange(); | ||||
void hmiChange(); | void hmiChange(); | ||||
void newProject(); | |||||
void openProject(); | |||||
void saveProject(); | |||||
private: | private: | ||||
Ui::MainWindow *ui; | Ui::MainWindow *ui; | ||||
PLC *plc_; | PLC *plc_; | ||||
HMI *hmi_; | HMI *hmi_; | ||||
Project plcProject_; | |||||
Project hmiProject_; | |||||
QString plcFilePath_; | |||||
QString hmiFilePath_; | |||||
bool currentIsPLC_ = true; | |||||
}; | }; | ||||
#endif // MAINWINDOW_H | #endif // MAINWINDOW_H |
@@ -4,6 +4,7 @@ | |||||
#include <QGraphicsScene> | #include <QGraphicsScene> | ||||
#include <QDebug> | #include <QDebug> | ||||
#include <QMenu> | #include <QMenu> | ||||
#include <QInputDialog> | |||||
MyGraphicsView::ClipInfo MyGraphicsView::clipboard_ = {}; | MyGraphicsView::ClipInfo MyGraphicsView::clipboard_ = {}; | ||||
@@ -46,6 +47,7 @@ void MyGraphicsView::dropEvent(QDropEvent *event) | |||||
item->setPos(scenePos); | item->setPos(scenePos); | ||||
connect(item, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy); | connect(item, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy); | ||||
connect(item, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete); | connect(item, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete); | ||||
connect(item, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister); | |||||
scene()->addItem(item); | scene()->addItem(item); | ||||
event->acceptProposedAction(); | event->acceptProposedAction(); | ||||
@@ -92,6 +94,7 @@ void MyGraphicsView::keyPressEvent(QKeyEvent *event) | |||||
newItem->setPos(center); | newItem->setPos(center); | ||||
connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy); | connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy); | ||||
connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete); | connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete); | ||||
connect(newItem, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister); | |||||
scene()->addItem(newItem); | scene()->addItem(newItem); | ||||
} | } | ||||
} else { | } else { | ||||
@@ -112,6 +115,7 @@ void MyGraphicsView::contextMenuEvent(QContextMenuEvent *event) | |||||
newItem->setPos(scenePos); | newItem->setPos(scenePos); | ||||
connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy); | connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy); | ||||
connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete); | connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete); | ||||
connect(newItem, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister); | |||||
scene()->addItem(newItem); | scene()->addItem(newItem); | ||||
} | } | ||||
} else { | } else { | ||||
@@ -159,6 +163,21 @@ void MyGraphicsView::onItemRequestDelete(Item *item) | |||||
delete item; | delete item; | ||||
} | } | ||||
void MyGraphicsView::onItemRequestBindRegister(Item *item) | |||||
{ | |||||
bool ok = false; | |||||
QString reg = QInputDialog::getText(this, | |||||
"寄存器", "编号:", | |||||
QLineEdit::Normal, | |||||
item->registerId(), | |||||
&ok); | |||||
if (ok && !reg.isEmpty()) { | |||||
item->setRegisterId(reg); | |||||
// 可选:在图元上显示寄存器编号 | |||||
item->update(); | |||||
} | |||||
} | |||||
void MyGraphicsView::mousePressEvent(QMouseEvent *event) | void MyGraphicsView::mousePressEvent(QMouseEvent *event) | ||||
{ | { | ||||
if (event->button() == Qt::LeftButton) { | if (event->button() == Qt::LeftButton) { | ||||
@@ -44,6 +44,7 @@ private: | |||||
public slots: | public slots: | ||||
void onItemRequestCopy(Item*); | void onItemRequestCopy(Item*); | ||||
void onItemRequestDelete(Item*); | void onItemRequestDelete(Item*); | ||||
void onItemRequestBindRegister(Item*); | |||||
}; | }; | ||||
#endif // MYGRAPHICSVIEW_H | #endif // MYGRAPHICSVIEW_H |
@@ -18,8 +18,8 @@ PLC::PLC(QWidget *parent) : | |||||
{ | { | ||||
ui->setupUi(this); | ui->setupUi(this); | ||||
/* 1. 场景 */ | /* 1. 场景 */ | ||||
m_scene = new QGraphicsScene(this); | |||||
ui->graphicsView->setScene(m_scene); | |||||
plc_scene_ = new QGraphicsScene(this); | |||||
ui->graphicsView->setScene(plc_scene_); | |||||
ui->graphicsView->setSceneRect(0, 0, 800, 600); | ui->graphicsView->setSceneRect(0, 0, 800, 600); | ||||
ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag); | ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag); | ||||
@@ -105,6 +105,70 @@ void PLC::createComponents() | |||||
} | } | ||||
} | } | ||||
void PLC::clearScene() | |||||
{ | |||||
plc_scene_->clear(); | |||||
} | |||||
void PLC::applyProjectToScene(const Project& proj) | |||||
{ | |||||
clearScene(); | |||||
QVector<Item*> itemObjs; | |||||
for (const auto& d : proj.items_) { | |||||
Item* item = creatItem(d.type); | |||||
if (!item) continue; | |||||
item->setPos(d.x, d.y); | |||||
connect(item, &Item::requestCopy, ui->graphicsView, &MyGraphicsView::onItemRequestCopy); | |||||
connect(item, &Item::requestDelete, ui->graphicsView, &MyGraphicsView::onItemRequestDelete); | |||||
connect(item, &Item::requestBindRegister, ui->graphicsView, &MyGraphicsView::onItemRequestBindRegister); | |||||
plc_scene_->addItem(item); | |||||
itemObjs.append(item); | |||||
} | |||||
for (const auto& c : proj.connections_) { | |||||
if (c.from >= 0 && c.from < itemObjs.size() && c.to >= 0 && c.to < itemObjs.size()) { | |||||
Connection* conn = new Connection( | |||||
itemObjs[c.from], static_cast<Item::AnchorType>(c.fromType), | |||||
itemObjs[c.to], static_cast<Item::AnchorType>(c.toType)); | |||||
plc_scene_->addItem(conn); | |||||
} | |||||
} | |||||
} | |||||
void PLC::extractSceneToProject(Project& proj) | |||||
{ | |||||
proj.clear(); | |||||
QList<Item*> items; | |||||
// (1) 先收集所有Item | |||||
for (QGraphicsItem* gi : plc_scene_->items()) { | |||||
if (Item* it = dynamic_cast<Item*>(gi)) { | |||||
items.append(it); | |||||
} | |||||
} | |||||
// (2) 存Item数据 | |||||
for (Item* it : items) { | |||||
Project::ItemData d; | |||||
d.type = it->itemType(); | |||||
d.x = it->pos().x(); | |||||
d.y = it->pos().y(); | |||||
proj.items_.append(d); | |||||
} | |||||
// (3) 存连线数据 | |||||
for (QGraphicsItem* gi : plc_scene_->items()) { | |||||
if (Connection* conn = dynamic_cast<Connection*>(gi)) { | |||||
int fromIdx = items.indexOf(conn->from_); | |||||
int toIdx = items.indexOf(conn->to_); | |||||
if (fromIdx >= 0 && toIdx >= 0) { | |||||
Project::ConnectionData c; | |||||
c.from = fromIdx; | |||||
c.to = toIdx; | |||||
c.fromType = static_cast<int>(conn->fromType_); | |||||
c.toType = static_cast<int>(conn->toType_); | |||||
proj.connections_.append(c); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
void PLC::onListwidgetCurrenttextchanged(const QString &text) | void PLC::onListwidgetCurrenttextchanged(const QString &text) | ||||
{ | { | ||||
selectedComponentType = text; | selectedComponentType = text; | ||||
@@ -3,6 +3,7 @@ | |||||
#include <QGraphicsScene> | #include <QGraphicsScene> | ||||
#include <QWidget> | #include <QWidget> | ||||
#include "project.h" | |||||
namespace Ui { | namespace Ui { | ||||
class PLC; | class PLC; | ||||
@@ -17,6 +18,10 @@ public: | |||||
~PLC(); | ~PLC(); | ||||
void createComponents(); | void createComponents(); | ||||
void clearScene(); | |||||
void applyProjectToScene(const Project& proj); // 加载工程到scene | |||||
void extractSceneToProject(Project& proj); // 从scene导出工程数据 | |||||
protected: | protected: | ||||
bool eventFilter(QObject *obj, QEvent *event) override; | bool eventFilter(QObject *obj, QEvent *event) override; | ||||
@@ -26,7 +31,7 @@ private slots: | |||||
private: | private: | ||||
Ui::PLC *ui; | Ui::PLC *ui; | ||||
QGraphicsScene *m_scene; | |||||
QGraphicsScene *plc_scene_; | |||||
QString selectedComponentType; | QString selectedComponentType; | ||||
}; | }; | ||||
@@ -0,0 +1,68 @@ | |||||
#include "project.h" | |||||
#include <QJsonDocument> | |||||
#include <QJsonObject> | |||||
#include <QJsonArray> | |||||
#include <QFile> | |||||
bool Project::saveToFile(const QString& filePath) const { | |||||
QJsonObject root; | |||||
QJsonArray itemsArray; | |||||
for (const ItemData& item : items_) { | |||||
QJsonObject obj; | |||||
obj["type"] = item.type; | |||||
obj["x"] = item.x; | |||||
obj["y"] = item.y; | |||||
itemsArray.append(obj); | |||||
} | |||||
root["items"] = itemsArray; | |||||
QJsonArray connArray; | |||||
for (const ConnectionData& c : connections_) { | |||||
QJsonObject obj; | |||||
obj["from"] = c.from; | |||||
obj["to"] = c.to; | |||||
obj["fromType"] = c.fromType; | |||||
obj["toType"] = c.toType; | |||||
connArray.append(obj); | |||||
} | |||||
root["connections"] = connArray; | |||||
QFile file(filePath); | |||||
if (!file.open(QIODevice::WriteOnly)) | |||||
return false; | |||||
file.write(QJsonDocument(root).toJson()); | |||||
file.close(); | |||||
return true; | |||||
} | |||||
bool Project::loadFromFile(const QString& filePath) { | |||||
clear(); | |||||
QFile file(filePath); | |||||
if (!file.open(QIODevice::ReadOnly)) | |||||
return false; | |||||
QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); | |||||
file.close(); | |||||
if (doc.isNull()) return false; | |||||
QJsonObject root = doc.object(); | |||||
QJsonArray itemsArray = root["items"].toArray(); | |||||
for (const QJsonValue& v : itemsArray) { | |||||
QJsonObject obj = v.toObject(); | |||||
ItemData d; | |||||
d.type = obj["type"].toString(); | |||||
d.x = obj["x"].toDouble(); | |||||
d.y = obj["y"].toDouble(); | |||||
items_.append(d); | |||||
} | |||||
QJsonArray connArray = root["connections"].toArray(); | |||||
for (const QJsonValue& v : connArray) { | |||||
QJsonObject obj = v.toObject(); | |||||
ConnectionData d; | |||||
d.from = obj["from"].toInt(); | |||||
d.to = obj["to"].toInt(); | |||||
d.fromType = obj["fromType"].toInt(); | |||||
d.toType = obj["toType"].toInt(); | |||||
connections_.append(d); | |||||
} | |||||
return true; | |||||
} |
@@ -0,0 +1,28 @@ | |||||
#ifndef PROJECT_H | |||||
#define PROJECT_H | |||||
#include <QString> | |||||
#include <QList> | |||||
// PLC工程数据模型 | |||||
class Project | |||||
{ | |||||
public: | |||||
struct ItemData { | |||||
QString type; | |||||
double x, y; | |||||
}; | |||||
struct ConnectionData { | |||||
int from, to; | |||||
int fromType, toType; | |||||
}; | |||||
void clear() { items_.clear(); connections_.clear(); } | |||||
bool saveToFile(const QString& filePath) const; | |||||
bool loadFromFile(const QString& filePath); | |||||
QList<ItemData> items_; | |||||
QList<ConnectionData> connections_; | |||||
}; | |||||
#endif // PROJECT_H |