QT之“蛛网图”自绘控件
程序员文章站
2022-03-11 10:17:10
...
在很多软件中我们会看到用雷达图的“蛛网图”来表示各类属性评分值,虽然我可以通过调用ECharts来实现这种效果,但是没有发现用QT来实现的控件,所以自己在闲下来的时候写了一个简单的图表,实现效果图如下:
核心代码如下:
1.绘制正多边形
void RadarChart::drawPolygon(QPainter *painter)
{
painter->save();
QPen pen;
pen.setWidthF(lineWidth);
pen.setColor(polygonLineColor); //添加线的颜色
painter->setPen(pen);
double startRad = (360 - startAngle) * (3.14 / 180);
double deltaRad = 360 * (3.14 / 180) / sides;
double radiusPer = 80.0 / level ;
double sina, cosa;
int x, y;
for(int j = 0 ; j < level ; j++ )
{
float newR = radiusPer * (j + 1);
QPolygonF polygon;
for (int i = 0; i < sides; i++)
{
sina = sin(startRad - i * deltaRad);
cosa = cos(startRad - i * deltaRad);
x = newR * cosa;
y = -newR * sina;
QPointF point(x, y);
polygon.append(point);
}
painter->drawPolygon(polygon);
}
painter->restore();
}
2.绘制刻度线
void RadarChart::drawLine(QPainter *painter)
{
painter->save();
QPen pen;
pen.setWidthF(lineWidth);
pen.setColor(lineColor); //添加线的颜色
painter->setPen(pen);
double radius = 80.0 ;
double startRad = (360 - startAngle) * (3.14 / 180);
double deltaRad = 360 * (3.14 / 180) / sides;
double sina, cosa;
int x, y;
for (int i = 0; i < sides; i++)
{
sina = sin(startRad - i * deltaRad);
cosa = cos(startRad - i * deltaRad);
x = radius * cosa;
y = -radius * sina;
QPointF point(x, y);
painter->drawLine(QPointF(0, 0), point);
}
painter->restore();
}
3.绘制属性类型
void RadarChart::drawCategories(QPainter *painter)
{
painter->save();
QPen pen;
pen.setColor(categoriesColor); //添加线的颜色
painter->setPen(pen);
QFont font("Arial", 5, QFont::Bold, false);
//设置字体的类型,大小,加粗,斜体
painter->setFont(font);
QFontMetrics fm = painter->fontMetrics();
double radius = 80.0 ;
double startRad = (360 - startAngle) * (3.14 / 180);
double deltaRad = 360 * (3.14 / 180) / sides;
double sina, cosa;
int x, y;
for (int i = 0; i < sides; i++)
{
sina = sin(startRad - i * deltaRad);
cosa = cos(startRad - i * deltaRad);
x = radius * cosa;
y = -radius * sina;
QPointF point(x, y);
QRectF titleRect;
//分8个方向
if(x == 0 && y > 0)
//正下
titleRect = QRectF(point.x() - fm.width(categories.at(i)) / 2, point.y(), fm.width(categories.at(i)), fm.height());
else if(x == 0 && y < 0)
//正上
titleRect = QRectF(point.x() - fm.width(categories.at(i)) / 2, point.y() - fm.height(), fm.width(categories.at(i)), fm.height());
else if(x > 0 && y == 0)
//正右
titleRect = QRectF(point.x(), point.y() - fm.height() / 2, fm.width(categories.at(i)), fm.height());
else if(x < 0 && y == 0)
//正左
titleRect = QRectF(point.x() - fm.width(categories.at(i)), point.y() - fm.height() / 2, fm.width(categories.at(i)), fm.height());
else if(x > 0 && y > 0)
//右下
titleRect = QRectF(point.x(), point.y(), fm.width(categories.at(i)), fm.height());
else if(x > 0 && y < 0)
//右上
titleRect = QRectF(point.x(), point.y() - fm.height(), fm.width(categories.at(i)), fm.height());
else if(x < 0 && y < 0)
//左上
titleRect = QRectF(point.x() - fm.width(categories.at(i)), point.y() - fm.height(), fm.width(categories.at(i)), fm.height());
else if(x < 0 && y > 0)
//左下
titleRect = QRectF(point.x() - fm.width(categories.at(i)), point.y(), fm.width(categories.at(i)), fm.height());
else
titleRect = QRectF(point.x(), point.y(), fm.width(categories.at(i)), fm.height());
painter->drawText(titleRect, Qt::AlignCenter | Qt::AlignTop, categories.at(i));
}
painter->restore();
}
4.绘制标尺值
void RadarChart::drawScaleNum(QPainter *painter)
{
painter->save();
QPen pen;
pen.setColor(categoriesColor); //添加线的颜色
painter->setPen(pen);
QFont font("Arial", 3, QFont::Bold, false);
//设置字体的类型,大小,加粗,斜体
painter->setFont(font);
QFontMetrics fm = painter->fontMetrics();
double startRad = (360 - startAngle) * (3.14 / 180);
double deltaRad = 360 * (3.14 / 180) / sides;
double radiusPer = 80.0 / level ;
double sina, cosa;
int x, y;
float scaleStep = (maxValue - minValue) / level * 1.0;
for(int j = 0 ; j < level + 1 ; j++ )
{
QPointF point;
if(j <= 0)
{
point = QPointF(0.0, 0.0);
}
else
{
float newR = radiusPer * j;
sina = sin(startRad - scalePos * deltaRad);
cosa = cos(startRad - scalePos * deltaRad);
x = newR * cosa;
y = -newR * sina;
point = QPointF(x, y);
}
QString scaleNum = QString::number(scaleStep * j + minValue, 'f', 0);
QRectF titleRect = QRectF(point.x() - fm.width(scaleNum) - 2, point.y(), fm.width(scaleNum), fm.height());
painter->drawText(titleRect, Qt::AlignCenter | Qt::AlignTop, scaleNum);
}
painter->restore();
}
5.绘制各曲线图
void RadarChart::drawValues(QPainter *painter)
{
painter->save();
double startRad = (360 - startAngle) * (3.14 / 180);
double deltaRad = 360 * (3.14 / 180) / sides;
double radius = 80.0;
double sina, cosa;
int x, y;
QMap<QString, QVector<float>>::const_iterator it = dataMap.constBegin();
while (it != dataMap.constEnd())
{
QVector<float> data = it.value();
QPolygonF polygon;
QColor dataColor = dataColorMap[it.key()];
QPen dataPen;
for(int j = 0 ; j < sides; j++)
{
sina = sin(startRad - j * deltaRad);
cosa = cos(startRad - j * deltaRad);
double r;
//QPen pointPen;
float value;
if(j >= data.size())
{
value = minValue;
r = qAbs( minValue / (maxValue - minValue)) * radius;
}
else
{
value = data.at(j) ;
if(value < minValue)
value = minValue;
else if(value > maxValue)
value = maxValue;
}
r = qAbs((value - minValue) / (maxValue - minValue)) * radius;
x = r * cosa;
y = -r * sina;
QPointF point(x, y);
polygon.append(point);
dataPen.setWidthF(1.5);
dataColor.setAlpha(150);
dataPen.setColor(dataColor); //添加线的颜色
painter->setPen(dataPen);
painter->drawPoint(point);
}
QPainterPath painterPath;
painterPath.addPolygon(polygon);
painterPath.closeSubpath();
dataPen.setWidthF(lineWidth);
//线条色
dataColor.setAlpha(255);
dataPen.setColor(dataColor);
painter->setPen(dataPen);
painter->drawPath(painterPath);
//填充色
dataColor.setAlpha(100);
painter->fillPath( painterPath, dataColor);
++it;
}
painter->restore();
}
6.绘制图例
void RadarChart::drawLegends(QPainter *painter)
{
painter->save();
QPen pen;
pen.setColor(categoriesColor); //添加线的颜色
painter->setPen(pen);
QFont font("Arial", 3, QFont::Bold, false);
//设置字体的类型,大小,加粗,斜体
painter->setFont(font);
QFontMetrics fm = painter->fontMetrics();
float sx = 100 - 1;
float sy = -100 + 1;
int i = 0;
int maxW = 0;
QMap<QString, QVector<float>>::const_iterator it = dataMap.constBegin();
while (it != dataMap.constEnd())
{
int w = fm.width(it.key());
if(w > maxW)
maxW = w;
++it;
}
QMap<QString, QVector<float>>::const_iterator it2 = dataMap.constBegin();
while (it2 != dataMap.constEnd())
{
QRectF legendNameRect = QRectF(sx - maxW, sy + (fm.height() + 1) * i, fm.width(it2.key()), fm.height());
QRectF legendColorRect = QRectF(sx - maxW - 1.5 - fm.height(), sy + (fm.height() + 1) * i, fm.height(), fm.height());
painter->drawText(legendNameRect, Qt::AlignCenter | Qt::AlignTop, it2.key());
//painter->drawRect(legendColorRect);
painter->fillRect(legendColorRect, dataColorMap[it2.key()]);
i++;
++it2;
}
painter->restore();
}
7,调用方法
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QVector<QString> testData0;
testData0 << "0" << "1" << "2" << "3" << "4" << "5" << "6";
ui->widget->setCategories(testData0);
QVector<float> testData;
testData << 10 << 20 << 50 << 20 << 60 << 10 << 55;
ui->widget->addData("test11111", testData);
ui->widget->setDataColor("test11111", Qt::green);
QVector<float> testData2;
testData2 << 30 << 70 << 20 << 10 << 50 << 20 << 65;
ui->widget->addData("test2", testData2);
ui->widget->setDataColor("test2", Qt::red);
}
写得比较粗糙,没有实现鼠标悬浮等动作,有兴趣的可以自己扩展一下。代码以经上传,请多指教。。。
上一篇: iOS解决键盘弹出遮挡输入框问题