在QGraphicsScene中选择项目

Fra*_*sco 7 qt selection qgraphicsitem

我试图了解如何重新定义项目的选择和转换方式(一旦被选中)QGraphicsScene.例如,更改线条的长度,移动线条,通过移动其中一个点来更改多边形.

我创建了一个孩子QGraphicsView并且已经开始重载它mousePressEvent,但似乎选择和移动动作都被捕获了QGraphicsItem.我怎样才能覆盖它,因为它们受到保护而且从孩子身上看不到QGraphicsView

我可以想象我需要QGraphicsItem::mousePressEvent在a中重载myGraphicsItem,但那意味着我还必须重载以QGraphicsScene进行处理myGraphicsItem?如何移动场景中的选定项目位置?

有什么我可以看的例子吗?

我(显然)有点失落.

更新:根据反馈,我创建了一个QGraphicsItems如下的孩子:

class baseGraphicItem : public QGraphicsItem
{
public:
    explicit baseGraphicItem(QVector<QPoint> data, operationType shape, QObject * parent = 0);

signals:

public slots:

public:
    virtual QRectF boundingRect() const;
    virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
    QPainterPath shape() const;
    virtual void hoverEnterEvent ( QGraphicsSceneHoverEvent * event );
    virtual void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event );


private:
    QPolygon vertex;
    operationType shapeType;

};

baseGraphicItem::baseGraphicItem(QVector<QPoint> data, operationType shape, QObject *parent) :
    QGraphicsItem(), vertex(data), shapeType(shape)
{
    qDebug() << vertex;
    this->setAcceptHoverEvents(false);
}
Run Code Online (Sandbox Code Playgroud)

这些是用于油漆boundingRect和形状.

void baseGraphicItem::paint(QPainter * painter, const QStyleOptionGraphicsItem*, QWidget*)
{
    int i=0;

    // Following needs better code for polygons
    do painter->drawLine(vertex.at(i), vertex.at(i+1));
    while (i++<vertex.size()-2);
}

QRectF baseGraphicItem::boundingRect() const
{
    return vertex.boundingRect();
}

QPainterPath baseGraphicItem::shape() const
{
    QPainterPath path;
    path.addPolygon(vertex);
    return path;
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,选择适用于一行或多边形.但是当一条线在多边形内时,它几乎总是选择多边形而不是线.这是因为它boundingRect的形状?另外,我如何获得存储在QPolygon顶点中的新坐标?谢谢

The*_*ght 7

这完全取决于您重新定义"选择和转换项目的方式"的具体含义

我们以QGraphicsLineItem为例.

如果我希望这个项是可移动的,我可以调用它的函数setFlag(QGraphicsItem :: ItemIsMovable).现在可以在场景中单击并移动项目.当然,这假设该项是可选的,这可以通过设置标志QGraphicsItem :: ItemIsSelectable来实现.

现在,如果我想能够改变一条线的点,我可以使用它的setLine函数并继续重新定义线.但是,最好直接从QGraphicsItem继承并创建自己的.

class MyLine : public QGraphicsItem
{
    Q_OBJECT

    public:
        virtual QRectF boundingRect();
        virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
};
Run Code Online (Sandbox Code Playgroud)

所以这是我从QGraphicsItem继承的最低要求,因为boundingRect和paint函数在QGraphicsItem中是纯虚拟的.

那么,现在我们可以在课程中添加起点和终点: -

class MyLine : public QGraphicsItem
{
    Q_OBJECT

    public:
        virtual QRectF boundingRect();
        virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);

    private:
        QPointF m_pointA;
        QPointF m_pointB;
};
Run Code Online (Sandbox Code Playgroud)

接下来,类需要在paint函数中绘制自己:

void MyLine::paint(QPainter * painter, const QStyleOptionGraphicsItem* , QWidget*)
{
    // The painter's pen and brush could be set here first

    // Draw the line
    painter->drawLine(m_pointA, m_pointB);
}
Run Code Online (Sandbox Code Playgroud)

完成此类的最后一件事是boundingRect函数,它表示类的可见区域: -

QRectF MyLine::boundingRect()
{
    return QRectF(m_pointA, m_pointB);
}
Run Code Online (Sandbox Code Playgroud)

虽然这个类在功能上是完整的,你会发现当行是水平时边界矩形非常大,这在选择对象时是个问题,所以我们可以覆盖形状函数来解决这个问题.

QPainterPath MyLine::shape() const
{
    QPainterPath path;
    path.moveTo(m_pointA);
    path.lineTo(m_pointB);
    return path;
}
Run Code Online (Sandbox Code Playgroud)

现在我们有了自己的行类,我们可以添加mouseEvent处理程序: -

class MyLine : public QGraphicsItem
{
    Q_OBJECT

    public:
        virtual QRectF boundingRect();
        QPainterPath shape() const
        virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);


        virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
        virtual void mousePressEvent(QGraphicsSceneMouseEvent * event);
        virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event);

    private:
        QPointF m_pointA;
        QPointF m_pointB;
};
Run Code Online (Sandbox Code Playgroud)

使用事件处理程序,您需要在mouseMoveEvent中单击鼠标时进行存储.鼠标事件最接近的点(m_pointA或m_PointB)是您可以在mouseMoveEvent中移动和更新的点,直到调用mouseReleaseEvent.

如果mousePressEvent中的原始mouseEvent更接近中心,而不是其中一个点,则只需将事件转发给父类,即可移动整行.

当然,您可以将此作为带有点列表的多边形的模板,然后在绘画中绘制,添加到painterPath的形状并在鼠标事件中进行操作.