diff --git a/button.cpp b/button.cpp index 702cf50..de00f9b 100644 --- a/button.cpp +++ b/button.cpp @@ -26,6 +26,7 @@ void Button::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QW painter->drawPixmap(0, 0, currentSize_.width(), currentSize_.height(), customPixmap_); } else{ + painter->setBrush(Qt::green); painter->drawRect(0, 0, currentSize_.width(), currentSize_.height()); } } @@ -120,9 +121,6 @@ void Button::loadImage() { if(!imagePath_.isEmpty()){ customPixmap_ = QPixmap(imagePath_); -// if (!customPixmap_.isNull()){ -// customPixmap_ = customPixmap_.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation); -// } } } diff --git a/contact.cpp b/contact.cpp index da1472d..8404c40 100644 --- a/contact.cpp +++ b/contact.cpp @@ -1,6 +1,7 @@ #include "contact.h" #include #include +#include Contact::Contact(const QString &type) : Item(type) { @@ -45,7 +46,6 @@ void Contact::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q painter->drawEllipse(QPointF(-18, 0), 4, 4); // 左 painter->drawEllipse(QPointF(18, 0), 4, 4); // 右 } - if (!registerId_.isEmpty()) { painter->save(); painter->setFont(QFont("Arial", 8)); @@ -69,3 +69,31 @@ bool Contact::state() const { return registerValue_ > 0; } + +void Contact::addMenuActions(QMenu *menu) +{ + menu->addAction("置ON"); + menu->addAction("置OFF"); +} + +void Contact::handleMenuAction(QAction *action) +{ + if (action->text() == "复制") { + emit requestCopy(this); + } + if (action->text() == "删除") { + emit requestDelete(this); + } + if (action->text() == "对象"){ + emit requestBindRegister(this); + } + if (action->text() == "重置"){ + emit requestReset(this); + } + if (action->text() == "置ON"){ + emit requestSetON(this, true); + } + if (action->text() == "置OFF"){ + emit requestSetON(this, false); + } +} diff --git a/contact.h b/contact.h index 625f8cb..0d2500a 100644 --- a/contact.h +++ b/contact.h @@ -10,6 +10,8 @@ public: const QStyleOptionGraphicsItem *option, QWidget *) override; bool state() const override; + void addMenuActions(QMenu *menu) override; + void handleMenuAction(QAction *action) override; }; #endif // CONTACT_H diff --git a/editor.pro.user b/editor.pro.user index 457c627..96aecba 100644 --- a/editor.pro.user +++ b/editor.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/item.cpp b/item.cpp index 982fc0e..4a4f65f 100644 --- a/item.cpp +++ b/item.cpp @@ -121,25 +121,6 @@ void Item::handleMenuAction(QAction *action) QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value) { -// if (change == QGraphicsItem::ItemPositionChange) { -// for (Connection* conn : connections_) -// conn->updatePosition(); -// } -// if (change == ItemPositionChange && scene()) { -// // 获取场景(确保是 GridScene) -// if (auto myScene = dynamic_cast(scene())) { -// if (myScene->getSnapToGrid()) { -// // 获取网格大小 -// int gridSize = myScene->getGridSize(); - -// // 对齐到网格 -// QPointF newPos = value.toPointF(); -// qreal xV = qRound(newPos.x() / gridSize) * gridSize; -// qreal yV = qRound(newPos.y() / gridSize) * gridSize; -// return QPointF(xV, yV); -// } -// } -// } // 处理位置即将改变事件(网格对齐) if (change == ItemPositionChange && scene()) { QPointF newPos = value.toPointF(); diff --git a/light.cpp b/light.cpp index 581583f..b79e7c6 100644 --- a/light.cpp +++ b/light.cpp @@ -29,7 +29,7 @@ void Light::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWi if (state()) { painter->setBrush(Qt::green); // 激活状态 } else { - painter->setBrush(Qt::white); // 未激活状态 + painter->setBrush(Qt::red); // 未激活状态 } painter->drawEllipse(0, 0, currentSize_.width(), currentSize_.height()); } diff --git a/mainwindow.cpp b/mainwindow.cpp index 8b6aa4d..f3da4a5 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -102,6 +102,8 @@ void MainWindow::newPage(bool isPlc) registerManager, &RegisterManager::bindItem); connect(newView, &MyGraphicsView::itemResetRegister, registerManager, &RegisterManager::unbindItem); + connect(newView, &MyGraphicsView::itemSetON, + modbusManager, &ModbusManager::writeRegister); } else { // 创建新场景 QGraphicsScene* newScene = new QGraphicsScene(this); @@ -437,18 +439,6 @@ void MainWindow::hmiChange() void MainWindow::newProject() { -// // 检查当前tabwidget是否只有一个页面且页面内容为空 -// if (currentIsPLC_ && plcScenes.size() == 1 && plcScenes[0]->items().isEmpty()) { -// // 复用第一个页面 -// clearScene(); -// setWindowTitle("PLC编辑器"); -// return; -// } -// if (!currentIsPLC_ && hmiScenes.size() == 1 && hmiScenes[0]->items().isEmpty()) { -// clearScene(); -// setWindowTitle("HMI编辑器"); -// return; -// } newPage(currentIsPLC_); // 更新窗口标题 @@ -476,18 +466,9 @@ void MainWindow::openProject() Project project; if (project.loadFromFile(filePath)) { -// // 在当前模块新建一个页面 -// newPage(currentIsPLC_); -// int newPageIndex = currentPageIndex(); - int newPageIndex = -1; - if (currentIsPLC_ && plcScenes.size() == 1 && plcScenes[0]->items().isEmpty()) { - newPageIndex = 0; - } else if (!currentIsPLC_ && hmiScenes.size() == 1 && hmiScenes[0]->items().isEmpty()) { - newPageIndex = 0; - } else { - newPage(currentIsPLC_); - newPageIndex = currentPageIndex(); - } + // 在当前模块新建一个页面 + newPage(currentIsPLC_); + int newPageIndex = currentPageIndex(); // 将项目应用到新页面 applyProjectToScene(project, newPageIndex); @@ -553,7 +534,7 @@ void MainWindow::saveProject() void MainWindow::connection() { modbusManager->connectToDevice("COM1",QSerialPort::BaudRate(9600),QSerialPort::DataBits(8),QSerialPort::EvenParity,QSerialPort::StopBits(1)); - modbusManager->startSimulation(1000); + modbusManager->startSimulation(); } void MainWindow::disconnection() diff --git a/mainwindow.ui b/mainwindow.ui index 54dd7dd..566f57d 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -19,7 +19,7 @@ 20 500 - 951 + 941 111 @@ -28,18 +28,18 @@ 20 - 30 - 181 - 461 + 40 + 91 + 451 - 210 + 110 10 - 761 + 861 481 @@ -47,9 +47,9 @@ - 0 + 10 0 - 761 + 841 481 @@ -62,9 +62,9 @@ - 0 + 10 0 - 761 + 841 481 @@ -77,8 +77,8 @@ - 30 - 0 + 20 + 10 93 28 @@ -87,6 +87,28 @@ 插入 + + + + 0 + 0 + 2 + 2 + + + + + + + + 0 + 0 + 2 + 2 + + + + diff --git a/mygraphicsview.cpp b/mygraphicsview.cpp index 915b7c9..31c5376 100644 --- a/mygraphicsview.cpp +++ b/mygraphicsview.cpp @@ -84,27 +84,49 @@ void MyGraphicsView::keyPressEvent(QKeyEvent *event) } }else if (event->matches(QKeySequence::Copy)) { // Ctrl+C + clipboard_.items.clear(); + clipboard_.connections.clear(); + QList selectedItems = scene()->selectedItems(); - for (QGraphicsItem* item : selectedItems) { - if (auto node = dynamic_cast(item)) { - clipboard_.input = node->itemType(); - break; + + // 过滤出Item类型的元件 + QList items; + for (QGraphicsItem* gi : selectedItems) { + if (auto item = dynamic_cast(gi)) { + items.append(item); + } + } + + // 计算中心点 + clipboard_.center = calculateItemsCenter(selectedItems); + + // 保存元件信息 + for (Item* item : items) { + CopiedItem copiedItem; + copiedItem.type = item->itemType(); + copiedItem.pos = item->pos() - clipboard_.center; + clipboard_.items.append(copiedItem); + } + + // 保存连接关系 + for (QGraphicsItem* gi : selectedItems) { + if (auto conn = dynamic_cast(gi)) { + int fromIdx = items.indexOf(conn->from_); + int toIdx = items.indexOf(conn->to_); + + if (fromIdx >= 0 && toIdx >= 0) { + CopiedConnection copiedConn; + copiedConn.fromIndex = fromIdx; + copiedConn.toIndex = toIdx; + copiedConn.fromType = conn->fromType_; + copiedConn.toType = conn->toType_; + clipboard_.connections.append(copiedConn); + } } } } else if (event->matches(QKeySequence::Paste)) { // Ctrl+V - if (!clipboard_.input.isEmpty()) { - QPointF center = mapToScene(viewport()->rect().center()); - Item* newItem = creatItem(clipboard_.input); - newItem->setPos(center); - connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy); - connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete); - connect(newItem, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister); - connect(newItem, &Item::requestCompare, this, &MyGraphicsView::onItemRequestCompare); - connect(newItem, &Item::requestReset, this, &MyGraphicsView::onItemRequestReset); - connect(newItem, &Item::requestSetON,this, &MyGraphicsView::onItemRequestSetON); - scene()->addItem(newItem); - } + performPaste(mapToScene(viewport()->rect().center())); } else { QGraphicsView::keyPressEvent(event); } @@ -114,23 +136,21 @@ void MyGraphicsView::contextMenuEvent(QContextMenuEvent *event) { QPointF scenePos = mapToScene(event->pos()); QList itemsAt = scene()->items(scenePos); - if (itemsAt.isEmpty() && !clipboard_.input.isEmpty()) { - QMenu menu; + + // 如果有选中的元件,显示元件自己的菜单 + if (!itemsAt.isEmpty()) { + QGraphicsView::contextMenuEvent(event); + return; + } + + // 没有选中元件时,显示粘贴菜单(如果剪贴板有内容) + QMenu menu; + if (!clipboard_.items.isEmpty()) { QAction* pasteAct = menu.addAction("粘贴"); QAction* sel = menu.exec(event->globalPos()); if (sel == pasteAct) { - Item* newItem = creatItem(clipboard_.input); - newItem->setPos(scenePos); - connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy); - connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete); - connect(newItem, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister); - connect(newItem, &Item::requestCompare, this, &MyGraphicsView::onItemRequestCompare); - connect(newItem, &Item::requestReset, this, &MyGraphicsView::onItemRequestReset); - connect(newItem, &Item::requestSetON,this, &MyGraphicsView::onItemRequestSetON); - scene()->addItem(newItem); + performPaste(scenePos); // 在鼠标位置粘贴 } - } else { - QGraphicsView::contextMenuEvent(event); // 让Item自己弹出菜单 } } @@ -156,9 +176,29 @@ Item* MyGraphicsView::anchorItemAt(const QPoint& viewPos, Item::AnchorType& anch return nullptr; } +QPointF MyGraphicsView::calculateItemsCenter(const QList &items) +{ + QPointF center(0, 0); + int count = 0; + + for (QGraphicsItem* item : items) { + if (auto node = dynamic_cast(item)) { + center += node->pos(); + count++; + } + } + + return count > 0 ? center / count : QPointF(0, 0); +} + void MyGraphicsView::onItemRequestCopy(Item *item) { - clipboard_.input = item->itemType(); + clipboard_.items.clear(); + clipboard_.connections.clear(); + + CopiedItem copiedItem; + copiedItem.type = item->itemType(); + clipboard_.items.append(copiedItem); } void MyGraphicsView::onItemRequestDelete(Item *item) @@ -360,3 +400,47 @@ void MyGraphicsView::wheelEvent(QWheelEvent *event) QGraphicsView::wheelEvent(event); } } + +void MyGraphicsView::performPaste(const QPointF &pasteCenter) +{ + if (clipboard_.items.isEmpty()) return; + + QList newItems; + + // 创建新元件 + for (const CopiedItem& copiedItem : clipboard_.items) { + Item* newItem = creatItem(copiedItem.type); + if (!newItem) continue; + + // 设置位置(相对于粘贴中心) + QPointF newPos = pasteCenter + copiedItem.pos; + newItem->setPos(newPos); + + // 连接信号 + connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy); + connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete); + connect(newItem, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister); + connect(newItem, &Item::requestCompare, this, &MyGraphicsView::onItemRequestCompare); + connect(newItem, &Item::requestReset, this, &MyGraphicsView::onItemRequestReset); + connect(newItem, &Item::requestSetON, this, &MyGraphicsView::onItemRequestSetON); + + scene()->addItem(newItem); + newItems.append(newItem); + } + + // 创建新连接 + for (const CopiedConnection& copiedConn : clipboard_.connections) { + if (copiedConn.fromIndex < newItems.size() && copiedConn.toIndex < newItems.size()) { + Connection* conn = new Connection( + newItems[copiedConn.fromIndex], copiedConn.fromType, + newItems[copiedConn.toIndex], copiedConn.toType); + scene()->addItem(conn); + } + } + + // 选中新粘贴的元件 + scene()->clearSelection(); + for (Item* item : newItems) { + item->setSelected(true); + } +} diff --git a/mygraphicsview.h b/mygraphicsview.h index f562c86..9e0820f 100644 --- a/mygraphicsview.h +++ b/mygraphicsview.h @@ -26,12 +26,21 @@ public: void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void wheelEvent(QWheelEvent *event) override; + void performPaste(const QPointF& pasteCenter); signals: void itemBoundToRegister(Item*, QString); void itemResetRegister(Item*, QString); void itemSetON(QString, quint16); +public slots: + void onItemRequestCopy(Item*); + void onItemRequestDelete(Item*); + void onItemRequestBindRegister(Item*); + void onItemRequestCompare(Item*); + void onItemRequestReset(Item*); + void onItemRequestSetON(Item*, bool isON); + private: Item* anchorItemAt(const QPoint& viewPos, Item::AnchorType& anchorType); @@ -40,18 +49,29 @@ private: Item::AnchorType startAnchor_; QGraphicsLineItem* tempLine_ = nullptr; +// struct ClipInfo { +// QString input; +// }; + struct CopiedItem { + QString type; + QPointF pos; + }; + + struct CopiedConnection { + int fromIndex; + int toIndex; + Item::AnchorType fromType; + Item::AnchorType toType; + }; + struct ClipInfo { - QString input; + QList items; + QList connections; + QPointF center; }; static ClipInfo clipboard_; + QPointF calculateItemsCenter(const QList& items); -public slots: - void onItemRequestCopy(Item*); - void onItemRequestDelete(Item*); - void onItemRequestBindRegister(Item*); - void onItemRequestCompare(Item*); - void onItemRequestReset(Item*); - void onItemRequestSetON(Item*, bool isON); }; #endif // MYGRAPHICSVIEW_H