Selaa lähdekoodia

复制、粘贴已经生成的组件

master
鹏鹏 李 4 päivää sitten
vanhempi
commit
01312d7ef7
10 muutettua tiedostoa jossa 179 lisäystä ja 77 poistoa
  1. +1
    -0
      connection.cpp
  2. +1
    -1
      editor.pro.user
  3. +81
    -25
      item.cpp
  4. +6
    -1
      item.h
  5. +2
    -1
      mainwindow.cpp
  6. +3
    -3
      mainwindow.ui
  7. +75
    -9
      mygraphicsview.cpp
  8. +10
    -0
      mygraphicsview.h
  9. +0
    -6
      mylistwidget.cpp
  10. +0
    -31
      mylistwidget.h

+ 1
- 0
connection.cpp Näytä tiedosto

@@ -9,6 +9,7 @@ Connection::Connection(Item* from, Item::AnchorType fromType,
{
setZValue(-1); // 在图元之下
setPen(QPen(Qt::black, 2));
setFlags(QGraphicsItem::ItemIsSelectable);
from_->addConnection(this);
to_->addConnection(this);
updatePosition();


+ 1
- 1
editor.pro.user Näytä tiedosto

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.11.1, 2025-08-05T20:13:55. -->
<!-- Written by QtCreator 4.11.1, 2025-08-06T13:12:15. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>


+ 81
- 25
item.cpp Näytä tiedosto

@@ -1,16 +1,13 @@
#include "item.h"
#include "connection.h"
#include <QMenu>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QGraphicsSceneContextMenuEvent>

Item::Item(const QString &type, QGraphicsItem *parent)
: QGraphicsObject(parent), type_(type)
{
if (type == "常开") color_ = Qt::blue;
else if (type == "常闭") color_ = Qt::red;
else if (type == "比较指令") color_ = Qt::green;
else color_ = Qt::darkYellow;

setFlags(QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemIsSelectable |
QGraphicsItem::ItemSendsGeometryChanges);
@@ -18,36 +15,76 @@ Item::Item(const QString &type, QGraphicsItem *parent)

QRectF Item::boundingRect() const
{
return QRectF(-5, -5, 90, 50);
return QRectF(-22, -15, 44, 30);
}

void Item::paint(QPainter *painter,
const QStyleOptionGraphicsItem *,
const QStyleOptionGraphicsItem * option,
QWidget *)
{
QRectF r = boundingRect().adjusted(5, 5, -5, -5); // 图元主体
painter->setBrush(color_.lighter(150));
painter->setPen(QPen(color_, 2));
painter->drawRoundedRect(r, 5, 5);
painter->setRenderHint(QPainter::Antialiasing);

if (type_ == "线圈") {
// 绘制线圈样式: 两边线段+中间椭圆
painter->drawLine(-12, 0, -5, 0);
painter->drawEllipse(QRectF(-5, -8, 10, 16));
painter->drawLine(5, 0, 12, 0);

// 画锚点
painter->setBrush(Qt::darkGray);
painter->setPen(Qt::NoPen);
painter->drawEllipse(QPointF(r.left(), r.center().y()), 5, 5); // 左锚点
painter->drawEllipse(QPointF(r.right(), r.center().y()), 5, 5); // 右锚点
// 画锚点
painter->setBrush(Qt::darkGray);
painter->setPen(Qt::NoPen);
painter->drawEllipse(QPointF(-12, 0), 4, 4); // 左锚点
painter->drawEllipse(QPointF(12, 0), 4, 4); // 右锚点
}
else if (type_ == "常开") {
painter->drawLine(-12, 0, -4, 0);
painter->drawLine(-4, -8, -4, 8);
painter->drawLine(4, -8, 4, 8);
painter->drawLine(4, 0, 12, 0);

// 锚点
painter->setBrush(Qt::darkGray);
painter->setPen(Qt::NoPen);
painter->drawEllipse(QPointF(-18, 0), 4, 4); // 左
painter->drawEllipse(QPointF(18, 0), 4, 4); // 右
}
else if (type_ == "常闭") {
painter->drawLine(-15, -10, 15, 10); // 对角线
painter->drawLine(-12, 0, -4, 0);
painter->drawLine(-4, -8, -4, 8);
painter->drawLine(4, -8, 4, 8);
painter->drawLine(4, 0, 12, 0);

painter->setPen(Qt::black);
painter->drawText(r, Qt::AlignCenter, type_);
// 锚点
painter->setBrush(Qt::darkGray);
painter->setPen(Qt::NoPen);
painter->drawEllipse(QPointF(-18, 0), 4, 4); // 左
painter->drawEllipse(QPointF(18, 0), 4, 4); // 右
}
else if (type_ == "比较") {
painter->drawRect(QRectF(-12, -8, 24, 16));
painter->setFont(QFont("Arial", 8));
painter->drawText(QRectF(-10, -8, 20, 16), Qt::AlignCenter, "CP");

// 锚点
painter->setBrush(Qt::darkGray);
painter->setPen(Qt::NoPen);
painter->drawEllipse(QPointF(-18, 0), 4, 4);
painter->drawEllipse(QPointF(18, 0), 4, 4);
}
if (option->state & QStyle::State_Selected) {
QPen pen(Qt::DashLine);
pen.setColor(Qt::blue);
pen.setWidth(2);
painter->setPen(pen);
painter->setBrush(Qt::NoBrush);
painter->drawRect(boundingRect());
}
}

QPointF Item::anchorPos(AnchorType anc) const
QPointF Item::anchorPos(AnchorType type) const
{
QRectF r = boundingRect();
switch (anc) {
case Left: return mapToScene(QPointF(r.left(), r.center().y()));
case Right: return mapToScene(QPointF(r.right(), r.center().y()));
}
return QPointF();
return mapToScene(type == Left ? QPointF(-18, 0) : QPointF(18, 0));
}

void Item::addConnection(Connection* conn)
@@ -66,6 +103,11 @@ QList<Connection *> Item::connections()
return connections_;
}

QString Item::itemType()
{
return type_;
}

QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == QGraphicsItem::ItemPositionChange) {
@@ -74,3 +116,17 @@ QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value)
}
return QGraphicsObject::itemChange(change, 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);
}
}

