坐标点确定是没问题的,就是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 versionQTransform xinv = viewportTransform().inverted();return d->scene->items(xinv.mapRect(QRectF(pos.x(), pos.y(), 1, 1)),Qt::IntersectsItemShape,Qt::DescendingOrder,viewportTransform());}// Use the polygon versionreturn 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