Bläddra i källkod

多个元件的复制粘贴

master
鹏鹏 李 1 dag sedan
förälder
incheckning
a48166da94
10 ändrade filer med 216 tillägg och 100 borttagningar
  1. +1
    -3
      button.cpp
  2. +29
    -1
      contact.cpp
  3. +2
    -0
      contact.h
  4. +1
    -1
      editor.pro.user
  5. +0
    -19
      item.cpp
  6. +1
    -1
      light.cpp
  7. +6
    -25
      mainwindow.cpp
  8. +34
    -12
      mainwindow.ui
  9. +114
    -30
      mygraphicsview.cpp
  10. +28
    -8
      mygraphicsview.h

+ 1
- 3
button.cpp Visa fil

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



+ 29
- 1
contact.cpp Visa fil

@@ -1,6 +1,7 @@
#include "contact.h"
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QMenu>

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

+ 2
- 0
contact.h Visa fil

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

+ 1
- 1
editor.pro.user Visa fil

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.11.1, 2025-08-12T22:16:53. -->
<!-- Written by QtCreator 4.11.1, 2025-08-13T11:12:10. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>


+ 0
- 19
item.cpp Visa fil

@@ -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<MyScene*>(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();


+ 1
- 1
light.cpp Visa fil

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


+ 6
- 25
mainwindow.cpp Visa fil

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


+ 34
- 12
mainwindow.ui Visa fil

@@ -19,7 +19,7 @@
<rect>
<x>20</x>
<y>500</y>
<width>951</width>
<width>941</width>
<height>111</height>
</rect>
</property>
@@ -28,18 +28,18 @@
<property name="geometry">
<rect>
<x>20</x>
<y>30</y>
<width>181</width>
<height>461</height>
<y>40</y>
<width>91</width>
<height>451</height>
</rect>
</property>
</widget>
<widget class="QStackedWidget" name="stackedWidget">
<property name="geometry">
<rect>
<x>210</x>
<x>110</x>
<y>10</y>
<width>761</width>
<width>861</width>
<height>481</height>
</rect>
</property>
@@ -47,9 +47,9 @@
<widget class="QTabWidget" name="plc_tab_widget">
<property name="geometry">
<rect>
<x>0</x>
<x>10</x>
<y>0</y>
<width>761</width>
<width>841</width>
<height>481</height>
</rect>
</property>
@@ -62,9 +62,9 @@
<widget class="QTabWidget" name="hmi_tab_widget">
<property name="geometry">
<rect>
<x>0</x>
<x>10</x>
<y>0</y>
<width>761</width>
<width>841</width>
<height>481</height>
</rect>
</property>
@@ -77,8 +77,8 @@
<widget class="QPushButton" name="btn_insert">
<property name="geometry">
<rect>
<x>30</x>
<y>0</y>
<x>20</x>
<y>10</y>
<width>93</width>
<height>28</height>
</rect>
@@ -87,6 +87,28 @@
<string>插入</string>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>2</width>
<height>2</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout"/>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>2</width>
<height>2</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2"/>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">


+ 114
- 30
mygraphicsview.cpp Visa fil

@@ -84,27 +84,49 @@ void MyGraphicsView::keyPressEvent(QKeyEvent *event)
}
}else if (event->matches(QKeySequence::Copy)) {
// Ctrl+C
clipboard_.items.clear();
clipboard_.connections.clear();

QList<QGraphicsItem*> selectedItems = scene()->selectedItems();
for (QGraphicsItem* item : selectedItems) {
if (auto node = dynamic_cast<Item*>(item)) {
clipboard_.input = node->itemType();
break;

// 过滤出Item类型的元件
QList<Item*> items;
for (QGraphicsItem* gi : selectedItems) {
if (auto item = dynamic_cast<Item*>(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<Connection*>(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<QGraphicsItem*> 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<QGraphicsItem *> &items)
{
QPointF center(0, 0);
int count = 0;

for (QGraphicsItem* item : items) {
if (auto node = dynamic_cast<Item*>(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<Item*> 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);
}
}

+ 28
- 8
mygraphicsview.h Visa fil

@@ -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<CopiedItem> items;
QList<CopiedConnection> connections;
QPointF center;
};
static ClipInfo clipboard_;
QPointF calculateItemsCenter(const QList<QGraphicsItem*>& 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

Laddar…
Avbryt
Spara