+ 6
- 1
item.h Näytä tiedosto

@@ -23,15 +23,20 @@ public:
void addConnection(Connection* conn);
void removeConnection(Connection* conn);
QList<Connection*> connections();
QString itemType();

signals:
void requestCopy(Item*);
void requestDelete(Item*);

protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;

private:
QString type_;
QColor color_;
QList<Connection*> connections_;

};

#endif // ITEM_H

+ 2
- 1
mainwindow.cpp Näytä tiedosto

@@ -20,6 +20,7 @@ MainWindow::MainWindow(QWidget *parent)
m_scene = new QGraphicsScene(this);
ui->graphicsView->setScene(m_scene);
ui->graphicsView->setSceneRect(0, 0, 800, 600);
ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);

/* 2. 列表 */
ui->listWidget->setViewMode(QListView::IconMode);
@@ -81,7 +82,7 @@ void MainWindow::createComponents()
const QVector<Comp> comps = {
{"常开", Qt::blue},
{"常闭", Qt::red},
{"比较指令", Qt::green},
{"比较", Qt::green},
{"线圈", Qt::darkYellow}
};



+ 3
- 3
mainwindow.ui Näytä tiedosto

@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1101</width>
<width>1012</width>
<height>656</height>
</rect>
</property>
@@ -29,7 +29,7 @@
<rect>
<x>210</x>
<y>10</y>
<width>871</width>
<width>761</width>
<height>491</height>
</rect>
</property>
@@ -43,7 +43,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1101</width>
<width>1012</width>
<height>26</height>
</rect>
</property>


+ 75
- 9
mygraphicsview.cpp Näytä tiedosto

@@ -3,14 +3,17 @@
#include <QCursor>
#include <QGraphicsScene>
#include <QDebug>
#include <QMenu>

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

MyGraphicsView::MyGraphicsView(QWidget *parent)
: QGraphicsView(parent)
{
setAcceptDrops(true);
viewport()->setAcceptDrops(true);
setRenderHint(QPainter::Antialiasing);
setFocusPolicy(Qt::StrongFocus);
setDragMode(QGraphicsView::RubberBandDrag);
}

