Qt-Qt利用QPainter实现雷达chart

 

.pro

 1 QT       += core gui
 2 
 3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
 4 
 5 CONFIG += c++11
 6 
 7 # The following define makes your compiler emit warnings if you use
 8 # any Qt feature that has been marked deprecated (the exact warnings
 9 # depend on your compiler). Please consult the documentation of the
10 # deprecated API in order to know how to port your code away from it.
11 DEFINES += QT_DEPRECATED_WARNINGS
12 
13 # You can also make your code fail to compile if it uses deprecated APIs.
14 # In order to do so, uncomment the following line.
15 # You can also select to disable deprecated APIs only up to a certain version of Qt.
16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
17 
18 SOURCES += \
19     main.cpp \
20     mainwindow.cpp \
21     radarChart.cpp
22 
23 HEADERS += \
24     mainwindow.h \
25     radarchart.h
26 
27 FORMS += \
28     mainwindow.ui
29 
30 # Default rules for deployment.
31 qnx: target.path = /tmp/$${TARGET}/bin
32 else: unix:!android: target.path = /opt/$${TARGET}/bin
33 !isEmpty(target.path): INSTALLS += target
View Code

main.cpp

 1 #include "mainwindow.h"
 2 
 3 #include <QApplication>
 4 
 5 int main(int argc, char *argv[])
 6 {
 7     QApplication a(argc, argv);
 8     MainWindow w;
 9     w.show();
10     return a.exec();
11 }
View Code

mainwindow.h

 1 #ifndef MAINWINDOW_H
 2 #define MAINWINDOW_H
 3 
 4 
 5 #include "radarchart.h"
 6 #include <QMainWindow>
 7 
 8 QT_BEGIN_NAMESPACE
 9 namespace Ui { class MainWindow; }
10 QT_END_NAMESPACE
11 
12 class MainWindow : public QMainWindow
13 {
14     Q_OBJECT
15 
16 public:
17     MainWindow(QWidget *parent = nullptr);
18     ~MainWindow();
19 
20 private:
21     Ui::MainWindow *ui;
22     RadarChart *g_radarChart;
23 };
24 #endif // MAINWINDOW_H
View Code

mainwindow.cpp

 1 #include "mainwindow.h"
 2 #include "ui_mainwindow.h"
 3 
 4 
 5 MainWindow::MainWindow(QWidget *parent)
 6     : QMainWindow(parent)
 7     , ui(new Ui::MainWindow)
 8 {
 9     ui->setupUi(this);
10     g_radarChart = new RadarChart;
11     this->setCentralWidget(g_radarChart);
12 
13     g_radarChart->setSides(3);
14 //    g_radarChart->setLevel(3);
15     g_radarChart->setScalePos(0);
16     g_radarChart->setIsShowScale(true);
17     g_radarChart->setIsShowLegend(true);
18     QVector<QString> oStr;
19     oStr << QStringLiteral("攻击") << QStringLiteral("防御") << QStringLiteral("仙术");
20     g_radarChart->setCategories(oStr);
21 
22 
23 
24     g_radarChart->clearDatas();
25 
26     QVector<float> list;
27     list << 10 << 30 << 40;
28     g_radarChart->addData("A",list);
29     g_radarChart->setDataColor("A", QColor(255,0,0,255));
30 
31     QVector<float> list2;
32     list2 << 20 << 40 << 60;
33     g_radarChart->addData("B",list2);
34     g_radarChart->setDataColor("B", QColor(0,255,0,255));
35 
36     QVector<float> list3;
37     list3 << 40 << 40 << 60;
38     g_radarChart->addData("C",list3);
39     g_radarChart->setDataColor("C", QColor(0,0,255,255));
40 //    g_radarChart->show();
41 }
42 
43 MainWindow::~MainWindow()
44 {
45     delete ui;
46 }
View Code

