【问题标题】:Customizing shape of bounding rect自定义边界矩形的形状
【发布时间】:2014-10-09 06:21:48
【问题描述】:

我正在使用鼠标点击画一条线。使用paint函数绘制线条为:

painter->drawLine(start_p, end_p);

线的边界矩形定义为:

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

这显示了绘制的线条。我得到了如图所示的边界矩形:

我想根据项目的形状设置边界矩形,例如:

如何做到这一点?

编辑

在选择任何重叠线时,会选择顶部有边界矩形的那条(见下图)。即使使用setZValue 在这里也行不通。 我想通过将边界矩形最小化为线的形状来实现这一点。

【问题讨论】:

  • 这是一个交叉帖子。 :)
  • 我是新手。能否请您提供一些演示代码。
  • 您检查了我链接的文档吗?那里有一个例子。还要检查QPainterPath 的文档。您也许可以使用QPainterPath::addPolygon 创建您的形状。
  • 您无法更改边界框的形状或方向。但是您可以更改用于碰撞和撞击测试的形状(如@thuga 所示)- 您的意思是这样吗?

标签: qt bounding-box qgraphicsitem


【解决方案1】:

如果您的项目不是矩形或旋转矩形,请使用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定义的形状内时才会选择它。

如果您需要制作曲线,可以按照 cmannett85 的建议使用 QPainterPathStroker::createStroke

【讨论】:

    【解决方案2】:

    您应该对 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
    }
    

    现在,您可以使用画家来绘制 shape() 项目,而不是使用 boundingRect(),并且碰撞将按预期工作。

    【讨论】:

      【解决方案3】:

      boundingRect一直用于优化场景的绘制过程。所以这里没有任何操纵的余地。

      但是如果你想改变鼠标交互的区域,有shape method。默认情况下,此方法返回从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;
      }
      

      【讨论】:

        【解决方案4】:

        如果你想要这样的东西,你必须画出自己的边界。让 Qt 将其 QRect 用于边界并定义新的 QRect 依赖于先前 QRect 的角,左上角和右下角。例如,如果左上角是 (2,2) 你的新 QRect 左上角是 (1,2) 而右上角是 (2,1) 和 ....

        【讨论】:

        • “如果你想要这样的东西,你必须画出自己的边界”这根本不是真的。
        • 简化我的观点并说(这根本不是真的)很简单。如果你能回答这个问题。我通过 QGraphicsView 创建了一个具有所有这些功能的整个项目。如果你没有看到这个东西你不能说它不是真的。
        • 我可以回答这个问题,但@thuga 已在 45 分钟前的评论中提供了答案,并且代表是他/她的要求。您的答案是错误的,因为您不需要按顺序绘制边界来设置它们,您可以覆盖QGraphicsItem::boundingRect()。此外,边界框是轴对齐的,因此绘制一个旋转的矩形会导致实际的边界框更大。