@@ -8,6 +8,7 @@ | |||||
#include <QDropEvent> | #include <QDropEvent> | ||||
#include <QGraphicsView> | #include <QGraphicsView> | ||||
#include <QMessageBox> | #include <QMessageBox> | ||||
#include <QVBoxLayout> | |||||
#include "creatitem.h" | #include "creatitem.h" | ||||
HMI::HMI(QWidget *parent) : | HMI::HMI(QWidget *parent) : | ||||
@@ -15,11 +16,9 @@ HMI::HMI(QWidget *parent) : | |||||
ui(new Ui::HMI) | ui(new Ui::HMI) | ||||
{ | { | ||||
ui->setupUi(this); | ui->setupUi(this); | ||||
/* 1. 场景 */ | |||||
hmi_scene_ = new QGraphicsScene(this); | |||||
ui->graphicsView->setScene(hmi_scene_); | |||||
ui->graphicsView->setSceneRect(0, 0, 800, 600); | |||||
ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag); | |||||
ui->tabWidget->setTabsClosable(true); | |||||
ui->tabWidget->setMovable(true); | |||||
/* 2. 列表 */ | /* 2. 列表 */ | ||||
ui->listWidget->setViewMode(QListView::IconMode); | ui->listWidget->setViewMode(QListView::IconMode); | ||||
@@ -27,16 +26,53 @@ HMI::HMI(QWidget *parent) : | |||||
ui->listWidget->setDragEnabled(false); | ui->listWidget->setDragEnabled(false); | ||||
ui->listWidget->viewport()->installEventFilter(this); | ui->listWidget->viewport()->installEventFilter(this); | ||||
// 创建初始页面 | |||||
newPage(); | |||||
/* 3. 填充列表 */ | /* 3. 填充列表 */ | ||||
createComponents(); | createComponents(); | ||||
connect(ui->listWidget,&QListWidget::currentTextChanged,this,&HMI::onListwidgetCurrenttextchanged); | connect(ui->listWidget,&QListWidget::currentTextChanged,this,&HMI::onListwidgetCurrenttextchanged); | ||||
// 连接标签页信号 | |||||
// connect(ui->tabWidget, &QTabWidget::currentChanged, this, &HMI::onTabChanged); | |||||
connect(ui->tabWidget, &QTabWidget::tabCloseRequested, [this](int index) { | |||||
if (scenes.size() > 1) { | |||||
delete scenes.takeAt(index); | |||||
delete views.takeAt(index); | |||||
ui->tabWidget->removeTab(index); | |||||
} else { | |||||
QMessageBox::information(this, "提示", "至少保留一个页面"); | |||||
} | |||||
}); | |||||
} | } | ||||
HMI::~HMI() | HMI::~HMI() | ||||
{ | { | ||||
qDeleteAll(scenes); | |||||
qDeleteAll(views); | |||||
delete ui; | delete ui; | ||||
} | } | ||||
void HMI::newPage() | |||||
{ | |||||
// 创建新场景 | |||||
QGraphicsScene* newScene = new QGraphicsScene(this); | |||||
// 创建新视图 | |||||
MyGraphicsView* newView = new MyGraphicsView(ui->tabWidget); | |||||
newView->setScene(newScene); | |||||
newView->setSceneRect(0, 0, 800, 600); | |||||
newView->setDragMode(QGraphicsView::RubberBandDrag); | |||||
// 添加到标签页 | |||||
int newIndex = ui->tabWidget->addTab(newView, QString("页面 %1").arg(scenes.size() + 1)); | |||||
ui->tabWidget->setCurrentIndex(newIndex); | |||||
// 保存场景和视图 | |||||
scenes.append(newScene); | |||||
views.append(newView); | |||||
} | |||||
bool HMI::eventFilter(QObject *obj, QEvent *event) | bool HMI::eventFilter(QObject *obj, QEvent *event) | ||||
{ | { | ||||
if (obj == ui->listWidget->viewport()) { | if (obj == ui->listWidget->viewport()) { | ||||
@@ -102,32 +138,43 @@ void HMI::createComponents() | |||||
void HMI::clearScene() | void HMI::clearScene() | ||||
{ | { | ||||
hmi_scene_->clear(); | |||||
if (currentPageIndex() >= 0 && currentPageIndex() < scenes.size()) { | |||||
scenes[currentPageIndex()]->clear(); | |||||
} | |||||
} | } | ||||
void HMI::applyProjectToScene(const Project& proj) | |||||
int HMI::currentPageIndex() const | |||||
{ | { | ||||
clearScene(); | |||||
return ui->tabWidget->currentIndex(); | |||||
} | |||||
void HMI::applyProjectToScene(const Project& proj, int pageIndex) | |||||
{ | |||||
if (pageIndex < 0 || pageIndex >= scenes.size()) | |||||
return; | |||||
scenes[pageIndex]->clear(); | |||||
QVector<Item*> itemObjs; | QVector<Item*> itemObjs; | ||||
for (const auto& d : proj.items_) { | for (const auto& d : proj.items_) { | ||||
Item* item = creatItem(d.type); | Item* item = creatItem(d.type); | ||||
if (!item) continue; | if (!item) continue; | ||||
item->setPos(d.x, d.y); | item->setPos(d.x, d.y); | ||||
item->setRegisterId(d.registerId); | item->setRegisterId(d.registerId); | ||||
connect(item, &Item::requestCopy, ui->graphicsView, &MyGraphicsView::onItemRequestCopy); | |||||
connect(item, &Item::requestDelete, ui->graphicsView, &MyGraphicsView::onItemRequestDelete); | |||||
connect(item, &Item::requestBindRegister, ui->graphicsView, &MyGraphicsView::onItemRequestBindRegister); | |||||
hmi_scene_->addItem(item); | |||||
connect(item, &Item::requestCopy, views[pageIndex], &MyGraphicsView::onItemRequestCopy); | |||||
connect(item, &Item::requestDelete, views[pageIndex], &MyGraphicsView::onItemRequestDelete); | |||||
connect(item, &Item::requestBindRegister, views[pageIndex], &MyGraphicsView::onItemRequestBindRegister); | |||||
scenes[pageIndex]->addItem(item); | |||||
itemObjs.append(item); | itemObjs.append(item); | ||||
} | } | ||||
} | } | ||||
void HMI::extractSceneToProject(Project& proj) | |||||
void HMI::extractSceneToProject(Project& proj, int pageIndex) | |||||
{ | { | ||||
if (pageIndex < 0 || pageIndex >= scenes.size()) return; | |||||
proj.clear(); | proj.clear(); | ||||
QList<Item*> items; | QList<Item*> items; | ||||
for (QGraphicsItem* gi : hmi_scene_->items()) { | |||||
if (Item* it = dynamic_cast<Item*>(gi)) { | |||||
for (QGraphicsItem* gi : scenes[pageIndex]->items()){ | |||||
if (Item* it = dynamic_cast<Item*>(gi)){ | |||||
items.append(it); | items.append(it); | ||||
} | } | ||||
} | } | ||||
@@ -139,7 +186,7 @@ void HMI::extractSceneToProject(Project& proj) | |||||
d.registerId = it->registerId(); | d.registerId = it->registerId(); | ||||
proj.items_.append(d); | proj.items_.append(d); | ||||
} | } | ||||
for (QGraphicsItem* gi : hmi_scene_->items()) { | |||||
for (QGraphicsItem* gi : scenes[pageIndex]->items()) { | |||||
if (Connection* conn = dynamic_cast<Connection*>(gi)) { | if (Connection* conn = dynamic_cast<Connection*>(gi)) { | ||||
int fromIdx = items.indexOf(conn->from_); | int fromIdx = items.indexOf(conn->from_); | ||||
int toIdx = items.indexOf(conn->to_); | int toIdx = items.indexOf(conn->to_); | ||||
@@ -4,6 +4,7 @@ | |||||
#include <QGraphicsScene> | #include <QGraphicsScene> | ||||
#include <QWidget> | #include <QWidget> | ||||
#include <project.h> | #include <project.h> | ||||
#include "mygraphicsview.h" | |||||
namespace Ui { | namespace Ui { | ||||
class HMI; | class HMI; | ||||
@@ -16,11 +17,13 @@ class HMI : public QWidget | |||||
public: | public: | ||||
explicit HMI(QWidget *parent = nullptr); | explicit HMI(QWidget *parent = nullptr); | ||||
~HMI(); | ~HMI(); | ||||
void newPage(); | |||||
void createComponents(); | void createComponents(); | ||||
void clearScene(); | void clearScene(); | ||||
void applyProjectToScene(const Project& proj); | |||||
void extractSceneToProject(Project& proj); | |||||
void applyProjectToScene(const Project& proj, int pageIndex = 0); // 添加页面索引参数 | |||||
void extractSceneToProject(Project& proj, int pageIndex = 0); // 添加页面索引参数 | |||||
int currentPageIndex() const; // 获取当前页面索引 | |||||
protected: | protected: | ||||
bool eventFilter(QObject *obj, QEvent *event) override; | bool eventFilter(QObject *obj, QEvent *event) override; | ||||
@@ -30,7 +33,8 @@ private slots: | |||||
private: | private: | ||||
Ui::HMI *ui; | Ui::HMI *ui; | ||||
QGraphicsScene *hmi_scene_; | |||||
QList<QGraphicsScene*> scenes; // 存储多个场景 | |||||
QList<MyGraphicsView*> views; // 存储多个视图 | |||||
QString selectedComponentType; | QString selectedComponentType; | ||||
}; | }; | ||||
@@ -19,7 +19,7 @@ | |||||
<x>10</x> | <x>10</x> | ||||
<y>30</y> | <y>30</y> | ||||
<width>171</width> | <width>171</width> | ||||
<height>451</height> | |||||
<height>431</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
</widget> | </widget> | ||||
@@ -29,44 +29,14 @@ | |||||
<x>190</x> | <x>190</x> | ||||
<y>10</y> | <y>10</y> | ||||
<width>781</width> | <width>781</width> | ||||
<height>481</height> | |||||
<height>451</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<property name="currentIndex"> | <property name="currentIndex"> | ||||
<number>0</number> | |||||
<number>-1</number> | |||||
</property> | </property> | ||||
<widget class="QWidget" name="tab"> | |||||
<attribute name="title"> | |||||
<string>Tab 1</string> | |||||
</attribute> | |||||
<widget class="MyGraphicsView" name="graphicsView"> | |||||
<property name="geometry"> | |||||
<rect> | |||||
<x>0</x> | |||||
<y>0</y> | |||||
<width>761</width> | |||||
<height>451</height> | |||||
</rect> | |||||
</property> | |||||
<property name="dragMode"> | |||||
<enum>QGraphicsView::NoDrag</enum> | |||||
</property> | |||||
</widget> | |||||
</widget> | |||||
<widget class="QWidget" name="tab_2"> | |||||
<attribute name="title"> | |||||
<string>Tab 2</string> | |||||
</attribute> | |||||
</widget> | |||||
</widget> | </widget> | ||||
</widget> | </widget> | ||||
<customwidgets> | |||||
<customwidget> | |||||
<class>MyGraphicsView</class> | |||||
<extends>QGraphicsView</extends> | |||||
<header>mygraphicsview.h</header> | |||||
</customwidget> | |||||
</customwidgets> | |||||
<resources/> | <resources/> | ||||
<connections/> | <connections/> | ||||
</ui> | </ui> |
@@ -35,7 +35,7 @@ MainWindow::MainWindow(QWidget *parent) | |||||
connect(ui->action_disconnect, &QAction::triggered, this, &MainWindow::disconnection); | connect(ui->action_disconnect, &QAction::triggered, this, &MainWindow::disconnection); | ||||
connect(modbusManager, &ModbusManager::connectionStatusChanged, | connect(modbusManager, &ModbusManager::connectionStatusChanged, | ||||
plc_, &PLC::updateConnectionStatus); | |||||
this, &MainWindow::updateConnectionStatus); | |||||
plc_->applyProjectToScene(plcProject_); // 初始空 | plc_->applyProjectToScene(plcProject_); // 初始空 | ||||
@@ -71,9 +71,11 @@ void MainWindow::newProject() | |||||
plc_->clearScene(); | plc_->clearScene(); | ||||
setWindowTitle("未命名项目 - PLC编辑器"); | setWindowTitle("未命名项目 - PLC编辑器"); | ||||
} else { | } else { | ||||
hmiProject_.clear(); | |||||
hmi_->newPage(); | |||||
hmiProject_.clear(); // 清除项目数据 | |||||
hmiFilePath_.clear(); | hmiFilePath_.clear(); | ||||
hmi_->clearScene(); | |||||
// 更新窗口标题 | |||||
setWindowTitle("未命名项目 - HMI编辑器"); | setWindowTitle("未命名项目 - HMI编辑器"); | ||||
} | } | ||||
} | } | ||||
@@ -99,14 +101,20 @@ void MainWindow::openProject() | |||||
{ | { | ||||
QString filePath = QFileDialog::getOpenFileName(this, "打开项目", "", "项目文件 (*.hmiproj)"); | QString filePath = QFileDialog::getOpenFileName(this, "打开项目", "", "项目文件 (*.hmiproj)"); | ||||
if (filePath.isEmpty()) return; | if (filePath.isEmpty()) return; | ||||
if (hmiProject_.loadFromFile(filePath)) | |||||
{ | |||||
Project newProject; | |||||
if (newProject.loadFromFile(filePath)) { | |||||
// 创建新页面 | |||||
hmi_->newPage(); | |||||
// 应用项目到新页面 | |||||
int newPageIndex = hmi_->currentPageIndex(); | |||||
hmi_->applyProjectToScene(newProject, newPageIndex); | |||||
// 保存文件路径 | |||||
hmiFilePath_ = filePath; | hmiFilePath_ = filePath; | ||||
hmi_->applyProjectToScene(hmiProject_); | |||||
setWindowTitle(QFileInfo(hmiFilePath_).fileName() + " - HMI编辑器"); | setWindowTitle(QFileInfo(hmiFilePath_).fileName() + " - HMI编辑器"); | ||||
} | |||||
else | |||||
{ | |||||
} else { | |||||
QMessageBox::critical(this, "错误", "无法打开HMI项目文件"); | QMessageBox::critical(this, "错误", "无法打开HMI项目文件"); | ||||
} | } | ||||
} | } | ||||
@@ -134,7 +142,10 @@ void MainWindow::saveProject() | |||||
filePath += ".hmiproj"; | filePath += ".hmiproj"; | ||||
hmiFilePath_ = filePath; | hmiFilePath_ = filePath; | ||||
} | } | ||||
hmi_->extractSceneToProject(hmiProject_); | |||||
// 从当前页面提取项目 | |||||
hmi_->extractSceneToProject(hmiProject_, hmi_->currentPageIndex()); | |||||
if (!hmiProject_.saveToFile(hmiFilePath_)) { | if (!hmiProject_.saveToFile(hmiFilePath_)) { | ||||
QMessageBox::critical(this, "错误", "保存项目失败"); | QMessageBox::critical(this, "错误", "保存项目失败"); | ||||
} | } | ||||
@@ -152,3 +163,15 @@ void MainWindow::disconnection() | |||||
modbusManager->disconnectDevice(); | modbusManager->disconnectDevice(); | ||||
modbusManager->stopSimulation(); | modbusManager->stopSimulation(); | ||||
} | } | ||||
void MainWindow::updateConnectionStatus(bool connection) | |||||
{ | |||||
if (connection) | |||||
{ | |||||
ui->textEdit->append("连接"); | |||||
} | |||||
else | |||||
{ | |||||
ui->textEdit->append("断开"); | |||||
} | |||||
} |
@@ -28,6 +28,7 @@ private slots: | |||||
void saveProject(); | void saveProject(); | ||||
void connection(); | void connection(); | ||||
void disconnection(); | void disconnection(); | ||||
void updateConnectionStatus(bool connection); | |||||
private: | private: | ||||
Ui::MainWindow *ui; | Ui::MainWindow *ui; | ||||
@@ -20,7 +20,17 @@ | |||||
<x>10</x> | <x>10</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>981</width> | <width>981</width> | ||||
<height>561</height> | |||||
<height>511</height> | |||||
</rect> | |||||
</property> | |||||
</widget> | |||||
<widget class="QTextEdit" name="textEdit"> | |||||
<property name="geometry"> | |||||
<rect> | |||||
<x>20</x> | |||||
<y>470</y> | |||||
<width>951</width> | |||||
<height>141</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
</widget> | </widget> | ||||
@@ -237,14 +237,14 @@ void PLC::btnInsertClicked() | |||||
ui->graphicsView->scene()->addItem(c2); | ui->graphicsView->scene()->addItem(c2); | ||||
} | } | ||||
void PLC::updateConnectionStatus(bool connection) | |||||
{ | |||||
if (connection) | |||||
{ | |||||
ui->textEdit->append("连接"); | |||||
} | |||||
else | |||||
{ | |||||
ui->textEdit->append("断开"); | |||||
} | |||||
} | |||||
//void PLC::updateConnectionStatus(bool connection) | |||||
//{ | |||||
// if (connection) | |||||
// { | |||||
// ui->textEdit->append("连接"); | |||||
// } | |||||
// else | |||||
// { | |||||
// ui->textEdit->append("断开"); | |||||
// } | |||||
//} |
@@ -30,7 +30,7 @@ public slots: | |||||
void onListwidgetCurrenttextchanged(const QString ¤tText); | void onListwidgetCurrenttextchanged(const QString ¤tText); | ||||
void btnInsertClicked(); | void btnInsertClicked(); | ||||
void updateConnectionStatus(bool connection); | |||||
// void updateConnectionStatus(bool connection); | |||||
private: | private: | ||||
Ui::PLC *ui; | Ui::PLC *ui; | ||||
@@ -19,7 +19,7 @@ | |||||
<x>10</x> | <x>10</x> | ||||
<y>30</y> | <y>30</y> | ||||
<width>171</width> | <width>171</width> | ||||
<height>401</height> | |||||
<height>431</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
</widget> | </widget> | ||||
@@ -29,7 +29,7 @@ | |||||
<x>200</x> | <x>200</x> | ||||
<y>30</y> | <y>30</y> | ||||
<width>761</width> | <width>761</width> | ||||
<height>401</height> | |||||
<height>431</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<property name="dragMode"> | <property name="dragMode"> | ||||
@@ -49,16 +49,6 @@ | |||||
<string>插入</string> | <string>插入</string> | ||||
</property> | </property> | ||||
</widget> | </widget> | ||||
<widget class="QTextEdit" name="textEdit"> | |||||
<property name="geometry"> | |||||
<rect> | |||||
<x>10</x> | |||||
<y>440</y> | |||||
<width>951</width> | |||||
<height>87</height> | |||||
</rect> | |||||
</property> | |||||
</widget> | |||||
</widget> | </widget> | ||||
<customwidgets> | <customwidgets> | ||||
<customwidget> | <customwidget> | ||||