qwt实现码流柱状图多色柱体显示
1. 前言
在视频码流分析中,经常用到elecard 来查询码流的参考关系,其中就有柱状图来表示每一帧的示意图,如:
在工作之余,想通过Qt实现一款自己的码流分析工具,实现这个工具需要了解视频的一些概念,在此文章中不展开讲述,本文主要是讲述qt实现多色柱状图,以及一些定制化实现。简单的demo如下:
功能:
1.每个柱体可以显示不同的颜色
2.每个柱体可以显示对应的数值
3.每个柱体的坐标显示不同的信息
4.实现滚动拉动滚动条显示剩余的柱体
5.单击/hover柱体,显示想要的字符串
6.单击选项,可以跳转到对应的柱体
2. qt实现柱状图
qt实现柱状图有多种方法,例如QChart, Qwt, QCustomPlot,甚至可以自己手搓,关于这三者的对比可以网上查询一些参考,个人觉得如果是实现一些简单的图表类,可以使用QChart,上手快,外观较其他两个漂亮,但在一些定制化中,却不够友好,而qwt就相对容易实现复杂的定制化,想要设计得很漂亮也可以,但需要比较深入研究,QCustomPlot源码就两个文件,可以方便集成到项目里,但由于不够成熟,对于一些复杂的画图,要自己实现很多功能。
为了实现图1的效果,本人一开始使用QtChart做,但最后发现,每个柱体要显示不同的颜色,会使用大量的内存,这个是不划算的,最后综合考虑下,使用qwt实现。
3.qwt基础说明
3.1 qwt安装与使用
这章内容在网络上有许多介绍,但有些作者在一些地方没有描述清楚,下面简略介绍下步骤:
本人的环境是:
pc: window 10
qt: qt5.9.8+mingw53_32
3.1.1 下载qwt源码
- sourceforge地址:
release包:https://sourceforge.net/projects/qwt/files/qwt/
git方式:https://sourceforge.net/p/qwt/git/ci/develop/tree/ - github地址:https://github.com/opencor/qwt
- wiki地址:https://qwt.sourceforge.io/
从上面的地址任意一个下载源码,如果后续需要研究源码,建议通过git下载仓库,方便回溯
3.1.2 编译
-
最简单的是通过QtCreator打开qwt的工程,一键编译
-
或者使用命令行方式,用qmake编译
编译模式选择:
选择release模式,这样编译出来的库size小一点,另外如果需要在qtdesigner,qtcreator上实现画图,需要用到release版本
当然debug,profile版本也是可以的,就是后续在发布软件时,size会大很多,发布软件一版都是release版本的库。
编译出来结果如下:
3.1.3 安装
为了后续可以在qtcreator,qtdesiner上画图,就需要将编译出来的库,头文件,画图插件拷贝到qt的安装目录下:
将编译出来的designer\plugins\designer文件夹下的qwt_designer_plugin.dll
放到C:\Qt\Qt5.9.8\5.9.8\mingw53_32\plugins\designer
下
另外,也需要:
- 将编译出来的lib文件夹下的
libqwt.a
,libqwtd.a
放到C:\Qt\Qt5.9.8\5.9.8\mingw53_32\lib
- 将编译出来的lib文件夹下的
qwt.dll
,qwtd.dll
放到C:\Qt\Qt5.9.8\5.9.8\mingw53_32\bin
- 将qwt源码目录下src里的*.h头文件全部拷贝到
C:\Qt\Qt5.9.8\5.9.8\mingw53_32\include\Qwt
,Qwt文件夹需要自行创建
3.1.4 使用
- 在工程中使用qwt,需要在*.pro文件里添加qwt的库和头文件链接,方法可以手动添加,也可以在pro文件里右键选择外部库路径
- 对于一份可移植的工程来说,一般做法是不链安装在qt目录下载qwt库的,应该在工程文件里创建一个文件夹,放置qwt的头文件和库,这样别人用的时候,就不需要额外去编译qwt。而且也可以放置多份不同的编译工具链编译出来的库,例如32位,64位的,这样就可以在不同平台中进行编译自己的code,而且发布软件时,也可以根据不同的平台进行发布
- 拖拽画图,如果qwt编译使用mingw53编译,那么只能在qtdesigner里打开进行画图,因为qtcreator是用mvsc编译的,
qwt_designer_plugin.dll
不匹配,方法是在打开的qtcreator工程里,在ui文件处右键,选择用qtdesigner打开。
3.2 QwtPlotBarChart类
qwt源码中有自带的example例子,可以参考来实现examples\distrowatch
该例子已经可以实现每个柱体不同颜色,但跟所想要的效果还差很多功能,以下定制,是基于此开发的。
在此之前,需要先说明下,qwt的barChart的画图原理:
文章为ganqiuye原创,转载请注明文章来源https://blog.csdn.net/ganqiuye/article/details/142798934)
-
高度:橙色蓝色两个柱体高度分别是1,2。
-
柱体位置:柱体的中间位置对应着坐标点
-
宽度:柱体的宽度默认是1,即两个柱体间应该紧密挨着,中间没有空隙,但可以通过QwtPlotBarChart的setLayoutHint,setSpacing来调节柱体的间的空隙。
全部柱体的宽度平均分配整个画布宽度的大小,例如,画布大小是400宽度,一共4个柱体,那么每个柱体应该是100宽度。对应箭头1,宽度也是100。
当通过setLayoutHint设置柱体的宽度,例如设置了20宽度,则箭头2是20宽度,箭头3空隙就是80,箭头4宽度是10,但箭头1还是100。
setSpacing函数,设置箭头3的宽度
箭头2+箭头3=箭头1
箭头4=箭头2的一半
-
坐标:以柱体的左上角的坐标为例
相对于整个画布的位置,分别是(-0.5,1),(0.5,2)
相当于pc窗口来说,分别是(100,50),(101,51)
画布坐标和pc窗口坐标的转换,通过mapToGlobal函数来转换
3.2.1画图步骤
如果没有任何定制化需求,QwtPlotBarChart在调用时,就两个步骤:
-
new一个QwtPlotBarChart实例
-
调用setSamples传递数据
这样就能生成柱状图(当然plot, cavas还是要创建的),QwtPlotBarChart类内部会自动画出默认格式的
3.2.2 specialSymbol
而当需要定制不同的柱体(不包括图例,下标等定制),就需要实现重载函数:
virtual QwtColumnSymbol* specialSymbol(int sampleIndex, const QPointF& ) const;
qwt的QwtPlotBarChart类中的specialSymbol函数是一个空函数,如果需要实现定制化,可以继承QwtPlotBarChart,自行实现此函数,该函数里有参数smpleIndex,可见是可以对具体的某个特定柱体实现特定的定制的。
qwt源码中QwtPlotBarChart类的specialSymbol函数是一个空函数:
QwtColumnSymbol* QwtPlotBarChart::specialSymbol(
int sampleIndex, const QPointF& sample ) const
{
Q_UNUSED( sampleIndex );
Q_UNUSED( sample );
return NULL;
}
当在画柱体时,drawBar函数:
void QwtPlotBarChart::drawBar( QPainter* painter,
int sampleIndex, const QPointF& sample,
const QwtColumnRect& rect ) const
{
const QwtColumnSymbol* specialSym =
specialSymbol( sampleIndex, sample );
const QwtColumnSymbol* sym = specialSym;
if ( sym == NULL )
sym = m_data->symbol;
if ( sym )
{
sym->draw( painter, rect );
}
else
{
// we build a temporary default symbol
QwtColumnSymbol columnSymbol( QwtColumnSymbol::Box