首先绘制区域扇形需要先注意一下几点:
QPainter中绘制完整的圆等于5760(16 * 360),此处数值用于计算每一块扇形区域所显示的
需要了解一下扇形二等分线的计算方法
要注意做坐标原点转换
/*此处为屏幕分辨率自适应*/
const qreal ratioW = DesktopResize::GetInstance()->getWidthRatio();
const qreal ratioH = DesktopResize::GetInstance()->getHeightRatio();
const qreal ratioT = qMin(ratioW, ratioH);
// 三角形和凸角必须指定为1/16度,即一个完整的圆等于5760(16 * 360)
int circleArea = 5760;
// 设置圆弧显示区域
QRect rect(418 * ratioW, 340 * ratioH, 557 * ratioT, 557 * ratioT);
// 圆半径
int radius = rect.width() / 2;
// 起始角度
qreal startAngle = 0;
// 当前绘制扇形所占角度
qreal angle;
//文字显示起始角度
qreal textStartAngle = 0;
// 文字显示角度
qreal textAngle;
// 需要统计的总数值
int totalValue = 0;
// _fanDataClassList为一个结构数据list,根据个人需要自行定义
// 计算总数值
for(int i = 0; i < _fanDataClassList.count(); i++)
{
totalValue += _fanDataClassList.at(i).value;
}
// 计算每个数值的扇形显示区域
for(int i = 0; i < _fanDataClassList.count(); i++)
{
// 设置画笔颜色与画刷颜色保持一致,需要注意此处需要设设置画笔,否则会出现两个扇形之间显示有空白间隙
QPen pen(_fanDataClassList.at(i).color, 1, Qt::SolidLine);
painter->setPen(pen);
// 设置画刷颜色与画笔保持一致
painter->setBrush(_fanDataClassList.at(i).color);
// 计算当前数值所占的百分比
qreal persent = (double)_fanDataClassList.at(i).value / totalValue;
// 根据百分比计算当前数值扇形尖角处所占角度的比例
angle = circleArea * persent;
// 通过path来获取当前绘制的扇形区域
QPainterPath path;
// 因圆心角需要在中位置来计算,将path起点移动到rect的中点位置
path.moveTo(rect.center());
// 创建一个占据给定矩形的弧,从指定的startAngle开始,逆时针扩展angle结束
// 角度用角度来表示。顺时针弧线可以使用负角度指定。
path.arcTo(rect, startAngle / 16, angle / 16);
// 此处用来确定鼠标点击区域显示统计数据用,根据个人需要添加
_pathValueMap.insert(i, path);
// 绘制当前数值所占扇形区域
painter->drawPath(path);
// 如果不需要获取每块扇形的点击区域也可以直接使用drawPie绘制,就不需要使用path了
// painter->drawPie(rect, startAngle, angle);
// 计算下一个扇形的起始角度
startAngle += angle;
}
// 绘制每一块扇形区域的文字数目和占比统计
painter->setBrush(Qt::NoBrush);
for(int i=0; i < _fanDataClassList.count(); i++)
{
if(_fanDataClassList.at(i).value == 0)
continue;
// 同样先计算当前数值的占比
qreal persent = (double)_fanDataClassList.at(i).value / totalValue;
// 计算文字显示角度
textAngle = circleArea * persent;
//各个对应扇形二等分线的角度
qreal abc = 3.14 * 2 * (double)(textStartAngle + textAngle / 2) / circleArea;
// 根据二等分线计算出当前扇形区域边缘的终点坐标
qreal valueX = radius * qCos(abc) + radius + rect.x();
qreal valueY = -radius * qSin(abc) + radius + rect.y();
// 计算终点坐标相对于圆心的坐标用以标定文字的显示方向
QPointF point = QPointF(valueX, valueY) - rect.center();
int lineX = 0;
int lineY = 0;
int lineWidth = 0;
int textX = 0;
// 根据数学坐标系判断该点坐标所处象限
if(point.x() > 0 && point.y() < 0)
{
lineX = 30 * ratioW;
lineY = -30 * ratioH;
lineWidth = 40 * ratioW;
textX = valueX + lineX + lineWidth + 10 * ratioW;
}
else if(point.x() < 0 && point.y() < 0)
{
lineX = -30 * ratioW;
lineY = -30 * ratioH;
lineWidth = -40 * ratioW;
textX = valueX + lineX + lineWidth - 250 * ratioW;
}
else if(point.x() < 0 && point.y() > 0)
{
lineX = -30 * ratioW;
lineY = 30 * ratioH;
lineWidth = -40 * ratioW;
textX = valueX + lineX + lineWidth - 250 * ratioW;
}
else if(point.x() > 0 && point.y() > 0)
{
lineX = 30 * ratioW;
lineY = 30 * ratioH;
lineWidth = 40 * ratioW;
textX = valueX + lineX + lineWidth + 10 * ratioW;
}
// 绘制二等分线和延迟线及文字下划线, 以下代码较为简单就不做注解了
QPen pen(_fanDataClassList.at(i).color, 1, Qt::SolidLine);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
painter->setPen(pen);
QVector<QPointF> points;
points.push_back(QPointF(valueX, valueY));
points.push_back(QPointF(valueX + lineX, valueY + lineY));
points.push_back(QPointF(valueX + lineX + lineWidth, valueY + lineY));
painter->drawPolyline(QPolygonF(points));
QFont font = painter->font();
font.setPixelSize(22 * ratioT);
font.setWeight(50);
font.setBold(true);
painter->setFont(font);
pen.setColor(Qt::black);
painter->setPen(pen);
// painter->drawText(valueX - 20, valueY, QString("%1%").arg( QString::number((persent * 100), 'f', 1)));
if(i == 0)
{
painter->drawText(textX, valueY + lineY + 5 * ratioH, QString("正确率:100% %1人")
.arg(_fanDataClassList.at(i).value));
}
else if(i == 1)
{
painter->drawText(textX, valueY + lineY + 5 * ratioH, QString("正确率:90%-99% %1人")
.arg(_fanDataClassList.at(i).value));
}
else if(i == 2)
{
painter->drawText(textX, valueY + lineY + 5 * ratioH, QString("正确率:80%-89% %1人")
.arg(_fanDataClassList.at(i).value));
}
else if(i == 3)
{
painter->drawText(textX, valueY + lineY + 5 * ratioH, QString("正确率:60%-79% %1人")
.arg(_fanDataClassList.at(i).value));
}
else
{
painter->drawText(textX, valueY + lineY + 5 * ratioH, QString("正确率:0%-59% %1人")
.arg(_fanDataClassList.at(i).value));
}
textStartAngle += textAngle;
}
效果如图: