两个可移动 QGraphicsRectItem

时间:2021-01-09 18:25:42

标签: c++ qt qt5 qgraphicsitem qgraphicspathitem

我正在尝试关注 this example 和 eyllanesc 的回答 Weird behaviour when dragging QGraphicsItem 在两个可拖动/可移动 QGraphicsRectItems

之间绘制一条以箭头结尾的线

这是我的代码:

定制的 QGraphicsPathItem 类(从 QObject 继承也是因为我使用信号):

wireArrow.h


public slots:
    void changePosStart(QPointF newpos);
    void changePosEnd(QPointF newpos);

private:
    component *myStartItem;
    component *myEndItem;
    QPolygonF arrowHead;
    QColor myColor = Qt::black;

WireArrow.cpp

WireArrow::WireArrow(component *startItem, component *endItem,
                                  QGraphicsItem *parent )
            : QGraphicsPathItem(parent), myStartItem(startItem), myEndItem(endItem)

{

    connect(startItem,SIGNAL(componentPosChanged(QPointF)),this, SLOT(changePosStart(QPointF))   );
);
    connect(endItem,SIGNAL(componentPosChanged(QPointF)),this,SLOT(changePosEnd(QPointF)) );;

    this->setPos(myStartItem->pos());
    setFlag(ItemIsSelectable);
    setPen(QPen(myColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

//    QPainterPath path;
//    path.quadTo(100,0,100,100);

    QPainterPath rectPath;
        rectPath.moveTo(0.0, 0.0);
        rectPath.lineTo(myStartItem->pos().x()-myEndItem->pos().x() , myStartItem->pos().y()-myEndItem->pos().y());



        this->setPath(rectPath);
}

void WireArrow::changePosStart(QPointF newpos)
{//@to-do: find how to update pos setpos + this->update maybe? }

void WireArrow::changePosEnd(QPointF newpos)
{//@to-do: find how to update the end pos}

自定义的 qgraphicsitem 类(也继承自 QObject 以在位置更新时发出信号):

component::component(/*some irrelevant params*/QGraphicsItem*parent  ):
QGraphicsRectItem(parent), //...init other params
    {
        setRect(-40, -40, 80, 80);
        setFlag(ItemIsMovable);
        setFlag(ItemIsSelectable);
        setFlag(QGraphicsItem::ItemSendsScenePositionChanges);

    }

QVariant component::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{

    if (change == ItemPositionChange && scene()) {
        qDebug() << "cmp:: event change on scene";
        QPointF newPos = value.toPointF();
        emit componentPosChanged(newPos);
    }
    return QGraphicsItem::itemChange(change, value);

}


main

 // create two components out and in
WireArrow * wa = new WireArrow(out,in);
scene->addItem(wa);

我可以创建矩形(组件)并将它们移动得很好(感谢答案 here ,我的问题是我可以从 out 绘制线条起点但是:

  1. 我无法正确地从一个组件绘制到另一个组件。
  2. 我需要在拖动矩形时让它们自动移动。在其他示例中,我看到他们将线条视为 项目,这是我不能在这里做的事情,因为电线是两个 项目而不是一个,所以我用信号/插槽连接替换了它,但是 我还是不知道如何更新位置...

解释我想要做什么的图片

enter image description here

(方块真的是用qt做的,但线是用油漆做的,方块是可移动的)。

简而言之:只是想在两点(两个方块的位置)之间画一条线,方块是可移动的,所以如果移动了两个方块中的一个,这条线应该适应。

1 个答案:

答案 0 :(得分:1)

所需的内容与我在 this answer 中实现的内容非常相似,因此我将限制从 转换为 的代码:

component.h

#ifndef COMPONENT_H
#define COMPONENT_H

#include <QGraphicsRectItem>

class Arrow;

class Component : public QGraphicsRectItem
{
public:
    Component(QGraphicsItem *parent = nullptr);
    void addArrow(Arrow *arrow);
protected:
    QVariant itemChange(GraphicsItemChange change, const QVariant &value);
private:
    QVector<Arrow *> mArrows;
};

#endif // COMPONENT_H

component.cpp

#include "arrow.h"
#include "component.h"

Component::Component(QGraphicsItem *parent):
    QGraphicsRectItem(parent)
{
    setRect(-40, -40, 80, 80);
    setFlags(QGraphicsItem::ItemIsMovable |
             QGraphicsItem::ItemIsSelectable |
             QGraphicsItem::ItemSendsGeometryChanges);
}

void Component::addArrow(Arrow *arrow)
{
    mArrows << arrow;
}

QVariant Component::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
    if(change == QGraphicsItem::ItemPositionHasChanged){
        for(Arrow * arrow: qAsConst(mArrows)){
            arrow->adjust();
        }
    }
    return QGraphicsRectItem::itemChange(change, value);
}

arrow.h

#ifndef ARROW_H
#define ARROW_H

#include <QGraphicsPathItem>

class Component;

class Arrow : public QGraphicsPathItem
{
public:
    Arrow(Component *startItem, Component *endItem, QGraphicsItem *parent = nullptr);
    void adjust();
private:
    Component *mStartItem;
    Component *mEndItem;
};

#endif // ARROW_H

arrow.cpp

#include "arrow.h"
#include "component.h"

#include <QPen>

Arrow::Arrow(Component *startItem, Component *endItem, QGraphicsItem *parent):
    QGraphicsPathItem(parent), mStartItem(startItem), mEndItem(endItem)
{
    mStartItem->addArrow(this);
    mEndItem->addArrow(this);
    setPen(QPen(QColor("red"), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    adjust();
}

void Arrow::adjust()
{
    prepareGeometryChange();
    QPainterPath path;
    path.moveTo(mStartItem->pos());
    path.lineTo(mEndItem->pos());
    setPath(path);
}
Component *comp1 = new Component;
Component *comp2 = new Component;

comp1->setPos(50, 50);
comp2->setPos(400, 400);

Arrow *arrow = new Arrow(comp1, comp2);
scene->addItem(comp1);
scene->addItem(comp2);
scene->addItem(arrow);