123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535 |
- #include "VWavechart.h"
- QPainterPath SmoothCurveCreator::createSmoothCurve(const QVector<QPointF>& points)
- {
- QPainterPath path;
- int len = points.size();
- if (len < 2) {
- return path;
- }
- QVector<QPointF> firstControlPoints;
- QVector<QPointF> secondControlPoints;
- calculateControlPoints(points, &firstControlPoints, &secondControlPoints);
- path.moveTo(points[0].x(), points[0].y());
- for (int i = 0; i < len - 1; ++i) {
- path.cubicTo(firstControlPoints[i], secondControlPoints[i], points[i + 1]);
- }
- return path;
- }
- void SmoothCurveCreator::calculateFirstControlPoints(double*& result, const double* rhs, int n)
- {
- result = new double[n];
- double* tmp = new double[n];
- double b = 2.0;
- result[0] = rhs[0] / b;
- for (int i = 1; i < n; i++) {
- tmp[i] = 1 / b;
- b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
- result[i] = (rhs[i] - result[i - 1]) / b;
- }
- for (int i = 1; i < n; i++) {
- result[n - i - 1] -= tmp[n - i] * result[n - i];
- }
- delete tmp;
- }
- void SmoothCurveCreator::calculateControlPoints(const QVector<QPointF>& knots, QVector<QPointF>* firstControlPoints, QVector<QPointF>* secondControlPoints)
- {
- int n = knots.size() - 1;
- for (int i = 0; i < n; ++i) {
- firstControlPoints->append(QPointF());
- secondControlPoints->append(QPointF());
- }
- if (n == 1) {
- (*firstControlPoints)[0].rx() = (2 * knots[0].x() + knots[1].x()) / 3;
- (*firstControlPoints)[0].ry() = (2 * knots[0].y() + knots[1].y()) / 3;
- (*secondControlPoints)[0].rx() = 2 * (*firstControlPoints)[0].x() - knots[0].x();
- (*secondControlPoints)[0].ry() = 2 * (*firstControlPoints)[0].y() - knots[0].y();
- return;
- }
- double* xs = 0;
- double* ys = 0;
- double* rhsx = new double[n];
- double* rhsy = new double[n];
- for (int i = 1; i < n - 1; ++i) {
- rhsx[i] = 4 * knots[i].x() + 2 * knots[i + 1].x();
- rhsy[i] = 4 * knots[i].y() + 2 * knots[i + 1].y();
- }
- rhsx[0] = knots[0].x() + 2 * knots[1].x();
- rhsx[n - 1] = (8 * knots[n - 1].x() + knots[n].x()) / 2.0;
- rhsy[0] = knots[0].y() + 2 * knots[1].y();
- rhsy[n - 1] = (8 * knots[n - 1].y() + knots[n].y()) / 2.0;
- calculateFirstControlPoints(xs, rhsx, n);
- calculateFirstControlPoints(ys, rhsy, n);
- for (int i = 0; i < n; ++i) {
- (*firstControlPoints)[i].rx() = xs[i];
- (*firstControlPoints)[i].ry() = ys[i];
- if (i < n - 1) {
- (*secondControlPoints)[i].rx() = 2 * knots[i + 1].x() - xs[i + 1];
- (*secondControlPoints)[i].ry() = 2 * knots[i + 1].y() - ys[i + 1];
- }
- else {
- (*secondControlPoints)[i].rx() = (knots[n].x() + xs[n - 1]) / 2;
- (*secondControlPoints)[i].ry() = (knots[n].y() + ys[n - 1]) / 2;
- }
- }
- delete xs;
- delete ys;
- delete rhsx;
- delete rhsy;
- }
- VWaveChart::VWaveChart(
- QWidget* parent,
- const QPoint& pos,
- const QSize& size,
- CONTROL_PROPERTY* pProperty
- )
- : QWidget(parent)
- , VControlObject(pProperty)
- {
- minValue = 0;
- maxValue = 100;
- xStep = 10;
- yStep = 10;
- space = 40;
- title = "曲线图";
- smooth = false;
- showHLine = true;
- showPoint = true;
- showPointBg = true;
- bgColorStart = QColor(79, 79, 79);
- bgColorEnd = QColor(51, 51, 51);
- textColor = QColor(250, 250, 250);
- pointColor = QColor(38, 114, 179);
- // 设置尺寸
- if (size == DEFAULT_CONTROL_SIZE)
- {
- this->resize(DEFAULT_WAVE_SIZE);
- }
- else
- {
- this->resize(size);
- }
- // 设置位置
- this->move(pos);
- this->m_pWidget = this;
- m_Type = VALUE_TYPE::Control_Wavechart;
- }
- void VWaveChart::paintEvent(QPaintEvent *)
- {
- //绘制准备工作,启用反锯齿
- QPainter painter(this);
- painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
- //绘制背景
- drawBg(&painter);
- //绘制盒子
- drawBox(&painter);
- //绘制文字
- drawText(&painter);
- //绘制标题
- drawTitle(&painter);
- //绘制数据点
- drawPoint(&painter);
- }
- void VWaveChart::drawBg(QPainter *painter)
- {
- painter->save();
- painter->setPen(Qt::NoPen);
- QLinearGradient topGradient(rect().topLeft(), rect().bottomLeft());
- topGradient.setColorAt(0.0, bgColorStart);
- topGradient.setColorAt(1.0, bgColorEnd);
- painter->setBrush(topGradient);
- painter->drawRect(rect());
- painter->restore();
- }
- void VWaveChart::drawBox(QPainter *painter)
- {
- painter->save();
- QPointF topLeftPot(space, space);
- QPointF bottomRightPot(width() - space / 2, height() - space / 2);
- painter->setPen(textColor);
- painter->setBrush(Qt::NoBrush);
- pointRect = QRectF(topLeftPot, bottomRightPot);
- painter->drawRect(pointRect);
- //绘制横线
- if (showHLine) {
- QPen pen(textColor, 1, Qt::DotLine);
- painter->setPen(pen);
- int step = (maxValue - minValue) / xStep;
- double increment = (double)pointRect.height() / step;
- double startY = pointRect.topLeft().y();
- for (int i = 0; i < step - 1; i++) {
- startY += increment;
- QPointF leftPot(pointRect.topLeft().x(), startY);
- QPointF rightPot(pointRect.topRight().x(), startY);
- painter->drawLine(leftPot, rightPot);
- }
- }
- painter->restore();
- }
- void VWaveChart::drawText(QPainter *painter)
- {
- painter->save();
- painter->setPen(textColor);
- painter->setBrush(Qt::NoBrush);
- int step = (maxValue - minValue) / xStep;
- int value = maxValue;
- double increment = (double)pointRect.height() / step;
- double startY = pointRect.topLeft().y();
- QString strValue;
- for (int i = 0; i <= step; i++) {
- strValue = QString("%1").arg(value);
- double textWidth = fontMetrics().width(strValue);
- double textHeight = fontMetrics().height();
- QPointF textPot(pointRect.topLeft().x() - 5 - textWidth, startY + textHeight / 2);
- painter->drawText(textPot, strValue);
- value -= xStep;
- startY += increment;
- }
- painter->restore();
- }
- void VWaveChart::drawTitle(QPainter *painter)
- {
- painter->save();
- painter->setPen(textColor);
- painter->setBrush(Qt::NoBrush);
- double titleX = (double)width() / 2;
- double titleY = space;
- double textWidth = fontMetrics().width(title);
- double textHeight = fontMetrics().height();
- //标题加粗显示
- QFont titleFont;
- titleFont.setBold(true);
- titleFont.setPixelSize(13);
- painter->setFont(titleFont);
- QPointF textPot(titleX - textWidth / 2, titleY / 2 + textHeight / 2);
- painter->drawText(textPot, title);
- painter->restore();
- }
- void VWaveChart::drawPoint(QPainter *painter)
- {
- painter->save();
- double startX = pointRect.topRight().x();
- QVector<QPointF> points;
- if (showPointBg) {
- points.push_back(QPointF(startX, pointRect.bottomRight().y()));
- }
- for (int i = 0; i < listData.count(); i++) {
- QPointF dataPot(startX, pointRect.bottomRight().y() - (double)listData.at(i) * (pointRect.height() / (maxValue - minValue)));
- points.push_back(dataPot);
- startX -= yStep;
- }
- if (showPointBg) {
- points.push_back(QPointF(startX, pointRect.bottomRight().y()));
- }
- //如果只有两个数据点不需要处理
- if (showPointBg && points.count() <= 2) {
- painter->restore();
- return;
- }
- painter->setPen(pointColor);
- if (showPointBg) {
- painter->setBrush(QColor(pointColor.red(), pointColor.green(), pointColor.blue(), 150));
- if (!smooth) {
- painter->drawPolygon(QPolygonF(points));
- }
- } else {
- painter->setBrush(Qt::NoBrush);
- if (!smooth) {
- painter->drawPolyline(QPolygonF(points));
- }
- }
- //绘制平滑曲线
- if (smooth) {
- QPainterPath path = SmoothCurveCreator::createSmoothCurve(points);
- painter->drawPath(path);
- }
- //绘制坐标点
- if (showPoint) {
- for (int i = 0; i < points.count(); i++) {
- QPointF dataPot = points.at(i);
- painter->setBrush(pointColor);
- painter->drawEllipse(dataPot, 3, 3);
- }
- }
- painter->restore();
- }
- void VWaveChart::updateData()
- {
- int count = pointRect.width() / yStep;
- int i = listData.count() - count;
- if (i > 0) {
- listData.remove(count, i);
- }
- update();
- }
- double VWaveChart::getMinValue() const
- {
- return this->minValue;
- }
- double VWaveChart::getMaxValue() const
- {
- return this->maxValue;
- }
- double VWaveChart::getXStep() const
- {
- return this->xStep;
- }
- double VWaveChart::getYStep() const
- {
- return this->yStep;
- }
- double VWaveChart::getSpace() const
- {
- return this->space;
- }
- QString VWaveChart::getTitle() const
- {
- return this->title;
- }
- bool VWaveChart::getSmooth() const
- {
- return this->smooth;
- }
- bool VWaveChart::getShowHLine() const
- {
- return this->showHLine;
- }
- bool VWaveChart::getShowPoint() const
- {
- return this->showPoint;
- }
- bool VWaveChart::getShowPointBg() const
- {
- return this->showPointBg;
- }
- QColor VWaveChart::getBgColorStart() const
- {
- return this->bgColorStart;
- }
- QColor VWaveChart::getBgColorEnd() const
- {
- return this->bgColorEnd;
- }
- QColor VWaveChart::getTextColor() const
- {
- return this->textColor;
- }
- QColor VWaveChart::getPointColor() const
- {
- return this->pointColor;
- }
- QSize VWaveChart::sizeHint() const
- {
- return QSize(500, 300);
- }
- QSize VWaveChart::minimumSizeHint() const
- {
- return QSize(200, 70);
- }
- void VWaveChart::addData(double data)
- {
- listData.push_front(data);
- updateData();
- }
- void VWaveChart::setData(QVector<double> data)
- {
- listData = data;
- updateData();
- }
- void VWaveChart::clearData()
- {
- listData.clear();
- update();
- }
- void VWaveChart::setMinValue(double minValue)
- {
- if (this->minValue != minValue) {
- this->minValue = minValue;
- update();
- }
- }
- void VWaveChart::setMaxValue(double maxValue)
- {
- if (this->maxValue != maxValue) {
- this->maxValue = maxValue;
- update();
- }
- }
- void VWaveChart::setXStep(double xStep)
- {
- if (this->xStep != xStep) {
- this->xStep = xStep;
- update();
- }
- }
- void VWaveChart::setYStep(double yStep)
- {
- if (this->yStep != yStep) {
- this->yStep = yStep;
- update();
- }
- }
- void VWaveChart::setSpace(double space)
- {
- if (this->space != space) {
- this->space = space;
- update();
- }
- }
- void VWaveChart::setTitle(const QString &title)
- {
- if (this->title != title) {
- this->title = title;
- update();
- }
- }
- void VWaveChart::setSmooth(bool smooth)
- {
- if (this->smooth != smooth) {
- this->smooth = smooth;
- update();
- }
- }
- void VWaveChart::setShowHLine(bool showHLine)
- {
- if (this->showHLine != showHLine) {
- this->showHLine = showHLine;
- update();
- }
- }
- void VWaveChart::setShowPoint(bool showPoint)
- {
- if (this->showPoint != showPoint) {
- this->showPoint = showPoint;
- update();
- }
- }
- void VWaveChart::setShowPointBg(bool showPointBg)
- {
- if (this->showPointBg != showPointBg) {
- this->showPointBg = showPointBg;
- update();
- }
- }
- void VWaveChart::setBgColorStart(const QColor &bgColorStart)
- {
- if (this->bgColorStart != bgColorStart) {
- this->bgColorStart = bgColorStart;
- update();
- }
- }
- void VWaveChart::setBgColorEnd(const QColor &bgColorEnd)
- {
- if (this->bgColorEnd != bgColorEnd) {
- this->bgColorEnd = bgColorEnd;
- update();
- }
- }
- void VWaveChart::setTextColor(const QColor &textColor)
- {
- if (this->textColor != textColor) {
- this->textColor = textColor;
- update();
- }
- }
- void VWaveChart::setPointColor(const QColor &pointColor)
- {
- if (this->pointColor != pointColor) {
- this->pointColor = pointColor;
- update();
- }
- }
|