自定义边界矩形的形状

Posted

技术标签:

【中文标题】自定义边界矩形的形状【英文标题】: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 在这里也行不通。 我想通过将边界矩形最小化为线的形状来实现这一点。

【问题讨论】:

这是一个交叉帖子。 :) 使用QGraphicsItem::shape 我是新手。能否请您提供一些演示代码。 您检查了我链接的文档吗?那里有一个例子。还要检查QPainterPath 的文档。您也许可以使用QPainterPath::addPolygon 创建您的形状。 您无法更改边界框的形状或方向。但是您可以更改用于碰撞和撞击测试的形状(如@thuga 所示)- 您的意思是这样吗? 【参考方案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()。此外,边界框是轴对齐的,因此绘制一个旋转的矩形会导致实际的边界框更大。

以上是关于自定义边界矩形的形状的主要内容,如果未能解决你的问题,请参考以下文章

形状的 UWP/XAML 自定义边框

将自定义形状应用于剪辑属性 CSS

java自定义鼠标形状

具有自定义形状的自定义 ImageView

圆形头像以及一些常见需求形状自定义ImageView组件

自定义卡片形状 Flutter SDK