如何使用QPainter或QPainterPath绘制自定义形状,包括单个形状或一组连接的形状。

7
我该如何绘制类似于泪滴形状的图形?我需要仅使用一个形状(椭圆和多边形)进行绘制,因为QPen会为每个形状进行绘制。我需要连接这些形状以创建一个新的形状,或者告诉QT沿着两个形状的边框进行连接,类似于这样:

tear

2个回答

21

如果你想要绘制的形状可以表示为其他形状的层叠,就像你提供的图像一样,那么这很容易实现:

首先,我们需要建立一个QPainterPath来表示形状的外边缘。我们通过叠加更简单的形状来构建它;在你的示例中,我们需要一个圆和一个正方形。请注意使用QPainterPath::setFillRule(Qt::WindingFill):这将影响路径绘制的方式(尝试删除它以查看差异!)。

QPainterPath OuterPath;
OuterPath.setFillRule(Qt::WindingFill);
OuterPath.addEllipse(QPointF(60, 60), 50, 50);
OuterPath.addRect(60, 10, 50, 50);

根据您给出的示例,我们还需要从填充的形状中删除一个圆形区域。 让我们将那个内部的“边框”表示为 QPainterPath,然后使用 QPainterPath::subtracted() 函数将InnerPathOuterPath中减去,以生成我们的最终形状:

QPainterPath InnerPath;
InnerPath.addEllipse(QPointF(60, 60), 20, 20);

QPainterPath FillPath = OuterPath.subtracted(InnerPath);

我们建立形状路径后,需要使用它们来填充/描边形状。让我们首先创建一个 QPainter 并将其设置为使用抗锯齿:

QPainter Painter(this);
Painter.setRenderHint(QPainter::Antialiasing);
我们随后需要填充我们已经构建的形状:
Painter.fillPath(FillPath, Qt::blue);

最后,让我们画出轮廓线。请注意,由于内边框和外边框有不同的路径,我们可以使用不同的线宽对每个边框进行描边。还要注意使用QPainterPath::simplified():这将把多层形状集合转换为一个没有交点的QPainterPath

Painter.strokePath(OuterPath.simplified(), QPen(Qt::black, 1));
Painter.strokePath(InnerPath, QPen(Qt::black, 3));
如果将所有这些内容放在一起,它会看起来像这样:

void Shape::paintEvent(QPaintEvent *)
{
  QPainterPath OuterPath;
  OuterPath.setFillRule(Qt::WindingFill);
  OuterPath.addEllipse(QPointF(60, 60), 50, 50);
  OuterPath.addRect(60, 10, 50, 50);

  QPainterPath InnerPath;
  InnerPath.addEllipse(QPointF(60, 60), 20, 20);

  QPainterPath FillPath = OuterPath.subtracted(InnerPath);

  QPainter Painter(this);
  Painter.setRenderHint(QPainter::Antialiasing);

  Painter.fillPath(FillPath, Qt::blue);
  Painter.strokePath(OuterPath.simplified(), QPen(Qt::black, 1));
  Painter.strokePath(InnerPath, QPen(Qt::black, 3));
}

太棒了,这正是我的问题所在——setFillRule。我曾尝试使用椭圆和矩形,但它们之间会产生白色空隙,我还考虑过使用弧线和两条直线来绘制这个图形。strokePath 和 fillPath 也正是我一直在寻找的解决方案,这个方法最简单实用,谢谢! - Diego Fernando Murillo Valenci

3

如果没有良好的数学背景,这实际上是相当困难的。如果您知道创建该形状的公式,只需将其放入您的QGraphicsItem :: paint()函数中即可。但有一些替代方法:

  1. 在向量编辑程序(如Inkscape)中制作图像(免费),将其保存为.svg文件,然后将其加载到QGraphicsSvgItem中。(这就是我会做的事情。)

  2. 查看QPainterPath :: cubicTo(),它允许您制作贝塞尔曲线。


1
当一个形状像OP所引用的那样可以表示为简单形状的分层时,就没有必要使用复杂的数学来表示它。只需将简单的形状分层,并使用内置于“QPainterPath”中的一些功能来构建您复杂的形状。有关详细信息,请参阅我的答案。 - sam-w

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