QGraphicsScene::itemAt和QGraphicsView::itemAt无法返回Item

坐标点确定是没问题的,就是item所在的位置

看源码,基于5.9.7
Src\qtbase\src\widgets\graphicsview\qgraphicsview.cpp

QGraphicsItem *QGraphicsView::itemAt(const QPoint &pos) const
{
    Q_D(const QGraphicsView);
    if (!d->scene)
        return 0;
    const QList<QGraphicsItem *> itemsAtPos = items(pos);
    return itemsAtPos.isEmpty() ? 0 : itemsAtPos.first();
}

QList<QGraphicsItem *> QGraphicsView::items(const QPoint &pos) const
{
    Q_D(const QGraphicsView);
    if (!d->scene)
        return QList<QGraphicsItem *>();
    // ### Unify these two, and use the items(QPointF) version in
    // QGraphicsScene instead. The scene items function could use the viewport
    // transform to map the point to a rect/polygon.
    if ((d->identityMatrix || d->matrix.type() <= QTransform::TxScale)) {
        // Use the rect version
        QTransform xinv = viewportTransform().inverted();
        return d->scene->items(xinv.mapRect(QRectF(pos.x(), pos.y(), 1, 1)),
                               Qt::IntersectsItemShape,
                               Qt::DescendingOrder,
                               viewportTransform());
    }
    // Use the polygon version
    return d->scene->items(mapToScene(pos.x(), pos.y(), 1, 1),
                           Qt::IntersectsItemShape,
                           Qt::DescendingOrder,
                           viewportTransform());
}

Src\qtbase\src\widgets\graphicsview\qgraphicsscene.cpp

QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode,
                                             Qt::SortOrder order, const QTransform &deviceTransform) const
{
    Q_D(const QGraphicsScene);
    return d->index->items(pos, mode, order, deviceTransform);
}

Src\qtbase\src\widgets\graphicsview\qgraphicssceneindex.cpp

QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPointF &pos, Qt::ItemSelectionMode mode,
                                                  Qt::SortOrder order, const QTransform &deviceTransform) const
{

    Q_D(const QGraphicsSceneIndex);
    QList<QGraphicsItem *> itemList;
    d->items_helper(QRectF(pos, QSizeF(1, 1)), &QtPrivate::intersect_point, &itemList, deviceTransform, mode, order, &pos);
    return itemList;
}

QList<QGraphicsItem *> QGraphicsSceneIndex::estimateTopLevelItems(const QRectF &rect, Qt::SortOrder order) const
{
    Q_D(const QGraphicsSceneIndex);
    Q_UNUSED(rect);
    QGraphicsScenePrivate *scened = d->scene->d_func();
    scened->ensureSortedTopLevelItems();
    if (order == Qt::DescendingOrder) {
        QList<QGraphicsItem *> sorted;
        const int numTopLevelItems = scened->topLevelItems.size();
        sorted.reserve(numTopLevelItems);
        for (int i = numTopLevelItems - 1; i >= 0; --i)
            sorted << scened->topLevelItems.at(i);
        return sorted;
    }
    return scened->topLevelItems;
}

void QGraphicsSceneIndexPrivate::recursive_items_helper(QGraphicsItem *item, QRectF exposeRect,
                                                        QGraphicsSceneIndexIntersector intersect,
                                                        QList<QGraphicsItem *> *items,
                                                        const QTransform &viewTransform,
                                                        Qt::ItemSelectionMode mode,
                                                        qreal parentOpacity, const void *intersectData) const
{
...
}

Src\qtbase\src\widgets\graphicsview\qgraphicssceneindex_p.h

class QGraphicsSceneIndexPrivate : public QObjectPrivate
{
    Q_DECLARE_PUBLIC(QGraphicsSceneIndex)
public:
    QGraphicsSceneIndexPrivate(QGraphicsScene *scene);
    ~QGraphicsSceneIndexPrivate();

    void init();
    static bool itemCollidesWithPath(const QGraphicsItem *item, const QPainterPath &path, Qt::ItemSelectionMode mode);

    void recursive_items_helper(QGraphicsItem *item, QRectF exposeRect,
                                QGraphicsSceneIndexIntersector intersect, QList<QGraphicsItem *> *items,
                                const QTransform &viewTransform,
                                Qt::ItemSelectionMode mode, qreal parentOpacity, const void *intersectData) const;
    inline void items_helper(const QRectF &rect, QGraphicsSceneIndexIntersector intersect,
                             QList<QGraphicsItem *> *items, const QTransform &viewTransform,
                             Qt::ItemSelectionMode mode, Qt::SortOrder order, const void *intersectData) const;

    QGraphicsScene *scene;
};

inline void QGraphicsSceneIndexPrivate::items_helper(const QRectF &rect, QGraphicsSceneIndexIntersector intersect,
                                                     QList<QGraphicsItem *> *items, const QTransform &viewTransform,
                                                     Qt::ItemSelectionMode mode, Qt::SortOrder order, const void *intersectData) const
{
    Q_Q(const QGraphicsSceneIndex);
    const QList<QGraphicsItem *> tli = q->estimateTopLevelItems(rect, Qt::AscendingOrder);
    for (int i = 0; i < tli.size(); ++i)
        recursive_items_helper(tli.at(i), rect, intersect, items, viewTransform, mode, 1.0, intersectData);
    if (order == Qt::DescendingOrder) {
        const int n = items->size();
        for (int i = 0; i < n / 2; ++i)
            items->swap(i, n - i - 1);
    }
}

recursive_items_helper里面没有再深入研究了,至此可以知道QGraphicsView和QGraphicsScene的itemAt内部都是QGraphicsScene::items,然后看QGraphicsItem::shape()的说明

Returns the shape of this item as a QPainterPath in local coordinates. The shape is used for many things, including collision detection, hit tests, and for the QGraphicsScene::items() functions.
The outline of a shape can vary depending on the width and style of the pen used when drawing

看QGraphicsItem::boundingRect()的说明

This pure virtual function defines the outer bounds of the item as a rectangle; all painting must be restricted to inside an item’s bounding rect. QGraphicsView uses this to determine whether the item requires redrawing.
Note: For shapes that paint an outline / stroke, it is important to include half the pen width in the bounding rect. It is not necessary to compensate for antialiasing, though.

问题就出在QGraphicsItem::shape(),自己重写的shape里计算结果超出boundingRect了,导致QGraphicsScene::items() 无法正确定位item

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值