最终效果:
一共三个文件
main.cpp
#include <QApplication>
#include "SplineBoard.h"
int main(int argc,char** argv) {QApplication a(argc, argv);SplineBoard b;b.setWindowTitle("标准的贝塞尔曲线");b.show();SplineBoard b2(0.0001);b2.show();b2.setWindowTitle("控制点在曲线上的贝塞尔曲线");b.move(0,0);b2.move(800,0);return a.exec();
}
SplineBoard.h
#ifndef SPLINEBOARD_H
#define SPLINEBOARD_H
#include <QPainter>
#include <QWidget>
class SplineBoard:public QWidget
{Q_OBJECT
public:SplineBoard(double terminalRatio = 0.25);protected:void mouseMoveEvent(QMouseEvent* e);void mousePressEvent(QMouseEvent* e);void mouseReleaseEvent(QMouseEvent* e);void paintEvent(QPaintEvent* e);int mPressedPos;QPointF mStart;QPointF mEnd;QPointF mCont;const double termRatio;
};#endif // SPLINEBOARD_H
SplineBoard.cpp
#include "SplineBoard.h"
#include <QDebug>
#include <QMouseEvent>
#include <QPainterPath>static int radius = 8;
static const int PosEmpty = 0;
static const int PosStart = 1;
static const int PosCont = 2;
static const int PosEnd = 4;static void buildQuadBezier(QPainterPath& pp, const QPointF& p0,const QPointF& p1,const QPointF& p2, qreal term){pp.moveTo(p0);const qreal a = (term-0.5)*-4;const qreal d = (1-2*term)*-4;for (qreal t = 0; t < 1.01; t += 0.01) {qreal A = a*t*t+(-1-a)*t+1;qreal B = d*t*t - d*t;qreal C = a*t*t + (1-a)*t;qreal x = A * p0.x() + B * p1.x() + C * p2.x();qreal y = A * p0.y() + B * p1.y() + C * p2.y();pp.lineTo(x, y);}
}
SplineBoard::SplineBoard(double terminalRatio):mPressedPos(PosEmpty),termRatio(terminalRatio)
{resize(800,600);setWindowTitle("spline board");mStart = QPointF(50,300);mEnd = QPointF(750,300);mCont = QPointF(400,300);
}void SplineBoard::mouseMoveEvent(QMouseEvent* e){auto cur = e->pos();if(mPressedPos == PosStart){mStart = cur;}else if(mPressedPos == PosCont){mCont = cur;}else if(PosEnd == mPressedPos){mEnd = cur;}else{return;}update();
}
void SplineBoard::mousePressEvent(QMouseEvent* e){auto pos = e->pos();auto startRect = QRectF(mStart,QSize(radius*2,radius*2));startRect.translate(-radius,-radius);auto contRect = QRectF(mCont,QSize(radius*2, radius*2));contRect.translate(-radius,-radius);auto endRect = QRectF(mEnd , QSize(radius*2, radius*2));endRect.translate(-radius,-radius);if(startRect.contains(pos)){mPressedPos = PosStart;}else if(contRect.contains(pos)) {mPressedPos = PosCont;}else if(endRect.contains(pos)){mPressedPos = PosEnd;}else{mPressedPos = PosEmpty;}}
void SplineBoard::mouseReleaseEvent(QMouseEvent* e){mPressedPos = PosEmpty;
}void SplineBoard::paintEvent(QPaintEvent* e){QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);QPen pen(Qt::blue);pen.setWidth(2);painter.setPen(pen);QPainterPath path;buildQuadBezier(path,mStart,mCont,mEnd,termRatio);painter.drawPath(path);painter.setPen(Qt::NoPen);painter.setBrush(Qt::magenta);painter.drawEllipse(mStart,radius,radius); // Draw start pointpainter.drawEllipse(mCont, radius,radius); // Draw control pointpainter.drawEllipse(mEnd, radius,radius); // Draw end pointQWidget::paintEvent(e);}