void MyGraphicsView::dragEnterEvent(QDragEnterEvent *event)
@@ -41,9 +44,9 @@ void MyGraphicsView::dropEvent(QDropEvent *event)
QPointF scenePos = mapToScene(event->pos());
Item *item = new Item(type);
item->setPos(scenePos);
if (scene())
scene()->addItem(item);
connect(item, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
connect(item, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
scene()->addItem(item);

event->acceptProposedAction();
}
@@ -53,24 +56,69 @@ void MyGraphicsView::keyPressEvent(QKeyEvent *event)
if (event->key() == Qt::Key_Delete && scene()) {
QList<QGraphicsItem*> selectedItems = scene()->selectedItems();
for (QGraphicsItem* item : selectedItems) {
// 如果是Item,顺便删除其连线
if (auto node = dynamic_cast<Item*>(item)) {
if (auto conn = dynamic_cast<Connection*>(item)) {
// 先通知两端节点断开
conn->from_->removeConnection(conn);
conn->to_->removeConnection(conn);
scene()->removeItem(conn);
delete conn;
} else if (auto node = dynamic_cast<Item*>(item)) {
// 删除节点的所有连线
QList<Connection*> conns = node->connections();
for (Connection* conn : conns) {
scene()->removeItem(conn);
conn->from_->removeConnection(conn);
conn->to_->removeConnection(conn);
scene()->removeItem(conn);
delete conn;
}
scene()->removeItem(node);
delete node;
}
scene()->removeItem(item);
delete item;
}
}else if (event->matches(QKeySequence::Copy)) {
// Ctrl+C
QList<QGraphicsItem*> selectedItems = scene()->selectedItems();
for (QGraphicsItem* item : selectedItems) {
if (auto node = dynamic_cast<Item*>(item)) {
clipboard_.input = node->itemType();
break;
}
}
} else if (event->matches(QKeySequence::Paste)) {
// Ctrl+V
if (!clipboard_.input.isEmpty()) {
QPointF center = mapToScene(viewport()->rect().center());
Item* newItem = new Item(clipboard_.input);
newItem->setPos(center);
connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
scene()->addItem(newItem);
}
} else {
QGraphicsView::keyPressEvent(event);
}
}

void MyGraphicsView::contextMenuEvent(QContextMenuEvent *event)
{
QPointF scenePos = mapToScene(event->pos());
QList<QGraphicsItem*> itemsAt = scene()->items(scenePos);
if (itemsAt.isEmpty() && !clipboard_.input.isEmpty()) {
QMenu menu;
QAction* pasteAct = menu.addAction("粘贴");
QAction* sel = menu.exec(event->globalPos());
if (sel == pasteAct) {
Item* newItem = new Item(clipboard_.input);
newItem->setPos(scenePos);
connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
scene()->addItem(newItem);
}
} else {
QGraphicsView::contextMenuEvent(event); // 让Item自己弹出菜单
}
}

// ----------- 连线交互 ------------

Item* MyGraphicsView::anchorItemAt(const QPoint& viewPos, Item::AnchorType& anchorType)
@@ -93,6 +141,24 @@ Item* MyGraphicsView::anchorItemAt(const QPoint& viewPos, Item::AnchorType& anch
return nullptr;
}

void MyGraphicsView::onItemRequestCopy(Item *item)
{
clipboard_.input = item->itemType();
}

void MyGraphicsView::onItemRequestDelete(Item *item)
{
QList<Connection*> conns = item->connections();
for (Connection* conn : conns) {
conn->from_->removeConnection(conn);
conn->to_->removeConnection(conn);
scene()->removeItem(conn);
delete conn;
}
scene()->removeItem(item);
delete item;
}

void MyGraphicsView::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {


+ 10
- 0
mygraphicsview.h Näytä tiedosto

@@ -21,6 +21,7 @@ protected:
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override;

void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
@@ -33,6 +34,15 @@ private:
Item* startItem_ = nullptr;
Item::AnchorType startAnchor_;
QGraphicsLineItem* tempLine_ = nullptr;

struct ClipInfo {
QString input;
};
static ClipInfo clipboard_;

private slots:
void onItemRequestCopy(Item*);
void onItemRequestDelete(Item*);
};

#endif // MYGRAPHICSVIEW_H

+ 0
- 6
mylistwidget.cpp Näytä tiedosto

@@ -1,6 +0,0 @@
#include "mylistwidget.h"

MyListWidget::MyListWidget()
{

}

+ 0
- 31
mylistwidget.h Näytä tiedosto

@@ -1,31 +0,0 @@
#ifndef MYLISTWIDGET_H
#define MYLISTWIDGET_H
#include <QDrag>
#include <QListWidget>
#include <QMimeData>

class MyListWidget : public QListWidget {
public:
using QListWidget::QListWidget;

protected:
void startDrag(Qt::DropActions supportedActions) override
{
QListWidgetItem *item = currentItem();
if (!item) return;

QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;

QString type = item->data(Qt::UserRole).toString();
mimeData->setData("application/x-component", type.toUtf8());
drag->setMimeData(mimeData);

drag->setPixmap(item->icon().pixmap(iconSize()));
drag->setHotSpot(drag->pixmap().rect().center());

drag->exec(Qt::CopyAction);
}
};

#endif // MYLISTWIDGET_H

Ladataan…
Peruuta
Tallenna