1、图的类型
不管什么类型的图,都是QChart类。决定图类型的是:数据系列的类型。各种数据系列类都继承自QAbstractSeries,常用的数据系列类如下图所示。本文主要研究折线图。
2、折线图的坐标轴
折线图的坐标轴类型QValueAxis(数字)、QDateTimeAxis(时间),本质上,时间轴这种类型也是数值型,只不过这种类型能把数据系列的X值灵活的显示为想要时间格式(如2017.10:20或者20:03:12.456 等,格式可参考QDateTime),而QValueAxis格式的轴,只能把数据系列的X值原样显示。
//在ui中添加QGraphicView控件,并提升为QChartView类
QChart Chart;//图表
QLineSeries lineseries;//折线图数据系列
QDateTimeAxis dateAxisX;//时间类型轴(用作X轴)
QValueAxis *axisY;//数值类型轴(用作Y轴)
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//或者从1970年0:0:0到此时此刻的总ms数
qint64 current_time_total_ms = QDateTime::currentMSecsSinceEpoch();
lineseries.append(current_time_total_ms, 10);
&lineseries << (current_time_total_ms+1, 5);
lineseries.append(current_time_total_ms + 2, 8);
Chart.addSeries(lineseries); // 将 series 添加至图表中
dataAxisX.setFormat("mm:ss:zzz");//设置X轴数据的显示格式(格式串的写法请参考QDateTime::toString的帮助文档)
Chart.setAxisX(&dataAxisX, lineseries);
Chart.setAxisY(axisY);
//下面是自己设置X轴的显示范围,参数必须转换为QDateTime。本例用的是,把从19700101的到此刻的ms数字转为QDateTime格式
//Chart.axisX()->setRange(QDateTime::fromMSecsSinceEpoch(x_min),
// QDateTime::fromMSecsSinceEpoch(x_max));
}
有运行结果可以看到,X轴的数据被转换成了时间样式显示了出来。如果我们把上述程序中X轴的类型更换为QValueAxis,那么X轴显示的数据就是上面程序中注释说到的毫秒数。如下图所示:
3、设置X轴的显示范围
可参考我的另一篇文章:《QT中图表类QChart 系列之(2):设置显示的区间》
4、获取鼠标指向的点的坐标值
这个功能在QChartView类中,很简单,以继承并重写鼠标移动事件为例:
需要注意的是,重写moveEvent之后,框选放大功能会失效,这时可以在自己的重写函数中加上:
QChartView::mouseMoveEvent(e);//调用父类的重写方法
void QChartView_my::mouseMoveEvent(QMouseEvent *e)
{
//打印鼠标位置处的点的坐标值
qDebug()<< this->chart()->mapToValue(e->pos());//把鼠标坐标值转化为画出的图中的坐标
//以防父类的实例接收不到mouseMoveEvent事件。
QChartView::mouseMoveEvent(e);//调用父类的重写方法。本行程序不同于e->ignore(),ignor是把事件继续向父控件(一般其父控件就是ui界面)传递,而不是向父类传递
}
5、动态滚动
假设我们在采集AD数据,并实时显示AD的值,这时就希望折线图能实时动态滚动,要不然几千个点都挤在屏幕上就看不清了。
void MainWindow::on_pushButton_addPoint_clicked()
{
static float new_x = 0;
new_x += 0.3;
float new_y = sin(new_x);
lineseries->append(new_x, new_y);//添加到数据系列中的点会被自动显示(如果该点处在显示区间的话)
QValueAxis *axisX = dynamic_cast<QValueAxis*>(lineChart->axisX());
qreal cur_x_min = axisX->min();//当前X轴显示区间的最小x值
qreal cur_x_max = axisX->max();
if(new_x > cur_x_max)//新的x值处在X轴显示区的之外了
{
qreal error = new_x - cur_x_max;//X轴的显示区向右挪error距离即可把新x显示出来
lineChart->axisX()->setRange(cur_x_min + error, cur_x_max + error);
}
else//还能显示出来,无需挪动显示区
{
}
lineChart->axisY()->setRange(-2, 2);
}
效果如下图所示:可以发现,当chart能显示出新的点sh时,图像没有发生滚动,一旦点把图像填满了,图像就开始滚动了,也即下面图3的X坐标区间整体变大了。
另外,如果想让最新的点,不是显示在最右侧,而是距离最右侧留出一点距离(这样观察新的点会更清楚),那么可以把上面程序中的lineChart->axisX()->setRange(cur_x_min + error, cur_x_max + error);再加一点偏移就好了,例如:
lineChart->axisX()->setRange(cur_x_min + error + 5, cur_x_max + error + 5);