前言
整理代码的时候看到了之前写的一个统计图的代码,感觉样式还可以,分享一下,适合初学者。
本统计图是一个填充了渐变颜色的曲线统计图,X轴显示了从今天往前倒推一周的日期,Y轴则显示的是时间的统计,目前只做了统计到“分”的计算,可以用于统计一周的运动时间、学习时间等。开发环境用的Qt5.5.1+MSVC2013。
一、效果图
先展示一下效果图:
二、主要代码
统计图的数据是用QList<QMap<QString, QString>>存储的,QMap中记录了X轴和Y轴的键值对,X轴对应的key是“date”,Y轴对应的key是“value”。产生的数据暂时用随机数模拟,代码如下:
QDateTime curTime = QDateTime::currentDateTime();
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
QList<QMap<QString, QString>> dataList;
for(int i = 1; i <= 7; i++)
{
QMap<QString, QString> oneMap;
oneMap.insert("date",
QString("%1.%2").arg(curTime.addDays(i - 7).date().month())
.arg(curTime.addDays(i - 7).date().day()));
oneMap.insert("value",QString::number(qrand() % 3599, 10));
dataList.append(oneMap);
}
如果你想把统计图换成其他颜色可以修改渐变色的值,一定要加上painter.setRenderHint(QPainter::Antialiasing, true)这一段代码,要不画出来的图有毛边。
QPainter painter(this);
painter.setPen(Qt::NoPen);
painter.setRenderHint(QPainter::Antialiasing, true);
QLinearGradient linearBubble(rect().topLeft(), rect().bottomLeft());
linearBubble.setColorAt(0, QColor(45,183,255));
linearBubble.setColorAt(0.4, QColor(45,183,255));
linearBubble.setColorAt(1, Qt::white);
painter.setBrush(linearBubble);
要遍历一下传递过来的数据,取到最大的值,以最大值占用总值90%的比率计算出统计图的阈值,然后再计算出每个点相隔的距离:
for(int i = 0;i < 7;i++)
{
if(m_data[i]["value"].toInt() > m_curveThreshold)
{
m_curveThreshold = m_data[i]["value"].toInt()/0.9;
}
if(m_curveThreshold == 0)
{
m_curveThreshold = 1;
}
}
//取点间距
m_pointSpace = (width() - CHART_EDGE * 2) / 6;
通过计算来确定每个点的位置,两个点之间用一条三次贝塞尔曲线链接:
//画链接两点的曲线
QPoint start_pos(CHART_EDGE + (i - 1) * m_pointSpace, startPosY);
QPoint end_pos(CHART_EDGE + i * m_pointSpace, endPosY);
QPoint c1((start_pos+end_pos).x()/2,start_pos.y());
QPoint c2((start_pos+end_pos).x()/2,end_pos.y());
myPath.cubicTo(c1 , c2, end_pos);
最后将每个点的连线放到QPainterPath中,再调用画笔的drawPath方法就可以了。
三、paintEvent全部代码
paintEvent中的全部代码:
void MyCountChart::paintEvent(QPaintEvent *event)
{
m_curveThreshold = 0;
if(m_data.count() < 7)
{
return;
}
//创建画板
QPainter painter(this);
//设置无画笔
painter.setPen(Qt::NoPen);
//反锯齿
painter.setRenderHint(QPainter::Antialiasing, true);
//填充画板渐变色
QLinearGradient linearBubble(rect().topLeft(), rect().bottomLeft());
linearBubble.setColorAt(0, QColor(45,183,255));
linearBubble.setColorAt(0.4, QColor(45,183,255));
linearBubble.setColorAt(1, Qt::white);
painter.setBrush(linearBubble);
//取阈值
for(int i = 0;i < 7;i++)
{
if(m_data[i]["value"].toInt() > m_curveThreshold)
{
m_curveThreshold = m_data[i]["value"].toInt()/0.9;
}
if(m_curveThreshold == 0)
{
m_curveThreshold = 1;
}
}
//取点间距
m_pointSpace = (width() - CHART_EDGE * 2) / 6;
//设置曲线图高度
m_chartCurveWidth = height() - CHART_EDGE * 2;
//底线端点
QPoint startEdge(CHART_EDGE, height() - CHART_EDGE);
QPoint endEdge(CHART_EDGE + 6 * m_pointSpace, height() - CHART_EDGE);
//创建路径
QPainterPath myPath(endEdge);
myPath.lineTo(startEdge);
//设置第一个点的位置
int firstPosY = height() - CHART_EDGE - m_data[0]["value"].toInt() * m_chartCurveWidth / m_curveThreshold;
QPoint firstPoint(CHART_EDGE, firstPosY);
myPath.lineTo(firstPoint);
//设置第一个点的日期标签位置和内容
m_dateLabels[0]->setText(m_data[0]["date"]);
m_dateLabels[0]->move(CHART_EDGE - 20, height() - CHART_EDGE + 10);
//设置第一个点的时长标签位置和内容
int firstTime_min = m_data[0]["value"].toInt()/60;
int firstTime_sec = m_data[0]["value"].toInt()%60;
if(firstTime_sec >= 30)
{
firstTime_min+=1;
}
else
{
if(firstTime_min == 0 && firstTime_sec > 0)
{
firstTime_min = 1;
}
}
m_timeLabels[0]->setText(QString("%1%2").arg(firstTime_min).arg(Y_UNIT_MIN));
m_timeLabels[0]->move(CHART_EDGE-23, firstPosY-18);
for(int i = 1; i < 7; i++)
{
//两点的Y坐标
int startPosY = height() - CHART_EDGE - m_data[i-1]["value"].toInt() * m_chartCurveWidth / m_curveThreshold;
int endPosY = height() - CHART_EDGE - m_data[i]["value"].toInt() * m_chartCurveWidth / m_curveThreshold;
//画链接两点的曲线
QPoint start_pos(CHART_EDGE + (i - 1) * m_pointSpace, startPosY);
QPoint end_pos(CHART_EDGE + i * m_pointSpace, endPosY);
QPoint c1((start_pos+end_pos).x()/2,start_pos.y());
QPoint c2((start_pos+end_pos).x()/2,end_pos.y());
myPath.cubicTo(c1 , c2, end_pos);
//日期
if(i == 6)
{
m_dateLabels[i]->setText(QString::fromLocal8Bit("今天"));
}
else
{
m_dateLabels[i]->setText(m_data[i]["date"]);
}
m_dateLabels[i]->move(CHART_EDGE + i * m_pointSpace - 20, height() - CHART_EDGE + 10);
//时长
int time_min = m_data[i]["value"].toInt()/60;
int time_sec = m_data[i]["value"].toInt()%60;
if(time_sec >= 30)
{
time_min+=1;
}
else
{
if(time_min == 0 && time_sec > 0)
{
time_min = 1;
}
}
m_timeLabels[i]->setText(QString("%1%2").arg(time_min).arg(Y_UNIT_MIN));
m_timeLabels[i]->move(CHART_EDGE + i * m_pointSpace - 23, endPosY - 18);
}
//封闭图形
myPath.lineTo(endEdge);
painter.drawPath(myPath);
return QWidget::paintEvent(event);
}
最后
主要就是通过重绘事件对界面的一个绘制,希望对您有帮助。
源码地址:https://download.csdn.net/download/qq_36129488/87810601