C++ 如何使用QPainter或QPainterPath在Qt中使用一个形状或一组连接的形状绘制自定义形状

C++ 如何使用QPainter或QPainterPath在Qt中使用一个形状或一组连接的形状绘制自定义形状,c++,qt,qpainter,C++,Qt,Qpainter,我怎样才能画出像眼泪一样的形状?我需要在不使用多个形状(椭圆和多边形)的情况下进行绘制,因为QPen将为每个形状绘制。我需要连接形状以创建一个新形状,或者告诉QT跨两个形状连接边框,类似于这样: 如果没有好的数学背景,这实际上是很难做到的。如果您知道创建该形状的公式,可以将其放入QGraphicsItem::paint()函数中。但也有一些替代方案: 在矢量编辑程序(如Inkscape(free))中生成图像,将其另存为.svg文件,然后将其加载到一个文件中。(这就是我要做的。) 看一看,它允许

我怎样才能画出像眼泪一样的形状?我需要在不使用多个形状(椭圆和多边形)的情况下进行绘制,因为QPen将为每个形状绘制。我需要连接形状以创建一个新形状,或者告诉QT跨两个形状连接边框,类似于这样:


如果没有好的数学背景,这实际上是很难做到的。如果您知道创建该形状的公式,可以将其放入
QGraphicsItem::paint()
函数中。但也有一些替代方案:

  • 在矢量编辑程序(如Inkscape(free))中生成图像,将其另存为.svg文件,然后将其加载到一个文件中。(这就是我要做的。)

  • 看一看,它允许你做一个贝塞尔曲线


  • 如果您要绘制的形状可以表示为其他形状的分层,就像您链接到的图像一样,这很容易做到:

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

    在您给出的示例中,我们还需要从填充形状的中心移除一个圆形区域。让我们将该内部“边界”表示为
    QPainterPath
    ,然后使用从
    OuterPath
    中减去
    InnerPath
    ,并生成最终形状:

    QPainterPath InnerPath;
    InnerPath.addEllipse(QPointF(60, 60), 20, 20);
    
    QPainterPath FillPath = OuterPath.subtracted(InnerPath);
    
    一旦我们构建了形状路径,我们需要使用它们来填充/勾勒形状。让我们首先创建一个
    qPaint
    ,并将其设置为使用抗锯齿:

    QPainter Painter(this);
    Painter.setRenderHint(QPainter::Antialiasing);
    
    然后,我们需要填充已构建的形状:

    Painter.fillPath(FillPath, Qt::blue);
    
    最后,让我们画出轮廓。请注意,由于内边界和外边界有单独的路径,因此我们可以使用不同的线厚度绘制每个边界。另请注意:这将分层形状集转换为一个无交点的
    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));
    }
    

    当OP引用的形状可以表示为简单形状的分层时,不需要使用复杂的数学来表示它。只需将简单形状分层,并使用
    QPainterPath
    中内置的一些功能来构建复杂形状。查看我的答案了解详细信息。令人惊讶的是,这是我的问题,setFillRule,我也曾想过使用椭圆和矩形,但它们之间会创建一个空白,我还认为使用一条圆弧和两条直线来绘制此图,strokePath和fillPath太过冗长,我也在搜索,此解决方案是最简单和最有用的,谢谢!
    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));
    }