|
- #include "mainwindow.h"
- #include "ui_mainwindow.h"
- #include "item.h"
-
- #include <QListWidgetItem>
- #include <QMimeData>
- #include <QDrag>
- #include <QPainter>
- #include <QMouseEvent>
- #include <QDropEvent>
- #include <QGraphicsView>
- #include <QMessageBox>
- #include <QAction>
- #include <QFileDialog>
- #include "creatitem.h"
-
- MainWindow::MainWindow(QWidget *parent)
- : QMainWindow(parent)
- , ui(new Ui::MainWindow)
- {
- ui->setupUi(this);
- registerManager = new RegisterManager(this);
- modbusManager = new ModbusManager(registerManager, this);
- // 初始化PLC标签页
- ui->plc_tab_widget->setTabsClosable(true);
- ui->plc_tab_widget->setMovable(true);
-
- // 初始化HMI标签页
- ui->hmi_tab_widget->setTabsClosable(true);
- ui->hmi_tab_widget->setMovable(true);
-
- /* 2. 列表 */
- ui->listWidget->setViewMode(QListView::IconMode);
- ui->listWidget->setIconSize(QSize(60, 30));
- ui->listWidget->setDragEnabled(false);
- ui->listWidget->viewport()->installEventFilter(this);
-
- newPage(true);
- newPage(false);
-
- createComponents();
-
- connect(ui->plc_tab_widget, &QTabWidget::tabCloseRequested,this,&MainWindow::onTabCloseRequested);
- connect(ui->hmi_tab_widget, &QTabWidget::tabCloseRequested,this,&MainWindow::onTabCloseRequested);
- connect(ui->listWidget,&QListWidget::currentTextChanged,this,&MainWindow::onListwidgetCurrenttextchanged);
-
- 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);
- connect(ui->action_connect, &QAction::triggered, this, &MainWindow::connection);
- connect(ui->action_disconnect, &QAction::triggered, this, &MainWindow::disconnection);
- connect(ui->btn_insert, &QPushButton::clicked, this, &MainWindow::btnInsertClicked);
-
- connect(modbusManager, &ModbusManager::connectionStatusChanged,
- this, &MainWindow::updateConnectionStatus);
- // connect(modbusManager, &ModbusManager::connectionStatusChanged,
- // this, &PLC::updateConnectionStatus);
- // connect(modbusManager, &ModbusManager::errorOccurred,
- // this, &PLC::handleModbusError);
- // connect(this, &PLC::requestWriteRegister,
- // modbusManager, &ModbusManager::writeRegister);
-
-
- ui->stackedWidget->setCurrentIndex(0);
- setWindowTitle("未命名项目 - PLC编辑器");
- }
-
- MainWindow::~MainWindow()
- {
- qDeleteAll(plcScenes);
- qDeleteAll(plcViews);
- qDeleteAll(hmiScenes);
- qDeleteAll(hmiViews);
- delete ui;
- }
-
- void MainWindow::newPage(bool isPlc)
- {
- // 创建新场景
- QGraphicsScene* newScene = new QGraphicsScene(this);
-
- // 创建新视图
- MyGraphicsView* newView = new MyGraphicsView(this);
- newView->setScene(newScene);
- newView->setSceneRect(0, 0, 800, 600);
- newView->setDragMode(QGraphicsView::RubberBandDrag);
-
- if (isPlc) {
- // 添加到PLC标签页
- int newIndex = ui->plc_tab_widget->addTab(newView, QString("页面 %1").arg(plcScenes.size() + 1));
- ui->plc_tab_widget->setCurrentIndex(newIndex);
-
- // 保存场景和视图
- plcScenes.append(newScene);
- plcViews.append(newView);
- connect(newView, &MyGraphicsView::itemBoundToRegister,
- registerManager, &RegisterManager::bindItem);
- connect(newView, &MyGraphicsView::itemResetRegister,
- registerManager, &RegisterManager::unbindItem);
- } else {
- // 添加到HMI标签页
- int newIndex = ui->hmi_tab_widget->addTab(newView, QString("页面 %1").arg(hmiScenes.size() + 1));
- ui->hmi_tab_widget->setCurrentIndex(newIndex);
-
- // 保存场景和视图
- hmiScenes.append(newScene);
- hmiViews.append(newView);
- connect(newView, &MyGraphicsView::itemBoundToRegister,
- registerManager, &RegisterManager::bindItem);
- connect(newView, &MyGraphicsView::itemResetRegister,
- registerManager, &RegisterManager::unbindItem);
- connect(newView, &MyGraphicsView::itemSetON,
- modbusManager, &ModbusManager::writeRegister);
- }
- }
-
- void MainWindow::createComponents()
- {
- ui->listWidget->clear();
- if (currentIsPLC_)
- {
- struct Comp { QString name; QColor color; };
- const QVector<Comp> comps = {
- {"常开", Qt::blue},
- {"常闭", Qt::red},
- {"比较", Qt::green},
- {"线圈", Qt::darkYellow}
- };
-
- for (const Comp &c : comps) {
- QListWidgetItem *it = new QListWidgetItem(c.name, ui->listWidget);
-
- QPixmap pix(60, 30);
- pix.fill(Qt::white);
- QPainter p(&pix);
- p.setRenderHint(QPainter::Antialiasing);
- p.setBrush(c.color.lighter(150));
- p.setPen(QPen(c.color, 2));
- p.drawRoundedRect(QRect(5, 5, 50, 20), 3, 3);
- p.setPen(Qt::black);
- p.drawText(QRect(5, 5, 50, 20), Qt::AlignCenter, c.name);
-
- it->setIcon(QIcon(pix));
- it->setData(Qt::UserRole, c.name);
- }
- }
- else
- {
- struct Comp { QString name; QColor color; };
- const QVector<Comp> comps = {
- {"按钮", Qt::blue},
- {"指示灯", Qt::red}
- };
-
- for (const Comp &c : comps) {
- QListWidgetItem *it = new QListWidgetItem(c.name, ui->listWidget);
-
- QPixmap pix(60, 30);
- pix.fill(Qt::white);
- QPainter p(&pix);
- p.setRenderHint(QPainter::Antialiasing);
- p.setBrush(c.color.lighter(150));
- p.setPen(QPen(c.color, 2));
- p.drawRoundedRect(QRect(5, 5, 50, 20), 3, 3);
- p.setPen(Qt::black);
- p.drawText(QRect(5, 5, 50, 20), Qt::AlignCenter, c.name);
-
- it->setIcon(QIcon(pix));
- it->setData(Qt::UserRole, c.name);
- }
- }
- }
-
- void MainWindow::clearScene()
- {
- if(currentIsPLC_)
- {
- if (currentPageIndex() >= 0 && currentPageIndex() < plcScenes.size()) {
- plcScenes[currentPageIndex()]->clear();
- }
- }
- else
- {
- if (currentPageIndex() >= 0 && currentPageIndex() < hmiScenes.size()) {
- hmiScenes[currentPageIndex()]->clear();
- }
- }
- }
-
- void MainWindow::applyProjectToScene(const Project &proj, int pageIndex)
- {
- if (currentIsPLC_)
- {
- if (pageIndex < 0 || pageIndex >= plcScenes.size())
- return;
-
- plcScenes[pageIndex]->clear();
- QVector<Item*> itemObjs;
- for (const auto& d : proj.items_) {
- Item* item = creatItem(d.type);
- if (!item) continue;
- item->setPos(d.x, d.y);
- item->setRegisterId(d.registerId);
- connect(item, &Item::requestCopy, plcViews[pageIndex], &MyGraphicsView::onItemRequestCopy);
- connect(item, &Item::requestDelete, plcViews[pageIndex], &MyGraphicsView::onItemRequestDelete);
- connect(item, &Item::requestBindRegister, plcViews[pageIndex], &MyGraphicsView::onItemRequestBindRegister);
- plcScenes[pageIndex]->addItem(item);
- registerManager->bindItem(item,d.registerId);
- 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));
- plcScenes[pageIndex]->addItem(conn);
- }
- }
- }
- else
- {
- if (pageIndex < 0 || pageIndex >= hmiScenes.size())
- return;
-
- hmiScenes[pageIndex]->clear();
- QVector<Item*> itemObjs;
- for (const auto& d : proj.items_) {
- Item* item = creatItem(d.type);
- if (!item) continue;
- item->setPos(d.x, d.y);
- item->setRegisterId(d.registerId);
- connect(item, &Item::requestCopy, hmiViews[pageIndex], &MyGraphicsView::onItemRequestCopy);
- connect(item, &Item::requestDelete, hmiViews[pageIndex], &MyGraphicsView::onItemRequestDelete);
- connect(item, &Item::requestBindRegister, hmiViews[pageIndex], &MyGraphicsView::onItemRequestBindRegister);
- hmiScenes[pageIndex]->addItem(item);
- registerManager->bindItem(item,d.registerId);
- itemObjs.append(item);
- }
- }
- }
-
- void MainWindow::extractSceneToProject(Project &proj, int pageIndex)
- {
- if (currentIsPLC_)
- {
- if (pageIndex < 0 || pageIndex >= plcScenes.size()) return;
- proj.clear();
- QList<Item*> items;
- for (QGraphicsItem* gi : plcScenes[pageIndex]->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();
- d.registerId = it->registerId();
- proj.items_.append(d);
- }
- for (QGraphicsItem* gi : plcScenes[pageIndex]->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);
- }
- }
- }
- }
- else
- {
- if (pageIndex < 0 || pageIndex >= hmiScenes.size()) return;
- proj.clear();
- QList<Item*> items;
- for (QGraphicsItem* gi : hmiScenes[pageIndex]->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();
- d.registerId = it->registerId();
- proj.items_.append(d);
- }
- }
- }
-
- int MainWindow::currentPageIndex() const
- {
- if (currentIsPLC_) {
- return ui->plc_tab_widget->currentIndex();
- } else {
- return ui->hmi_tab_widget->currentIndex();
- }
- }
-
- bool MainWindow::eventFilter(QObject *obj, QEvent *event)
- {
- if (obj == ui->listWidget->viewport()) {
- static QListWidgetItem *dragItem = nullptr;
- static QPoint startPos;
-
- if (event->type() == QEvent::MouseButtonPress) {
- auto *me = static_cast<QMouseEvent*>(event);
- if (me->button() == Qt::LeftButton) {
- dragItem = ui->listWidget->itemAt(me->pos());
- startPos = me->pos();
- }
- } else if (event->type() == QEvent::MouseMove && dragItem) {
- auto *me = static_cast<QMouseEvent*>(event);
- if ((me->pos() - startPos).manhattanLength()
- >= QApplication::startDragDistance()) {
-
- QString type = dragItem->data(Qt::UserRole).toString();
-
- QMimeData *mime = new QMimeData;
- mime->setData("application/x-component", type.toUtf8());
-
- QDrag *drag = new QDrag(this);
- drag->setMimeData(mime);
- drag->setPixmap(dragItem->icon().pixmap(ui->listWidget->iconSize()));
- drag->setHotSpot(drag->pixmap().rect().center());
- drag->exec(Qt::CopyAction);
-
- dragItem = nullptr;
- }
- } else if (event->type() == QEvent::MouseButtonRelease) {
- dragItem = nullptr;
- }
- }
- return QWidget::eventFilter(obj, event);
- }
-
- void MainWindow::plcChange()
- {
- currentIsPLC_ = true;
- createComponents();
- ui->stackedWidget->setCurrentIndex(0); // 显示PLC页面
- // setWindowTitle((plcFilePath_.isEmpty() ? "未命名项目" : QFileInfo(plcFilePath_).fileName()) + " - PLC编辑器");
- }
-
-
- void MainWindow::hmiChange()
- {
- currentIsPLC_ = false;
- createComponents();
- ui->stackedWidget->setCurrentIndex(1); // 显示HMI页面
- // setWindowTitle((hmiFilePath_.isEmpty() ? "未命名项目" : QFileInfo(hmiFilePath_).fileName()) + " - HMI编辑器");
- }
-
- void MainWindow::newProject()
- {
- newPage(currentIsPLC_);
-
- // 更新窗口标题
- if (currentIsPLC_) {
- setWindowTitle("未命名项目 - PLC编辑器");
- } else {
- setWindowTitle("未命名项目 - HMI编辑器");
- }
- }
-
- void MainWindow::openProject()
- {
- QString filePath;
- QString filter;
-
- if (currentIsPLC_) {
- filter = "PLC项目文件 (*.plcproj)";
- filePath = QFileDialog::getOpenFileName(this, "打开PLC项目", "", filter);
- } else {
- filter = "HMI项目文件 (*.hmiproj)";
- filePath = QFileDialog::getOpenFileName(this, "打开HMI项目", "", filter);
- }
-
- if (filePath.isEmpty()) return;
-
- Project project;
- if (project.loadFromFile(filePath)) {
- // 在当前模块新建一个页面
- newPage(currentIsPLC_);
- int newPageIndex = currentPageIndex();
-
- // 将项目应用到新页面
- applyProjectToScene(project, newPageIndex);
-
- // 更新窗口标题
- setWindowTitle(QFileInfo(filePath).fileName() +
- (currentIsPLC_ ? " - PLC编辑器" : " - HMI编辑器"));
- } else {
- QMessageBox::critical(this, "错误", "无法打开项目文件");
- }
- }
-
- void MainWindow::saveProject()
- {
- QString filePath;
- QString filter;
- QString defaultSuffix;
-
- if (currentIsPLC_) {
- filter = "PLC项目文件 (*.plcproj)";
- defaultSuffix = "plcproj";
- filePath = QFileDialog::getSaveFileName(this, "保存PLC项目", "", filter);
- } else {
- filter = "HMI项目文件 (*.hmiproj)";
- defaultSuffix = "hmiproj";
- filePath = QFileDialog::getSaveFileName(this, "保存HMI项目", "", filter);
- }
-
- if (filePath.isEmpty()) return;
-
- // 确保文件有正确的扩展名
- if (!filePath.endsWith("." + defaultSuffix, Qt::CaseInsensitive)) {
- filePath += "." + defaultSuffix;
- }
-
- Project project;
- // 从当前页面提取项目
- extractSceneToProject(project, currentPageIndex());
-
- if (project.saveToFile(filePath)) {
- // 更新窗口标题
- setWindowTitle(QFileInfo(filePath).fileName() +
- (currentIsPLC_ ? " - PLC编辑器" : " - HMI编辑器"));
- } else {
- QMessageBox::critical(this, "错误", "保存项目失败");
- }
- }
-
- void MainWindow::connection()
- {
- modbusManager->connectToDevice("COM1",QSerialPort::BaudRate(9600),QSerialPort::DataBits(8),QSerialPort::EvenParity,QSerialPort::StopBits(1));
- modbusManager->startSimulation(1000);
- }
-
- void MainWindow::disconnection()
- {
- modbusManager->disconnectDevice();
- modbusManager->stopSimulation();
- }
-
- void MainWindow::updateConnectionStatus(bool connection)
- {
- if (connection)
- {
- ui->textEdit->append("连接");
- }
- else
- {
- ui->textEdit->append("断开");
- }
- }
-
- void MainWindow::onListwidgetCurrenttextchanged(const QString ¤tText)
- {
- selectedComponentType = currentText;
- }
-
- void MainWindow::onTabCloseRequested(int index)
- {
- if (currentIsPLC_) {
- if (plcScenes.size() > 1) {
- delete plcScenes.takeAt(index);
- delete plcViews.takeAt(index);
- ui->plc_tab_widget->removeTab(index);
- } else {
- QMessageBox::information(this, "提示", "至少保留一个PLC页面");
- }
- } else {
- if (hmiScenes.size() > 1) {
- delete hmiScenes.takeAt(index);
- delete hmiViews.takeAt(index);
- ui->hmi_tab_widget->removeTab(index);
- } else {
- QMessageBox::information(this, "提示", "至少保留一个HMI页面");
- }
- }
- }
-
- void MainWindow::btnInsertClicked()
- {
- // 1. 找场景中被选中的连线
- QList<QGraphicsItem*> selectedItems = plcScenes[currentPageIndex()]->selectedItems();
- Connection* selectedConn = nullptr;
- for (QGraphicsItem* item : selectedItems) {
- selectedConn = dynamic_cast<Connection*>(item);
- if (selectedConn) break;
- }
- if (!selectedConn) {
- QMessageBox::warning(this, "提示", "请先选中一条连线");
- return;
- }
- if (selectedComponentType.isEmpty()) {
- QMessageBox::warning(this, "提示", "请先在列表中选择要插入的组件");
- return;
- }
-
- // 2. 计算插入点(中点)
- QLineF lf = selectedConn->line();
- QPointF insertPos = (lf.p1() + lf.p2()) / 2;
-
- // 3. 删除原连线
- Item* from = selectedConn->from_;
- Item* to = selectedConn->to_;
- Item::AnchorType fromType = selectedConn->fromType_;
- Item::AnchorType toType = selectedConn->toType_;
-
- from->removeConnection(selectedConn);
- to->removeConnection(selectedConn);
- plcScenes[currentPageIndex()]->removeItem(selectedConn);
- delete selectedConn;
-
- // 4. 插入新元件
- Item* newItem = creatItem(selectedComponentType);
- newItem->setPos(insertPos);
- connect(newItem, &Item::requestCopy, plcViews[currentPageIndex()], &MyGraphicsView::onItemRequestCopy);
- connect(newItem, &Item::requestDelete, plcViews[currentPageIndex()], &MyGraphicsView::onItemRequestDelete);
- connect(newItem, &Item::requestBindRegister, plcViews[currentPageIndex()], &MyGraphicsView::onItemRequestBindRegister);
- connect(newItem, &Item::requestCompare, plcViews[currentPageIndex()], &MyGraphicsView::onItemRequestCompare);
- connect(newItem, &Item::requestReset, plcViews[currentPageIndex()], &MyGraphicsView::onItemRequestReset);
- plcScenes[currentPageIndex()]->addItem(newItem);
-
- // 5. 新建两条连线
- Connection* c1 = new Connection(from, fromType, newItem, Item::Left);
- plcScenes[currentPageIndex()]->addItem(c1);
- Connection* c2 = new Connection(newItem, Item::Right, to, toType);
- plcScenes[currentPageIndex()]->addItem(c2);
- }
|