瀏覽代碼

在两个组件之间生成连线

master
鹏鹏 李 4 天之前
父節點
當前提交
71aeff0c68
共有 9 個文件被更改,包括 212 次插入13 次删除
  1. +20
    -0
      connection.cpp
  2. +19
    -0
      connection.h
  3. +2
    -0
      editor.pro
  4. +46
    -3
      item.cpp
  5. +15
    -0
      item.h
  6. +0
    -3
      mainwindow.cpp
  7. +4
    -4
      mainwindow.ui
  8. +91
    -2
      mygraphicsview.cpp
  9. +15
    -1
      mygraphicsview.h

+ 20
- 0
connection.cpp 查看文件

@@ -0,0 +1,20 @@
#include "connection.h"

#include <QPen>

Connection::Connection(Item* from, Item::AnchorType fromType,
Item* to, Item::AnchorType toType, QGraphicsItem* parent)
: QGraphicsLineItem(parent),
from_(from), to_(to), fromType_(fromType), toType_(toType)
{
setZValue(-1); // 在图元之下
setPen(QPen(Qt::black, 2));
from_->addConnection(this);
to_->addConnection(this);
updatePosition();
}

void Connection::updatePosition()
{
setLine(QLineF(from_->anchorPos(fromType_), to_->anchorPos(toType_)));
}

+ 19
- 0
connection.h 查看文件

@@ -0,0 +1,19 @@
#ifndef CONNECTION_H
#define CONNECTION_H

#include <QGraphicsLineItem>
#include "item.h"

class Connection : public QGraphicsLineItem
{
public:
Connection(Item* from, Item::AnchorType fromType,
Item* to, Item::AnchorType toType, QGraphicsItem* parent = nullptr);

void updatePosition();

Item *from_, *to_;
Item::AnchorType fromType_, toType_;
};

#endif // CONNECTION_H

+ 2
- 0
editor.pro 查看文件

@@ -16,12 +16,14 @@ DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
connection.cpp \
item.cpp \
main.cpp \
mainwindow.cpp \
mygraphicsview.cpp

HEADERS += \
connection.h \
item.h \
mainwindow.h \
mygraphicsview.h


+ 46
- 3
item.cpp 查看文件

@@ -1,4 +1,5 @@
#include "item.h"
#include "connection.h"
#include <QPainter>
#include <QStyleOptionGraphicsItem>

@@ -17,17 +18,59 @@ Item::Item(const QString &type, QGraphicsItem *parent)

QRectF Item::boundingRect() const
{
return QRectF(0, 0, 80, 40);
return QRectF(-5, -5, 90, 50);
}

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

// 画锚点
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->setPen(Qt::black);
painter->drawText(boundingRect(), Qt::AlignCenter, type_);
painter->drawText(r, Qt::AlignCenter, type_);
}

QPointF Item::anchorPos(AnchorType anc) 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();
}

void Item::addConnection(Connection* conn)
{
if (!connections_.contains(conn))
connections_.append(conn);
}

void Item::removeConnection(Connection* conn)
{
connections_.removeAll(conn);
}

QList<Connection *> Item::connections()
{
return connections_;
}

QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == QGraphicsItem::ItemPositionChange) {
for (Connection* conn : connections_)
conn->updatePosition();
}
return QGraphicsObject::itemChange(change, value);
}

+ 15
- 0
item.h 查看文件

@@ -2,11 +2,16 @@
#define ITEM_H

#include <QGraphicsObject>
#include <QColor>
#include <QList>

class Connection;

class Item : public QGraphicsObject
{
Q_OBJECT
public:
enum AnchorType { Left, Right };
explicit Item(const QString &type, QGraphicsItem *parent = nullptr);

QRectF boundingRect() const override;
@@ -14,9 +19,19 @@ public:
const QStyleOptionGraphicsItem *option,
QWidget *widget) override;

QPointF anchorPos(AnchorType type) const;
void addConnection(Connection* conn);
void removeConnection(Connection* conn);
QList<Connection*> connections();

protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;

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

};

#endif // ITEM_H

+ 0
- 3
mainwindow.cpp 查看文件

@@ -19,10 +19,7 @@ MainWindow::MainWindow(QWidget *parent)
/* 1. 场景 */
m_scene = new QGraphicsScene(this);
ui->graphicsView->setScene(m_scene);
ui->graphicsView->setRenderHint(QPainter::Antialiasing);
ui->graphicsView->setSceneRect(0, 0, 800, 600);
ui->graphicsView->setAcceptDrops(true);
ui->graphicsView->setFocus();

/* 2. 列表 */
ui->listWidget->setViewMode(QListView::IconMode);


+ 4
- 4
mainwindow.ui 查看文件