radarchart.h

  1 #ifndef RADARCHART_H
  2 #define RADARCHART_H
  3 
  4 #include <QWidget>
  5 #include <QMap>
  6 #include <QVector>
  7 
  8 #ifdef qct
  9 #if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
 10 #include <QtDesigner/QDesignerExportWidget>
 11 #else
 12 #include <QtUiPlugin/QDesignerExportWidget>
 13 #endif
 14 
 15 class QDESIGNER_WIDGET_EXPORT RadarChart : public QWidget
 16 #else
 17 class RadarChart : public QWidget
 18 #endif
 19 
 20 {
 21     Q_OBJECT
 22 
 23     Q_PROPERTY(int scalePos READ getScalePos WRITE setScalePos)
 24     Q_PROPERTY(double startAngle READ getStartAngle WRITE setStartAngle)
 25     Q_PROPERTY(int sides READ getSides WRITE setSides)
 26     Q_PROPERTY(int level READ getLevel WRITE setLevel)
 27     Q_PROPERTY(bool isShowScale READ getIsShowScale WRITE setIsShowScale)
 28     Q_PROPERTY(bool isShowLegend READ getIsShowLegend WRITE setIsShowLegend)
 29 
 30 public:
 31 
 32     explicit RadarChart(QWidget *parent = 0);
 33     ~RadarChart();
 34 
 35 protected:
 36     void paintEvent(QPaintEvent *);
 37     void drawPolygon(QPainter *painter);
 38     void drawLine(QPainter *painter);
 39     void drawCategories(QPainter *painter);
 40     void drawScaleNum(QPainter *painter);
 41     void drawValues(QPainter *painter);
 42     void drawLegends(QPainter *painter);
 43     void drawLightRing(QPainter *painter);
 44 
 45 private slots:
 46 
 47 private:
 48     double startAngle;    /*开始角度*/
 49     int sides;      /*几条边*/
 50     int level;      /*画几层*/
 51     QVector<QString> categories;     /*各项含义与边数相同*/
 52     QList<QList<float>> valueList;  /*数据*/
 53 
 54     float maxValue;     /*最大值*/
 55     float minValue;     /*最小值*/
 56 
 57     int scalePos;       /*标尺位置*/
 58     bool isShowScale;   /*是否显示标尺*/
 59     bool isShowLegend;   /*是否显示图例*/
 60 
 61     QColor polygonLineColor;    /*多边形边颜色*/
 62     QColor polygonColor;        /*多边形颜色*/
 63     int lineWidth;              /*边宽*/
 64     QColor lineColor;           /*线颜色*/
 65     QColor categoriesColor;     /*小标题颜色*/
 66 
 67     QMap<QString, QVector<float>> dataMap;
 68     QMap<QString, QColor> dataColorMap;
 69 
 70     int randColorValue(int value);
 71 
 72 public:
 73     QSize sizeHint()                        const;
 74     QSize minimumSizeHint()                 const;
 75 
 76     double getStartAngle()                  const;
 77     int getSides()                          const;
 78     int getLevel()                          const;
 79     int getScalePos()                       const;
 80     bool getIsShowScale()                   const;
 81     bool getIsShowLegend()                   const;
 82 
 83     void addData(QString key, QVector<float> list);
 84     void removeData(QString key);
 85     void clearDatas();
 86 
 87     void setDataColor(QString key, QColor);
 88 
 89 public Q_SLOTS:
 90     void setStartAngle(double startAngle);
 91     void setSides(int sides);
 92     void setLevel(int level);
 93     void setScalePos(int scalePos);
 94     void setIsShowScale(bool isShowScale);
 95     void setIsShowLegend(bool isShowLegend);
 96     void setCategories(QVector<QString> categories);
 97 
 98 };
 99 
100 #endif //RADARCHART_H
View Code

