Qt 自定义控件-维度图/雷达图
一、效果展示
![在这里插入图片描述](https://img-blog.csdnimg.cn/00a2f8ee6383494fa2960766803894fb.png)
二、头文件
#ifndef DIMENSIONCHARTWIDGET_H
#define DIMENSIONCHARTWIDGET_H
#include <QMap>
#include <QPen>
#include <QObject>
#include <QWidget>
class DimensionInfo;
class DimensionChartWidget : public QWidget
{
Q_OBJECT
public:
explicit DimensionChartWidget(QWidget *parent = nullptr);
inline QColor backgroundColor() const { return m_backgroundColor; }
inline void setBackgroundColor(const QColor &backgroundColor) { m_backgroundColor = backgroundColor; }
inline float radius() const { return m_radius; }
inline void setRadius(float radius) { m_radius = radius; }
inline int sidesNumber() const { return m_sidesNumber; }
inline void setSidesNumber(int sidesNumber) {m_sidesNumber = sidesNumber; }
inline QPen sidesPen() const { return m_sidesPen; }
inline void setSidesPen(const QPen &sidesPen) { m_sidesPen = sidesPen; }
inline QVector<DimensionInfo> dimensionInfos() const { return m_dimensionInfos; }
inline void setDimensionInfos(const QVector<DimensionInfo> &dimensionInfos) { m_dimensionInfos = dimensionInfos; }
inline QPen textPen() const { return m_textPen; }
inline void setTextPen(const QPen &textPen) { m_textPen = textPen; }
inline QPen dimensionPen() const { return m_dimensionPen; }
inline void setDimensionPen(const QPen &dimensionPen) { m_dimensionPen = dimensionPen; }
inline QFont textFont() const { return m_textFont; }
inline void setTextFont(const QFont &textFont) { m_textFont = textFont; }
inline int filletRadius() const { return m_filletRadius; }
inline void setFilletRadius(int filletRadius) { m_filletRadius = filletRadius; }
protected:
void paintEvent(QPaintEvent*);
void drawText(QPainter&, QPointF, QString text);
void convertPoint(QPointF&);
private:
QPen m_textPen;
QPen m_sidesPen;
QPen m_dimensionPen;
QFont m_textFont;
QColor m_backgroundColor;
int m_filletRadius;
float m_radius;
int m_sidesNumber;
QVector<DimensionInfo> m_dimensionInfos;
};
class DimensionInfo {
public:
DimensionInfo() = default;
DimensionInfo(QString text, float percentage) { m_text = text; m_percentage = percentage; }
inline QString text() const { return m_text; }
inline void setText(const QString &text) { m_text = text; }
inline float percentage() const { return m_percentage; }
inline void setPercentage(float percentage) { m_percentage = percentage; }
private:
QString m_text;
float m_percentage;
};
#endif
三、源文件
#include "DimensionChartWidget.h"
#include <QPainter>
#include <QtMath>
#include <QDebug>
#include <QPainterPath>
DimensionChartWidget::DimensionChartWidget(QWidget *parent) : QWidget(parent)
{
m_radius = 0;
m_sidesNumber = 1;
}
void DimensionChartWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QColor(m_backgroundColor));
painter.setBrush(QBrush(m_backgroundColor));
painter.drawRoundedRect(rect(), m_filletRadius, m_filletRadius);
painter.translate(width() / 2.0, height() / 2.0);
float degree = 360.0 / m_dimensionInfos.size();
painter.setPen(m_sidesPen);
QPointF lastPoint(0, -m_radius);
QVector<QPointF> points;
for(int i = 0; i < m_dimensionInfos.size(); i++)
{
float radian = qDegreesToRadians(degree * (i + 1));
float x = m_radius * qSin(radian);
float y = m_radius * qCos(radian);
QPainterPath path;
QPointF point(x, -y);
path.lineTo(point);
path.lineTo(lastPoint);
path.lineTo(0, 0);
painter.drawPath(path);
for(int j = m_sidesNumber - 1; j > 0; j--)
{
float multiple = (float)j / m_sidesNumber;
painter.drawLine(point * multiple, lastPoint * multiple);
}
painter.save();
painter.setPen(m_textPen);
painter.setFont(m_textFont);
drawText(painter, point, m_dimensionInfos.at(i).text());
painter.restore();
lastPoint = point;
points << point * m_dimensionInfos.at(i).percentage();
}
painter.setPen(m_dimensionPen);
QColor color = m_dimensionPen.color();
color.setAlpha(150);
painter.setBrush(QBrush(color));
QPolygonF polygon(points);
QPainterPath painterPath;
painterPath.addPolygon(polygon);
painter.drawPolygon(polygon);
}
void DimensionChartWidget::drawText(QPainter& painter, QPointF point, QString text)
{
convertPoint(point);
QRectF textRect;
textRect.setSize(QSize(50, 30));
int flag = Qt::AlignCenter;
if(point.x() > 0)
{
if(point.y() < 0)
{
textRect.setBottomLeft(point);
textRect.setTopRight(QPoint(point.x() + 50, point.y() - 30));
flag = Qt::AlignBottom | Qt::AlignLeft;
}
else if(point.y() > 0)
{
textRect.setTopLeft(point);
textRect.setBottomRight(QPoint(point.x() + 50, point.y() + 30));
flag = Qt::AlignTop | Qt::AlignLeft;
}
else
{
point.setY(point.y() - 15);
textRect.setTopLeft(point);
textRect.setBottomRight(QPoint(point.x() + 50, point.y() + 30));
flag = Qt::AlignVCenter | Qt::AlignLeft;
}
}
else if(point.x() < 0)
{
if(point.y() < 0)
{
textRect.setBottomRight(point);
textRect.setTopLeft(QPoint(point.x() - 50, point.y() - 30));
flag = Qt::AlignBottom | Qt::AlignRight;
}
else if(point.y() > 0)
{
textRect.setTopRight(point);
textRect.setBottomLeft(QPoint(point.x() - 50, point.y() + 30));
flag = Qt::AlignTop | Qt::AlignRight;
}
else
{
point.setY(point.y() - 15);
textRect.setTopRight(point);
textRect.setBottomLeft(QPoint(point.x() - 50, point.y() + 30));
flag = Qt::AlignVCenter | Qt::AlignRight;
}
}
else
{
if(point.y() < 0)
{
point.setX(point.x() - 25);
textRect.setBottomRight(point);
textRect.setTopLeft(QPoint(point.x() + 50, point.y() - 30));
flag = Qt::AlignHCenter | Qt::AlignBottom;
}
else if(point.y() > 0)
{
point.setX(point.x() - 25);
textRect.setTopLeft(point);
textRect.setBottomRight(QPoint(point.x() + 50, point.y() + 30));
flag = Qt::AlignHCenter | Qt::AlignTop;
}
}
painter.drawText(textRect, flag, text);
}
void DimensionChartWidget::convertPoint(QPointF& point)
{
if(qAbs(point.x()) < 0.001)
{
point.setX(0);
}
else if(qAbs(point.y()) < 0.001)
{
point.setY(0);
}
}
四、调用示例
pragma execution_character_set("utf-8")
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include "DimensionChartWidget.h"
#include <QPen>
#include <QPainter>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle("维度图测试");
this->resize(400, 400);
initRadarChart();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setPen(QPen(QColor("#1A1A1A")));
painter.setBrush(QBrush(QColor("#1A1A1A")));
painter.drawRect(rect());
}
void MainWindow::initRadarChart()
{
DimensionChartWidget* pDimensionChartWidget = new DimensionChartWidget(this);
pDimensionChartWidget->resize(this->width() - 60, this->height() -60);
pDimensionChartWidget->move(30, 30);
pDimensionChartWidget->setSidesNumber(5);
pDimensionChartWidget->setRadius(120);
QPen sidesPen;
sidesPen.setColor(QColor("#003545"));
sidesPen.setWidth(2);
pDimensionChartWidget->setSidesPen(sidesPen);
QPen dimensionPen;
dimensionPen.setColor(QColor("#0095C5"));
dimensionPen.setWidth(3);
pDimensionChartWidget->setDimensionPen(dimensionPen);
QPen textPen;
textPen.setColor(Qt::GlobalColor::white);
pDimensionChartWidget->setTextPen(textPen);
QFont textFont;
textFont.setFamily("微软雅黑");
textFont.setPointSize(10);
pDimensionChartWidget->setTextFont(textFont);
QVector<DimensionInfo> dimensionInfos;
DimensionInfo dimensionInfo("维度1", 0.55);
dimensionInfos.append(dimensionInfo);
dimensionInfo.setText("维度2");
dimensionInfo.setPercentage(0.85);
dimensionInfos.append(dimensionInfo);
dimensionInfo.setText("维度3");
dimensionInfo.setPercentage(0.95);
dimensionInfos.append(dimensionInfo);
dimensionInfo.setText("维度4");
dimensionInfo.setPercentage(0.45);
dimensionInfos.append(dimensionInfo);
dimensionInfo.setText("维度5");
dimensionInfo.setPercentage(0.65);
dimensionInfos.append(dimensionInfo);
pDimensionChartWidget->setDimensionInfos(dimensionInfos);
}