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
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 }
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
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 }
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
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 }
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>
作者:疯狂Delphi
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
欢迎关注我,一起进步!扫描下方二维码即可加我