接下来实现平滑曲线的效果。

1. 绘制原理

绘制平滑曲线用到QPainterPath::cubicTo()函数,该函数用来在当前点和结束点之间绘制贝瑟尔曲线,函数原型如下:

void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint);
void QPainterPath::cubicTo(qreal c1X, qreal c1Y, qreal c2X, qreal c2Y, qreal endPointX, qreal endPointY);

只要计算出c1c2两个控制点的坐标,就可以在sp起始点和ep结束点之间绘制一条平滑曲线,计算方法如下:
image-20260813212749771

以上,我是通过在亿图图示绘图工具里使用贝塞尔曲线工具,绘制的一条平滑曲线。
关于贝瑟尔曲线的动态演示,可以查看这里:http://yisibl.github.io/cubic-bezier

2. 代码实现

首先,在widget.cpp中实现一个createSmoothPath()函数,如下:

QPainterPath createSmoothPath(const QVector<QPoint> &points)
{
    int count = points.count();
    if (count == 0) {
        return QPainterPath();
    }

    QPainterPath path;
    path.moveTo(points.at(0));
    for (int i = 0; i < count - 1; ++i) {
        // 控制点的 x 坐标为 sp 与 ep 的 x 坐标和的一半
        // 第一个控制点 c1 的 y 坐标为起始点 sp 的 y 坐标
        // 第二个控制点 c2 的 y 坐标为结束点 ep 的 y 坐标
        QPoint sp = points.at(i);
        QPoint ep = points.at(i + 1);
        QPoint c1 = QPoint((sp.x() + ep.x()) / 2, sp.y());
        QPoint c2 = QPoint((sp.x() + ep.x()) / 2, ep.y());
        path.cubicTo(c1, c2, ep);
    }

    return path;
}

然后,修改函数,如下:

void Widget::drawTempLine(bool high)
{
    // ...

    QVector<QPoint> points;
    for (int i = 0; i < 7; i++) {
        points.append(QPoint(pointX[i], pointY[i]));
    }
    
    // 3. 开始绘制
    // ...
    
    // 3.3 绘制曲线
#if 0
    // 折线
    for (int i = 0; i < 6; i++) {
        pen.setStyle(i == 0 ? Qt::DotLine : Qt::SolidLine);  // 虚线
        painter.setPen(pen);
        painter.drawLine(pointX[i], pointY[i], pointX[i + 1], pointY[i + 1]);
    }
#else
    // 平滑曲线
    QBrush brush = painter.brush();
    brush.setStyle(Qt::NoBrush);
    painter.setBrush(brush);
    QPainterPath path = createSmoothPath(points);
    painter.drawPath(path);
#endif
}