@@ -19,8 +19,8 @@
<rect>
<x>20</x>
<y>10</y>
<width>161</width>
<height>381</height>
<width>171</width>
<height>491</height>
</rect>
</property>
</widget>
@@ -29,8 +29,8 @@
<rect>
<x>210</x>
<y>10</y>
<width>791</width>
<height>381</height>
<width>871</width>
<height>491</height>
</rect>
</property>
<property name="dragMode">


+ 91
- 2
mygraphicsview.cpp 查看文件

@@ -10,7 +10,7 @@ MyGraphicsView::MyGraphicsView(QWidget *parent)
setAcceptDrops(true);
viewport()->setAcceptDrops(true);
setRenderHint(QPainter::Antialiasing);
setFocusPolicy(Qt::StrongFocus); // 让view能接收键盘事件
setFocusPolicy(Qt::StrongFocus);
}

void MyGraphicsView::dragEnterEvent(QDragEnterEvent *event)
@@ -51,9 +51,18 @@ void MyGraphicsView::dropEvent(QDropEvent *event)
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)) {
QList<Connection*> conns = node->connections();
for (Connection* conn : conns) {
scene()->removeItem(conn);
conn->from_->removeConnection(conn);
conn->to_->removeConnection(conn);
delete conn;
}
}
scene()->removeItem(item);
delete item;
}
@@ -61,3 +70,83 @@ void MyGraphicsView::keyPressEvent(QKeyEvent *event)
QGraphicsView::keyPressEvent(event);
}
}

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

Item* MyGraphicsView::anchorItemAt(const QPoint& viewPos, Item::AnchorType& anchorType)
{
QPointF scenePos = mapToScene(viewPos);
for (QGraphicsItem* item : scene()->items(scenePos)) {
if (Item* node = dynamic_cast<Item*>(item)) {
QRectF r = node->boundingRect();
QPointF local = node->mapFromScene(scenePos);
if (QLineF(local, QPointF(r.left(), r.center().y())).length() < 10) {
anchorType = Item::Left;
return node;
}
if (QLineF(local, QPointF(r.right(), r.center().y())).length() < 10) {
anchorType = Item::Right;
return node;
}
}
}
return nullptr;
}

void MyGraphicsView::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
Item::AnchorType anchor;
Item* node = anchorItemAt(event->pos(), anchor);
if (node) {
drawingConnection_ = true;
startItem_ = node;
startAnchor_ = anchor;
tempLine_ = scene()->addLine(QLineF(node->anchorPos(anchor), mapToScene(event->pos())),
QPen(Qt::darkGray, 2, Qt::DashLine));
return;
}
}
QGraphicsView::mousePressEvent(event);
}

void MyGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
if (drawingConnection_ && tempLine_) {
QLineF l = tempLine_->line();
l.setP2(mapToScene(event->pos()));
tempLine_->setLine(l);
return;
}
QGraphicsView::mouseMoveEvent(event);
}

void MyGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
if (drawingConnection_ && tempLine_) {
// 检查鼠标释放点是否在某个Item boundingRect内
QPointF scenePos = mapToScene(event->pos());
for (QGraphicsItem* item : scene()->items(scenePos)) {
if (Item* node = dynamic_cast<Item*>(item)) {
QRectF r = node->boundingRect();
QPointF local = node->mapFromScene(scenePos);
// 计算落点距离左右端点
double distLeft = QLineF(local, QPointF(r.left(), r.center().y())).length();
double distRight = QLineF(local, QPointF(r.right(), r.center().y())).length();
Item::AnchorType anchor = (distLeft < distRight) ? Item::Left : Item::Right;
// 生成连线
Connection* conn = new Connection(startItem_, startAnchor_, node, anchor);
scene()->addItem(conn);
break;
}
}
// 清除临时线
scene()->removeItem(tempLine_);
delete tempLine_;
tempLine_ = nullptr;
drawingConnection_ = false;
startItem_ = nullptr;
return;
}
QGraphicsView::mouseReleaseEvent(event);
}

+ 15
- 1
mygraphicsview.h 查看文件

@@ -6,7 +6,9 @@
#include <QDragEnterEvent>
#include <QMimeData>
#include <QKeyEvent>
#include <QMouseEvent>
#include "item.h"
#include "connection.h"

class MyGraphicsView : public QGraphicsView
{
@@ -16,9 +18,21 @@ public:

protected:
void dragEnterEvent(QDragEnterEvent *event) override;
void dropEvent(QDropEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;

void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;

private:
Item* anchorItemAt(const QPoint& viewPos, Item::AnchorType& anchorType);

bool drawingConnection_ = false;
Item* startItem_ = nullptr;
Item::AnchorType startAnchor_;
QGraphicsLineItem* tempLine_ = nullptr;
};

#endif // MYGRAPHICSVIEW_H

Loading…
取消
儲存