Browse Source

保存读取文件功能

master
鹏鹏 李 2 days ago
parent
commit
0b76463cae
15 changed files with 372 additions and 24 deletions
  1. +1
    -1
      connection.cpp
  2. +4
    -2
      editor.pro
  3. +1
    -1
      editor.pro.user
  4. +62
    -2
      hmi.cpp
  5. +6
    -1
      hmi.h
  6. +5
    -11
      item.cpp
  7. +8
    -3
      item.h
  8. +89
    -0
      mainwindow.cpp
  9. +8
    -0
      mainwindow.h
  10. +19
    -0
      mygraphicsview.cpp
  11. +1
    -0
      mygraphicsview.h
  12. +66
    -2
      plc.cpp
  13. +6
    -1
      plc.h
  14. +68
    -0
      project.cpp
  15. +28
    -0
      project.h

+ 1
- 1
connection.cpp View File

@@ -8,7 +8,7 @@ Connection::Connection(Item* from, Item::AnchorType fromType,
: QGraphicsLineItem(parent),
from_(from), to_(to), fromType_(fromType), toType_(toType)
{
setZValue(-1); // 在图元之下
setZValue(-1);
setPen(QPen(Qt::black, 2));
setFlags(QGraphicsItem::ItemIsSelectable);
from_->addConnection(this);


+ 4
- 2
editor.pro View File

@@ -28,7 +28,8 @@ SOURCES += \
main.cpp \
mainwindow.cpp \
mygraphicsview.cpp \
plc.cpp
plc.cpp \
project.cpp

HEADERS += \
button.h \
@@ -42,7 +43,8 @@ HEADERS += \
light.h \
mainwindow.h \
mygraphicsview.h \
plc.h
plc.h \
project.h

FORMS += \
hmi.ui \


+ 1
- 1
editor.pro.user View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<data>
<variable>EnvironmentId</variable>


+ 62
- 2
hmi.cpp View File

@@ -16,8 +16,8 @@ HMI::HMI(QWidget *parent) :
{
ui->setupUi(this);
/* 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->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)
{
selectedComponentType = text;


+ 6
- 1
hmi.h View File

@@ -3,6 +3,7 @@

#include <QGraphicsScene>
#include <QWidget>
#include <project.h>

namespace Ui {
class HMI;
@@ -17,6 +18,10 @@ public:
~HMI();
void createComponents();

void clearScene();
void applyProjectToScene(const Project& proj);
void extractSceneToProject(Project& proj);

protected:
bool eventFilter(QObject *obj, QEvent *event) override;

@@ -25,7 +30,7 @@ private slots:

private:
Ui::HMI *ui;
QGraphicsScene *m_scene;
QGraphicsScene *hmi_scene_;
QString selectedComponentType;
};



+ 5
- 11
item.cpp View File

@@ -62,6 +62,7 @@ void Item::MenuActions(QMenu *menu)
{
menu->addAction("复制");
menu->addAction("删除");
menu->addAction("对象");
}

void Item::addMenuActions(QMenu *menu)
@@ -74,9 +75,12 @@ void Item::handleMenuAction(QAction *action)
if (action->text() == "复制") {
emit requestCopy(this);
}
else if (action->text() == "删除") {
if (action->text() == "删除") {
emit requestDelete(this);
}
if (action->text() == "对象"){
emit requestBindRegister(this);
}
}

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)
{
// 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;

// 创建菜单


+ 8
- 3
item.h View File

@@ -21,19 +21,24 @@ public:
void removeConnection(Connection* conn);
QList<Connection*> connections();
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:
void requestCopy(Item*);
void requestDelete(Item*);
void requestBindRegister(Item*);

protected:
virtual void MenuActions(QMenu *menu);
virtual void addMenuActions(QMenu *menu);
virtual void handleMenuAction(QAction *action);
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
QString type_;
QList<Connection*> connections_;
QString registerId_;
};

#endif // ITEM_H

+ 89
- 0
mainwindow.cpp View File

@@ -11,6 +11,7 @@
#include <QGraphicsView>
#include <QMessageBox>
#include <QAction>
#include <QFileDialog>
#include "creatitem.h"

MainWindow::MainWindow(QWidget *parent)
@@ -24,6 +25,13 @@ MainWindow::MainWindow(QWidget *parent)
hmi_->hide();
connect(ui->action_plc,&QAction::triggered,this,&MainWindow::plcChange);
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()
@@ -35,11 +43,92 @@ void MainWindow::plcChange()
{
plc_->show();
hmi_->hide();
currentIsPLC_ = true;
setWindowTitle((plcFilePath_.isEmpty() ? "未命名项目" : QFileInfo(plcFilePath_).fileName()) + " - PLC编辑器");
}

void MainWindow::hmiChange()
{
hmi_->show();
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, "错误", "保存项目失败");
}
}
}

+ 8
- 0
mainwindow.h View File

@@ -21,11 +21,19 @@ public:
private slots:
void plcChange();
void hmiChange();
void newProject();
void openProject();
void saveProject();

private:
Ui::MainWindow *ui;
PLC *plc_;
HMI *hmi_;
Project plcProject_;
Project hmiProject_;
QString plcFilePath_;
QString hmiFilePath_;
bool currentIsPLC_ = true;
};

#endif // MAINWINDOW_H

+ 19
- 0
mygraphicsview.cpp View File

@@ -4,6 +4,7 @@
#include <QGraphicsScene>
#include <QDebug>
#include <QMenu>
#include <QInputDialog>

MyGraphicsView::ClipInfo MyGraphicsView::clipboard_ = {};

@@ -46,6 +47,7 @@ void MyGraphicsView::dropEvent(QDropEvent *event)
item->setPos(scenePos);
connect(item, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
connect(item, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
connect(item, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister);
scene()->addItem(item);

event->acceptProposedAction();
@@ -92,6 +94,7 @@ void MyGraphicsView::keyPressEvent(QKeyEvent *event)
newItem->setPos(center);
connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
connect(newItem, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister);
scene()->addItem(newItem);
}
} else {
@@ -112,6 +115,7 @@ void MyGraphicsView::contextMenuEvent(QContextMenuEvent *event)
newItem->setPos(scenePos);
connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
connect(newItem, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister);
scene()->addItem(newItem);
}
} else {
@@ -159,6 +163,21 @@ void MyGraphicsView::onItemRequestDelete(Item *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)
{
if (event->button() == Qt::LeftButton) {


+ 1
- 0
mygraphicsview.h View File

@@ -44,6 +44,7 @@ private:
public slots:
void onItemRequestCopy(Item*);
void onItemRequestDelete(Item*);
void onItemRequestBindRegister(Item*);
};

#endif // MYGRAPHICSVIEW_H

+ 66
- 2
plc.cpp View File

@@ -18,8 +18,8 @@ PLC::PLC(QWidget *parent) :
{
ui->setupUi(this);
/* 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->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)
{
selectedComponentType = text;


+ 6
- 1
plc.h View File

@@ -3,6 +3,7 @@

#include <QGraphicsScene>
#include <QWidget>
#include "project.h"

namespace Ui {
class PLC;
@@ -17,6 +18,10 @@ public:
~PLC();
void createComponents();

void clearScene();
void applyProjectToScene(const Project& proj); // 加载工程到scene
void extractSceneToProject(Project& proj); // 从scene导出工程数据

protected:
bool eventFilter(QObject *obj, QEvent *event) override;

@@ -26,7 +31,7 @@ private slots:

private:
Ui::PLC *ui;
QGraphicsScene *m_scene;
QGraphicsScene *plc_scene_;
QString selectedComponentType;
};



+ 68
- 0
project.cpp View File

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

+ 28
- 0
project.h View File

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

Loading…
Cancel
Save