自定义边界框形状

10

我正在使用鼠标点击绘制一条直线。该直线是使用绘图函数绘制的,如下所示:

painter->drawLine(start_p, end_p);

线段的边界矩形被定义为:

QRectF Line::boundingRect() const
{
  // bounding rectangle for line
  return QRectF(start_p, end_p).normalized();
}

在此输入图片描述

这张图片展示了一个线条。我获取其边界矩形如下图所示:

在此输入图片描述

我想要根据物品的形状获取其边界矩形,类似于以下图片:

在此输入图片描述

如何实现?

编辑

在选择任意重叠的线条时,会选择具有最上面边界矩形的那个(参见下图)。即使使用 setZValue也行不通。我希望通过将边界矩形最小化来实现这一点以适应线条的形状。

在此输入图片描述


1
使用QGraphicsItem::shape - thuga
我是新手。你能提供一些演示代码吗? - Kamalpreet Grewal
你看过我发链接的文档了吗?里面有个例子。还要查看 QPainterPath 的文档。也许你可以用 QPainterPath::addPolygon 来创建你的形状。 - thuga
您不能更改边界框的形状或方向。但是,您可以更改用于碰撞和命中测试的形状(如@thuga所示)-这就是您的意思吗? - cmannett85
供以后参考:边界矩形以外的部分不参与交互。 - Simon Marynissen
显示剩余3条评论
4个回答

10

如果您有一个不像矩形或是旋转的矩形形状,请使用QGraphicsItem::shape

该函数应返回一个QPainterPath。您可以通过使用QPainterPath::addPolygon来创建路径。

这里是一个小例子:

QPainterPath Item::shape() const
{
    QPainterPath path;
    QPolygon polygon;
    polygon << QPoint(0, 0);
    polygon << QPoint(5, 5);
    polygon << QPoint(width, height);
    polygon << QPoint(width - 5, height - 5);
    path.addPolygon(polygon);

    return path;
}

当然,您应该以不同的方式计算路径内的点,但您已经得到了要点。现在,当您单击一个项目时,仅当单击发生在由QPainterPath定义的形状内部时,它才会选择该项目。

如果您需要制作曲线,请使用QPainterPathStroker::createStroke,如cmannett85建议的那样。


3

在QGraphicsItem中有两个相关的函数,你可能会感兴趣。第一个是boundingRect。这是一个矩形,包含整个项。Qt使用它来快速计算项目的可见部分和简单的项目碰撞。

如果你有矩形项,那就太好了;你可以重写从QGraphicsItem或QGraphicsObject继承的任何项中的boundingRect()

如果你有一个不规则的形状,并且想要做一些与项目形状的碰撞等事情,那么shape()函数也需要在你的类中进行重写。

这将返回一个QPainterPath,所以你可以做这样的事情:-

QPainterPath Line::shape()
{
    QRectF rect(start_p, end_p).normalized();

    // increase the rect beyond the width of the line
    rect.adjust(-2, -2, 2, 2); 

    QPainterPath path;
    path.addRect(rect);

    return path;    // return the item's defined shape
}

现在,您可以使用绘图工具来绘制形状()项目,而不是boundingRect(),碰撞将按预期工作。

2

boundingRect 用于优化场景的绘制过程。因此,在这里你没有任何操作的空间。

但是,如果你想改变鼠标交互的区域,可以使用shape方法。默认情况下,该方法返回从boundingRect方法获得的QPainterPath矩形。
因此,只需重写此方法并提供所需的形状即可。

QPainterPath YourGraphicsItem::shape() const {
     static const qreal kClickTolerance = 10;

     QPointF vec = end_p-start_p;
     vec = vec*(kClickTolerance/qSqrt(QPointF::dotProduct(vec, vec)));
     QPointF orthogonal(vec.y(), -vec.x());

     QPainterPath result(start_p-vec+orthogonal);
     result.lineTo(start_p-vec-orthogonal);
     result.lineTo(end_p+vec-orthogonal);
     result.lineTo(end_p+vec+orthogonal);
     result.closeSubpath();

     return result;
}

-1

如果你想要类似这样的东西,你必须自己绘制边界。让Qt使用它的QRect来定义边界,并根据前一个QRect的角落定义你的新QRect,例如,如果左上角是(2,2),那么你的新QRect的左上角就是(1,2),右上角是(2,1)等等。


如果你想要类似的东西,你必须自己绘制边界。这完全不是真的。 - cmannett85
很简单就把我的观点缩小为“这根本不是真的”。如果您能够回答这个问题,请回答。我使用QGraphicsView创建了一个具有所有这些功能的完整项目。如果您没有看到这件事,就不能说它不是真的。 - QCoder
我可以回答这个问题,但是@thuga在45分钟前的评论中已经提供了答案,声望应该归他/她所有。你的答案是错误的,因为你不需要绘制边界来设置它们,你可以重写QGraphicsItem::boundingRect()。此外,边界框是轴对齐的,所以绘制旋转矩形会导致实际边界框变得更大。 - cmannett85

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接