radarchart.cpp

  1 #pragma execution_character_set("utf-8")
  2 
  3 #include "radarchart.h"
  4 
  5 #include "qpainter.h"
  6 #include "qmath.h"
  7 #include "qtimer.h"
  8 #include <QDebug>
  9 #include <QTime>
 10 
 11 RadarChart::RadarChart(QWidget *parent) : QWidget(parent)
 12 {
 13     startAngle = 270.0;
 14     sides = 7;
 15     level = 5;
 16     maxValue = 100;
 17     minValue = 0;
 18 
 19     scalePos = 0;
 20     isShowScale = true;
 21     isShowLegend = true;
 22 
 23     for (int i = 0 ; i < sides; i++)
 24     {
 25         categories << QString("null%0").arg(i);
 26     }
 27 
 28 
 29     polygonLineColor = QColor(Qt::lightGray);
 30     //polygonColor;
 31     lineWidth = 0.4;
 32     lineColor = QColor(Qt::lightGray);
 33     categoriesColor =  QColor(Qt::lightGray);
 34 }
 35 
 36 void RadarChart::addData(QString key, QVector<float> list)
 37 {
 38     dataMap[key] = list;
 39     qsrand(QTime(0, 0, 0).msecsTo(QTime::currentTime()));
 40     dataColorMap[key] = QColor(randColorValue(255), randColorValue(255), randColorValue(255));
 41     update();
 42 }
 43 
 44 void RadarChart::removeData(QString key)
 45 {
 46     dataMap.remove(key);
 47     dataColorMap.remove(key);
 48     update();
 49 }
 50 
 51 void RadarChart::clearDatas()
 52 {
 53     dataMap.clear();
 54     dataColorMap.clear();
 55     update();
 56 }
 57 
 58 void RadarChart::setDataColor(QString key, QColor color)
 59 {
 60     qsrand(QTime(0, 0, 0).msecsTo(QTime::currentTime()));
 61     dataColorMap[key] = color;
 62     update();
 63 }
 64 
 65 void RadarChart::setCategories(QVector<QString> categories)
 66 {
 67     this->categories = categories;
 68     update();
 69 }
 70 
 71 int RadarChart::randColorValue(int value)
 72 {
 73     int v = rand() % value;
 74     return v;
 75 }
 76 
 77 RadarChart::~RadarChart()
 78 {
 79 
 80 }
 81 
 82 int RadarChart::getScalePos() const
 83 {
 84     return this->scalePos;
 85 }
 86 
 87 double RadarChart::getStartAngle() const
 88 {
 89     return this->startAngle;
 90 }
 91 
 92 int RadarChart::getSides() const
 93 {
 94     return this->sides;
 95 }
 96 
 97 int RadarChart::getLevel() const
 98 {
 99     return this->level;
100 }
101 
102 bool RadarChart::getIsShowScale() const
103 {
104     return this->isShowScale;
105 }
106 
107 bool RadarChart::getIsShowLegend() const
108 {
109     return this->isShowLegend;
110 }
111 
112 void RadarChart::setStartAngle(double startAngle)
113 {
114     if(startAngle >= 0 && startAngle < 360)
115     {
116         if (this->startAngle != startAngle)
117         {
118             this->startAngle = startAngle;
119             update();
120         }
121     }
122 }
123 
124 void RadarChart::setSides(int sides)
125 {
126     if(sides >= 3)
127     {
128         if (this->sides != sides)
129         {
130             this->sides = sides;
131             if(categories.size() < sides)
132             {
133                 for (int i = sides - categories.size() - 1 ; i < sides; i++)
134                 {
135                     categories << QString("null%0").arg(i);
136                 }
137             }
138             update();
139         }
140     }
141 
142 }
143 
144 void RadarChart::setLevel(int level)
145 {
146     if(level > 0)
147     {
148         if (this->level != level)
149         {
150             this->level = level;
151             update();
152         }
153     }
154 }
155 
156 void RadarChart::setScalePos(int scalePos)
157 {
158     if(scalePos >= 0 && scalePos < sides)
159     {
160         if (this->scalePos != scalePos)
161         {
162             this->scalePos = scalePos;
163             update();
164         }
165     }
166 }
167 
168 void RadarChart::setIsShowScale(bool isShowScale)
169 {
170     if (this->isShowScale != isShowScale)
171     {
172         this->isShowScale = isShowScale;
173         update();
174     }
175 }
176 
177 void RadarChart::setIsShowLegend(bool isShowLegend)
178 {
179     if (this->isShowLegend != isShowLegend)
180     {
181         this->isShowLegend = isShowLegend;
182         update();
183     }
184 }
185 
186 void RadarChart::paintEvent(QPaintEvent *)
187 {
188     int width = this->width();
189     int height = this->height();
190     int side = qMin(width, height);
191 
192     //绘制准备工作,启用反锯齿,平移坐标轴中心,等比例缩放
193     QPainter painter(this);
194     painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
195     painter.translate(width / 2, height / 2);
196     painter.scale(side / 200.0, side / 200.0);
197 
198     //drawLightRing(&painter);
199     drawPolygon(&painter);
200     drawLine(&painter);
201     drawCategories(&painter);
202     if(isShowScale)
203         drawScaleNum(&painter);
204     drawValues(&painter);
205 
206     if(isShowLegend)
207         drawLegends(&painter);
208 }
209 
210 void RadarChart::drawLightRing(QPainter *painter)
211 {
212     int radius = 99;
213     painter->save();
214 
215     QRadialGradient g(QPoint(0, 0), radius);
216 
217     QColor bgColor = QColor(100, 100, 255);
218 
219     bgColor.setAlpha(0);
220     g.setColorAt(0.1, bgColor);
221     bgColor.setAlpha(60);
222     g.setColorAt(1.0, bgColor);
223 
224 
225     painter->setPen(Qt::NoPen);
226     painter->setBrush(g);
227     painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
228 
229     painter->restore();
230 }
231 
232 void RadarChart::drawPolygon(QPainter *painter)
233 {
234     painter->save();
235     QPen pen;
236     pen.setWidthF(lineWidth);
237     pen.setColor(polygonLineColor); //添加线的颜色
238     painter->setPen(pen);
239 
240     double startRad = (360 - startAngle) * (3.14 / 180);
241     double deltaRad = 360 * (3.14 / 180) / sides;
242     double radiusPer = 80.0 / level ;
243 
244     double sina, cosa;
245     int x, y;
246     for(int j = 0 ; j < level ; j++ )
247     {
248         float newR = radiusPer * (j + 1);
249         QPolygonF polygon;
250         for (int i = 0; i < sides; i++)
251         {
252             sina = sin(startRad - i * deltaRad);
253             cosa = cos(startRad - i * deltaRad);
254 
255             x = newR * cosa;
256             y = -newR * sina;
257             QPointF point(x, y);
258             polygon.append(point);
259         }
260         painter->drawPolygon(polygon);
261     }
262     painter->restore();
263 }
264 
265 void RadarChart::drawLine(QPainter *painter)
266 {
267     painter->save();
268     QPen pen;
269     pen.setWidthF(lineWidth);
270     pen.setColor(lineColor); //添加线的颜色
271     painter->setPen(pen);
272 
273     double radius = 80.0 ;
274 
275     double startRad = (360 - startAngle) * (3.14 / 180);
276     double deltaRad = 360 * (3.14 / 180) / sides;
277 
278     double sina, cosa;
279     int x, y;
280 
281     for (int i = 0; i < sides; i++)
282     {
283         sina = sin(startRad - i * deltaRad);
284         cosa = cos(startRad - i * deltaRad);
285 
286         x = radius * cosa;
287         y = -radius * sina;
288         QPointF point(x, y);
289         painter->drawLine(QPointF(0, 0), point);
290     }
291 
292     painter->restore();
293 }
294 
295 void RadarChart::drawCategories(QPainter *painter)
296 {
297     painter->save();
298     QPen pen;
299     pen.setColor(categoriesColor); //添加线的颜色
300     painter->setPen(pen);
301 
302     QFont font("Arial", 5, QFont::Bold, false);
303     //设置字体的类型,大小,加粗,斜体
304     painter->setFont(font);
305     QFontMetrics fm = painter->fontMetrics();
306 
307     double radius = 80.0 ;
308 
309     double startRad = (360 - startAngle) * (3.14 / 180);
310     double deltaRad = 360 * (3.14 / 180) / sides;
311 
312     double sina, cosa;
313     int x, y;
314 
315     for (int i = 0; i < sides; i++)
316     {
317         sina = sin(startRad - i * deltaRad);
318         cosa = cos(startRad - i * deltaRad);
319 
320         x = radius * cosa;
321         y = -radius * sina;
322         QPointF point(x, y);
323 
324         QRectF titleRect;
325         //分8个方向
326         if(x == 0 && y > 0)
327             //正下
328             titleRect = QRectF(point.x() - fm.width(categories.at(i)) / 2, point.y(), fm.width(categories.at(i)), fm.height());
329         else if(x == 0 && y < 0)
330             //正上
331             titleRect = QRectF(point.x() - fm.width(categories.at(i)) / 2, point.y() - fm.height(), fm.width(categories.at(i)), fm.height());
332         else if(x > 0 && y == 0)
333             //正右
334             titleRect = QRectF(point.x(), point.y() - fm.height() / 2, fm.width(categories.at(i)), fm.height());
335         else if(x < 0 && y == 0)
336             //正左
337             titleRect = QRectF(point.x() - fm.width(categories.at(i)), point.y() - fm.height() / 2, fm.width(categories.at(i)), fm.height());
338         else if(x > 0 && y > 0)
339             //右下
340             titleRect = QRectF(point.x(), point.y(), fm.width(categories.at(i)), fm.height());
341         else if(x > 0 && y < 0)
342             //右上
343             titleRect = QRectF(point.x(), point.y() - fm.height(), fm.width(categories.at(i)), fm.height());
344         else if(x < 0 && y < 0)
345             //左上
346             titleRect = QRectF(point.x() - fm.width(categories.at(i)), point.y() - fm.height(), fm.width(categories.at(i)), fm.height());
347         else if(x < 0 && y > 0)
348             //左下
349             titleRect = QRectF(point.x() - fm.width(categories.at(i)), point.y(), fm.width(categories.at(i)), fm.height());
350         else
351             titleRect = QRectF(point.x(), point.y(), fm.width(categories.at(i)), fm.height());
352 
353         painter->drawText(titleRect, Qt::AlignCenter | Qt::AlignTop, categories.at(i));
354     }
355 
356     painter->restore();
357 }
358 
359 void RadarChart::drawScaleNum(QPainter *painter)
360 {
361     painter->save();
362     QPen pen;
363     pen.setColor(categoriesColor); //添加线的颜色
364     painter->setPen(pen);
365 
366     QFont font("Arial", 3, QFont::Bold, false);
367     //设置字体的类型,大小,加粗,斜体
368     painter->setFont(font);
369     QFontMetrics fm = painter->fontMetrics();
370 
371     double startRad = (360 - startAngle) * (3.14 / 180);
372     double deltaRad = 360 * (3.14 / 180) / sides;
373     double radiusPer = 80.0 / level ;
374 
375     double sina, cosa;
376     int x, y;
377     float scaleStep = (maxValue - minValue) / level * 1.0;
378 
379     for(int j = 0 ; j < level + 1 ; j++ )
380     {
381         QPointF point;
382         if(j <= 0)
383         {
384             point = QPointF(0.0, 0.0);
385         }
386         else
387         {
388             float newR = radiusPer * j;
389             sina = sin(startRad - scalePos * deltaRad);
390             cosa = cos(startRad - scalePos * deltaRad);
391 
392             x = newR * cosa;
393             y = -newR * sina;
394             point = QPointF(x, y);
395         }
396 
397         QString scaleNum = QString::number(scaleStep * j + minValue, 'f', 0);
398 
399         QRectF titleRect = QRectF(point.x() - fm.width(scaleNum) - 2, point.y(), fm.width(scaleNum), fm.height());
400 
401         painter->drawText(titleRect, Qt::AlignCenter | Qt::AlignTop, scaleNum);
402     }
403 
404     painter->restore();
405 }
406 
407 void RadarChart::drawValues(QPainter *painter)
408 {
409     painter->save();
410 
411     double startRad = (360 - startAngle) * (3.14 / 180);
412     double deltaRad = 360 * (3.14 / 180) / sides;
413     double radius = 80.0;
414 
415     double sina, cosa;
416     int x, y;
417 
418     QMap<QString, QVector<float>>::const_iterator it = dataMap.constBegin();
419     while (it != dataMap.constEnd())
420     {
421 
422         QVector<float> data = it.value();
423         QPolygonF polygon;
424         QColor dataColor = dataColorMap[it.key()];
425         QPen dataPen;
426 
427         for(int j = 0 ; j < sides; j++)
428         {
429             sina = sin(startRad - j * deltaRad);
430             cosa = cos(startRad - j * deltaRad);
431             double r;
432             //QPen pointPen;
433 
434             float value;
435             if(j >= data.size())
436             {
437                 value = minValue;
438                 r = qAbs( minValue / (maxValue - minValue)) * radius;
439             }
440             else
441             {
442                 value = data.at(j) ;
443                 if(value < minValue)
444                     value = minValue;
445                 else if(value > maxValue)
446                     value = maxValue;
447             }
448             r = qAbs((value - minValue) / (maxValue - minValue))  * radius;
449 
450             x = r * cosa;
451             y = -r * sina;
452             QPointF point(x, y);
453             polygon.append(point);
454 
455             dataPen.setWidthF(1.5);
456             dataColor.setAlpha(150);
457             dataPen.setColor(dataColor); //添加线的颜色
458 
459             painter->setPen(dataPen);
460             painter->drawPoint(point);
461         }
462 
463         QPainterPath painterPath;
464         painterPath.addPolygon(polygon);
465         painterPath.closeSubpath();
466 
467         dataPen.setWidthF(lineWidth);
468         //线条色
469         dataColor.setAlpha(255);
470         dataPen.setColor(dataColor);
471         painter->setPen(dataPen);
472 
473         painter->drawPath(painterPath);
474 
475         //填充色
476         dataColor.setAlpha(100);
477         painter->fillPath( painterPath, dataColor);
478 
479         ++it;
480     }
481 
482     painter->restore();
483 }
484 
485 void RadarChart::drawLegends(QPainter *painter)
486 {
487     painter->save();
488 
489     QPen pen;
490     pen.setColor(categoriesColor); //添加线的颜色
491     painter->setPen(pen);
492 
493     QFont font("Arial", 3, QFont::Bold, false);
494     //设置字体的类型,大小,加粗,斜体
495     painter->setFont(font);
496     QFontMetrics fm = painter->fontMetrics();
497 
498     float sx = 100 - 1;
499     float sy = -100 + 1;
500 
501     int i = 0;
502 
503     int maxW = 0;
504     QMap<QString, QVector<float>>::const_iterator it = dataMap.constBegin();
505     while (it != dataMap.constEnd())
506     {
507         int w = fm.width(it.key());
508         if(w > maxW)
509             maxW = w;
510         ++it;
511     }
512 
513 
514     QMap<QString, QVector<float>>::const_iterator it2 = dataMap.constBegin();
515     while (it2 != dataMap.constEnd())
516     {
517 
518         QRectF legendNameRect = QRectF(sx - maxW, sy + (fm.height() + 1) * i, fm.width(it2.key()), fm.height());
519         QRectF legendColorRect = QRectF(sx - maxW - 1.5 - fm.height(), sy + (fm.height() + 1) * i, fm.height(), fm.height());
520 
521         painter->drawText(legendNameRect, Qt::AlignCenter | Qt::AlignTop, it2.key());
522         //painter->drawRect(legendColorRect);
523         painter->fillRect(legendColorRect, dataColorMap[it2.key()]);
524         i++;
525 
526         ++it2;
527     }
528 
529 
530     painter->restore();
531 }
532 
533 QSize RadarChart::sizeHint() const
534 {
535     return QSize(100, 100);
536 }
537 
538 QSize RadarChart::minimumSizeHint() const
539 {
540     return QSize(50, 50);
541 }
View Code

mainwindow.ui

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <ui version="4.0">
 3  <class>MainWindow</class>
 4  <widget class="QMainWindow" name="MainWindow">
 5   <property name="geometry">
 6    <rect>
 7     <x>0</x>
 8     <y>0</y>
 9     <width>800</width>
10     <height>600</height>
11    </rect>
12   </property>
13   <property name="windowTitle">
14    <string>MainWindow</string>
15   </property>
16   <widget class="QWidget" name="centralwidget"/>
17   <widget class="QMenuBar" name="menubar">
18    <property name="geometry">
19     <rect>
20      <x>0</x>
21      <y>0</y>
22      <width>800</width>
23      <height>22</height>
24     </rect>
25    </property>
26   </widget>
27   <widget class="QStatusBar" name="statusbar"/>
28  </widget>
29  <resources/>
30  <connections/>
31 </ui>
View Code

 

 

 

posted on 2022-08-31 19:25  疯狂delphi  阅读(200)  评论(0编辑  收藏  举报

导航