IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 深入浅出CChart 每日一课——快乐高四第五十六课 絮絮叨叨,岁月杀猪刀之FAQ -> 正文阅读

[C++知识库]深入浅出CChart 每日一课——快乐高四第五十六课 絮絮叨叨,岁月杀猪刀之FAQ

CChart发布已有多年,QQ交流群也成立了很久。在和网友的交流中,发行了CChart的很多问题,也进行了很多改进和完善。

网友们接触CChart的时间有早有晚,不同的网友经常在群里或私聊的时候提出的相近的问题,本节课准备对这些共性问题进行一些介绍。

A56.1 刷新问题

问:为什么我添加数据或修改数据后,屏幕的图像没有变化,或者是需要鼠标在图像上动一下图像才有变化?

答:CChart一般不会自动画图。

有时候你觉得好像我没有主动调用绘图函数啊,怎么也画图了呢?这是由于你使用CChartWnd的时候,在窗口的OnPaint函数里面调用了CChart的OnDraw函数。只要不触发OnPaint,图像是画不出来的。而鼠标移动有可能会触发OnPaint,所以有时候需要鼠标在图像上动一下图像才有变化。

为了主动刷新图像,在添加完数据后,可以调用一下CChartWnd::ReDraw(),或者CChart::OnDraw(HWND hWnd),也可以用Win32API的InvalidateRect刷新。

A56.2 默认背景问题

问:我不喜欢CChart的默认背景,请问怎么取消?

答:一般软件都有一个无法取消的默认背景,起到版权宣示或者产品推广的作用,

CChart的默认背景就温柔得多了,如下:

这个背景并不是强制性的,可以取消,也可以换成别的背景。参考本系列教程的第A17课,“深入浅出CChart 每日一课——快乐高四第十七课 麦田的守望,默认界面的设置方法_baita96的博客-CSDN博客”。

默认背景界面的设置内容其实也是很丰富的。

A56.3?多线程问题

问:我在多线程下使用CChart,偶尔程序崩溃,但也不一定崩溃,是什么原因。

答:所有的操作系统,刷新UI界面都不建议在工作线程中进行,包括Windows、Linux、Android、MacOS等。因为各大系统的UI元素都不是线程安全的。

Windows推荐的在线程中刷新界面的标准方法是发消息,具体的方法是调用InvalidateRect,使得窗口某一部分失效,这样Windows系统会在主线程的消息队列里插入一个WM_PAINT消息,从而刷新窗口。当然,这样的话,由于WM_PAINT消息在队列里排队,有时候刷新可能不即时,可以在InvalidateRect之后,立马调用一下UpdateWindow或RedrawWindow,这样系统会立马处理WM_PAINT消息。

具体到CChart中,有两种情况。

如果使用的是CChart这个类,一般情况下在主线程里面可以调用OnDraw(HWND hWnd)这个接口刷新界面。但在主线程之外的其它线程里面,不要这样使用,还是用InvalidateRect吧。当然如果是MFC,可以调用Invalidate这个函数,它是InvalidateRect的一个包装。

如果使用的是CChartWnd,那么CChartWnd::ReDraw()这个接口就是刷新绘图区域。但这里要注意CChart::SetDirectRedraw(bool bRedraw)这个函数。默认情况下这个函数是设置为false的,也就是说,CChartWnd内部不是直接绘图,而是调用消息刷新的,也就是说这是安全的。如果SetDirectRedraw(true),那么CChartWnd内部调用OnDraw重绘,线程不安全。

A56.4?曲线颜色问题

问:我怎么才能设置曲线的颜色,SetDataColor似乎不起作用?

答:CChart的曲线颜色具有很丰富的选项,具体设置方法请参考上一课“深入浅出CChart 每日一课——快乐高四第五十五课 天然去雕饰,出水芙蓉之美轮美奂_baita96的博客-CSDN博客”。

此外,上一课主要介绍的是绘图类型为kTypeXY的折线图的曲线颜色设置。对于多层视图,包括分层视图和共享X轴视图,默认情况下,每一层的所有曲线颜色均设置为和该层的坐标轴颜色相同,以便区分不同的图层。在这种情况下,如果想单独设置曲线颜色,请先调用CChart::SetUniteLayerColor(bool bUnite)这个接口,参数设置为false,以解除曲线颜色的绑定。

A56.5 曲线名称问题

问:怎么修改屏幕上“未命名000”、“未命名001”等显示的曲线名称为我想要的名字?

答:屏幕上曲线名称是显示在图例之中的。每条曲线都有一个名称,可以用CChart::SetDataTitle()这个接口设置。如果不设置,在图例中显示的名称就是“未命名XXX”。

A56.6 图像缩放问题

问:图像怎么放大缩小?可以用鼠标滚轮缩放图像吗?

答:在默认状态下,CChart是关闭图像缩放功能的。

打开图像缩放功能用两种方式。

一种是在程序运行时,通过右键菜单打开,“绘图状态”-->“特别功能”-->“坐标缩放”。

一种是通过代码打开,调用CChart::SetRangeZoomMode();

CChart坐标缩放功能是按住鼠标左键,往右拖动放大,往左拖动缩小(还原上一次拖动状态),很方便实用。

如图,在往右拖动的时候,会出现一个拖动框,松开鼠标左键,图像就放大到拖动框的范围。?

此外,打开坐标缩放功能后,默认鼠标滚轮就可以缩放图像了。

A56.7 图像显示范围问题

问:图像默认的坐标轴范围和我想要的不一样,我想设置一下,但调用SetXRange或SetYRange后,根本没有任何作用,请问怎么办?

答:调用SetXRange、SetYRange或SetPlotRange后,不起作用的原因是CChart默认情况下是自动计算坐标轴显示范围的。为了让这些设置其作用,需要先调用一下SetXAutoRange(false)或SetYAutoRange(false)。

这里还有一个问题,如果图像中增加了曲线或某曲线增加了数据点,即使调用了SetXAutoRange或SetYAutoRange,显示范围也会重新计算。

为了彻底固定显示范围,可以调用SetXStaticRange(true)或SetYStaticRange(true)。

A56.8?数据点驱动的等高线图、云图、三维曲面图问题

问:我已有一些数据点,怎么绘制等高线图、云图、三维曲面图?

答:CChart的等高线图、云图、三维曲面图,都是由场函数驱动的。场函数的基本形式是h=f(x,y),需要调用SetFieldFcn(f)以设置场函数。

如果已知一些数据点,怎么画图呢?理论上,可以根据这些数据点编写自己的场函数,然后SetFieldFcn即可。

但实际上,根据数据点获得场函数是一项难度极大的工作,这也是一个庞大的研究课题,用户自己实现的可能性极小。

CChart内部已经集成了多种算法,包括克里金法、自然邻域法、反距离权重法等。

具体的使用方法是需要先调用一下下面这个函数

void		CChart::SetContourByArbPoints();

CChart内部就建立了一个插值函数作为场函数,默认的插值算法是自然领域法。

然后添加数据点即可。添加数据点的接口为

void		CChart::AddContourPoint(double x, double y, double h);

详细的用法请参考本教程第A6课“深入浅出CChart 每日一课——快乐高四第六课 二丫的青梅,返璞归真之普通窗口多区域绘图_baita96的博客-CSDN博客”。

A56.9 同一个窗口绘制多个图像问题

问:我想在一个窗口上画多个图像,请问怎么办?

答:单个窗口分成多个区域,然后每个区域画一张图像,这在CChart库中有多种实现方式。

方式1、利用分裂视图。

分裂视图直接将窗口客户区分成多块,每个区域绘制一个图像。

分裂视图划分窗口的方式有很多种,最简单的是按行列划分,也可以按左一右二、左二右一、上一下二、上二下一的方式划分,比较灵活。

详细的使用方式见本教程第十课“深入浅出CChart 每日一课——第十课 分裂视图,锤子肖哥之错位人格_baita96的博客-CSDN博客”。

分裂视图最大的优点是Chart内部对这种视图进行了一下处理,可以实现一些自己处理较难实现的功能,比如各个区域之间可以用鼠标拖动调整大小,Ctrl+鼠标双击可以切换单区域独占窗口功能等。

分裂视图也有一些问题,最大的问题是发布的版本里面,分开的每个区域都只能绘制折线图,不能画其它类型的图像,更不用说每个区域画不同类型图像了。

方式2、利用多个CChart类对象。

这种方式是设置多个CChart类对象,每一个对应窗口的一个区域。

本系列教程的A06、A07、A08三课都是讲述这个方式,详见“深入浅出CChart 每日一课——快乐高四第六课 二丫的青梅,返璞归真之普通窗口多区域绘图_baita96的博客-CSDN博客”、“深入浅出CChart 每日一课——快乐高四第七课 铁蛋的竹马,返璞归真之对话框窗口多区域绘图_baita96的博客-CSDN博客”、“深入浅出CChart 每日一课——快乐高四第八课 懵懂的童年,返璞归真之Duilib窗口多区域绘图_baita96的博客-CSDN博客_duilib多窗口”。

采用多个CChart类对象的方法,比较灵活。缺点是需要自己编写消息响应代码。当然如果不需要消息响应的话,这种方法是最好的。

方式3、利用多个ChartCtrl控件。

这种方式是在窗口每个区域放置一个ChartCtrl控件。

ChartCtrl控件是CChart内部已经注册的窗口类,可以看作和Windows内置的Button、Edit、Label等窗口类是等同的。

详细用法参见本系列教程的A15课,“深入浅出CChart 每日一课——快乐高四第十五课 罗马通途,利用ChartCtrl控件实现多区域绘图_baita96的博客-CSDN博客_chartctrl”。

此方法最关键的是一个函数:

CChart *GetChart(HWND hWnd);

用这个函数获得CChart指针,然后进行各种操作。

其中hWnd这个句柄是ChartCtrl控件的窗口,如果不是的话,GetChart将返回空指针。

方式4、利用多个CChartWnd变量。

这种方式是窗口每个区域对应一个CChartWnd变量,Attach的时候,注意要给出该区域的RECT。

此方法的关键函数是:

int CChartWnd::Attach(HWND hWnd, RECT rect);

注意最好不同区域的RECT不要有重叠的部分,以避免不必要的问题。

另一个关键函数是:

CChart *CChartWnd::GetChart();

这个函数获得CChart指针,然后就可以开展各种操作了。

注意这个函数没有形参。

方式5、利用单个CChartWnd变量,多次Attach

与上一个方式的差别在于,只有一个CChartWnd变量。CChart库已经实现了同一个CChartWnd多次Attach的功能,用户可以放心使用。

此方法的关键函数仍然是:

int CChartWnd::Attach(HWND hWnd, RECT rect);

同样,Attach的时候,rect之间最好不要有重叠。

但是,可能同学们会疑惑,那怎么区分不同的图像呢?那就看看下面这个关键函数。

CChart *CChartWnd::GetChart(int nChartIndex);

真的吗?这个和上面那个方法不是同样的函数吗?

的确,还是上面那个函数,但这里带了形参。nChartIndex是图像序号。简单地说:第一次Attach的图像,其序号为0;第二次Attach的图像,其序号为1;以此类推。

方式6、前两种方式混用。

也就是说,可以设置多个CChartWnd变量,其中一些CChartWnd变量对应单个图像,另一些CChartWnd变量对应多个图像。

CChart库非常灵活,这样用是完全没有问题的。

A56.10 时间坐标轴问题

问:我想让X轴显示为时间,请问怎么办?

答:CChart支持时间坐标轴,把一个坐标轴设置为时间轴的接口如下。

void CChart::SetAxisToTime(bool bTime, int location);

其中location表示哪个坐标轴,具体来说,0是左轴,1是下轴,2是右轴,3是上轴。

也可以设置时间刻度的显示格式。

void CChart::SetAxisTimeFormat(TCHAR *format, int location);

注意这里的format格式字符串,这个字符串格式和C语言标准函数strftime是完全一样的,可以查阅strftime的资料。其中一部分,%Y表示年份,%m表示月份,%d表示日,%H表示小时,%M表示分,%S表示秒。

但是要注意,光把坐标轴设置为时间轴,数据也得是时间才对。

CChart内部的时间数据采用C语言的标准类型time_t数据。对于VC来说,time_t就是一个64位长整数,

也就是说,如果需要X轴显示时间,您的数据的X坐标应该是time_t数据。

数据输入的时候,可以直接给time_t数据,也可以利用时间字符串输入。相关的函数有

int CChart::AddPoint2D(TCHAR *strTime, TCHAR *fmt, double y, int nDataIndex=0, int nPlotIndex=0);

int AddCurve(TCHAR **pStrTime, TCHAR *fmt, double *pY, int nLen, int nPlotIndex=0);

这两个函数的x数据由字符串给定,其中字符串的格式由fmt格式字符串指定,这个格式仍然需要参考strftime这个API。例如,假定时间是2022年6月20日16点50分30秒,时间字符串可以是”2022-06-20 16:50:30”,格式字符串为”%Y-%m-%d %H:%M:%S”,当然格式也可以调整。

注意,这里用于输入的字符串格式,可以和上面坐标轴显示的格式不一样。

当然,您也可以不用上面两个函数输入数据,仍然把时间数据用time_t直接输入。

不过,自己操作time_t可能比较困难,笨笨提供了一个时间字符串转数值的接口。

double StringToTime(TCHAR *str, TCHAR *fmt);

这里返回值就是time_t,但是转换为double了。

问:X轴显示为时间时,各个刻度的数据比较乱,比如显示多少分多少秒,我想让它稍微凑整一点可以吗?

答:这是可以的,可以利用下面这两个函数:

void CChart::SetXAtom(double atom);

void CChart::SetYAtom(double atom);

这两个函数的参数就表示刻度之间的间隔。对于time_t数据,就是多少秒。比如,您希望刻度间隔为5分钟,可以调用SetXAtom(300)。

当然,这个函数在内部实现的时候,不是硬性的。如果您设置的atom离实际情况差别比较大,这个函数不起作用。例如比如您的坐标总的范围只有1分钟,但您这里仍然设置atom为300,那明显超出太多。

问:X轴显示为时间时,时间精度能优于秒吗?

答:CChart的时间精度不能直接优于秒,但笨笨加了一些补丁,可以让时间精度优于秒。

CChart的时间精度不能直接优于秒的原因是内部采用time_t作为时间数据,time_t的最小只能表示到秒,不能再小。

当然,Windows系统提供的另一种时间数据COleTime,其精度完全可以优于秒,但CChart一开始就没有选择这种方案。

为了让时间精度优于秒。笨笨在CChart内部做了如下处理。

首先设置一个基准时间;然后具体的时间数据都是在基准时间的基础上变化,变化的精度当然是可以优于秒的;最后在绘制坐标轴的时候,显示坐标刻度时加上精确的秒数。

相关的接口如下:

void CChart::SetAxisTimeMixMode(bool bMix, int location);

此接口需要在SetAxisToTime之后调用,表示坐标轴是混合模式。

void CChart::SetAxisDecimalTimeFormat(TCHAR *format, int location);

此接口表示混合模式的时候,小数部分的显示格式。

注意这里的format格式字符串不是参考strftime,而是参考printf这个最基本的函数。

void CChart::SetAxisTimeBase(TCHAR *strTime, TCHAR *strFmt, int location);

此接口设置时间基准。

在混合模式下,数据点的输入时最好用StringToTime这个接口获得基准时间的数值,然后再加上相应的时间偏离,作为数据值。

A56.11?对数坐标轴问题

问:我想让X轴显示对数刻度,请问可以吗?

答:CChart支持对数坐标轴,只需要调用这个接口即可。

void CChart::SetXLogarithm(bool bLog);

void CChart::SetYLogarithm(bool bLog);

当然,设置为对数坐标轴的前提是该坐标轴的所有数据都是正数,没有0或负数,不然会发生不可预计的错误。

A56.12 坐标轴反向问题

问:我想让X轴从大到小显示,请问可以吗?

答:CChart默认情况下坐标轴数据都是从小到大显示的。

CChart支持坐标轴反向,只需要调用这个接口即可。

void CChart::SetXOpposite(bool bOpposite);

void CChart::SetYOpposite(bool bOpposite);

A56.13 坐标轴浮动刻度问题

问:matlab等很多软件,其坐标轴刻度显示似乎和CChart不一样,这是怎么回事?

答:CChart在默认情况下,坐标轴的两端是有刻度的,并且刻度值是在一定程度上进行了“凑整”处理。其实大部分软件似乎都是这样处理的,只是凑整的算法不一样。

还有很多软件,包括matlab,采用了另外一种方法。这种是坐标轴的两端不一定有刻度线,刻度线是在坐标轴的内部比较“靠整”的位置显示。例如,假定坐标范围是0.5到5.5,其刻度线分别位于1、2、3、4、5这5个位置,起点和终点没有刻度线。

CChart实际上也支持这种刻度显示方式,并把这种方式称为“浮动刻度”模式,相应的接口如下:

void CChart::SetXFloatTicks(bool flt);

void CChart::SetYFloatTicks(bool flt);

A56.14 控制台程序问题

问:CChart可以在Dos程序中使用吗?

答:所谓Dos程序,在Windows中称为控制台。

CChart是一个基于Win32API的软件库,纯粹的Dos程序,CChart是不支持的。但目前应该很难找到纯粹的Dos环境。

在Windows环境里面,CChart完美支持控制台程序。

实际上,在控制台程序里,既可以弹出一个Windows窗口,用于CChart绘图,也可以让CChart直接在控制台那个黑乎乎的窗口里绘图。

本系列教程里面,有多课内容都是讲述控制台编程的,包括A33课“深入浅出CChart 每日一课——快乐高四第三十三课 叶落归根,返璞归真之控制台程序_baita96的博客-CSDN博客”、A34课“深入浅出CChart 每日一课——快乐高四第三十四课 不忘初心,Fortran控制台绘制曲线图_baita96的博客-CSDN博客_fortran绘制函数图像”、A35课“深入浅出CChart 每日一课——快乐高四第三十五课 砥砺前行,Fortran控制台绘制等高线云图_baita96的博客-CSDN博客”、A49课“深入浅出CChart 每日一课——快乐高四第四十九课 旧石器时代,老血狂喷之控制台窗口绘图_baita96的博客-CSDN博客”、A50课“深入浅出CChart 每日一课——快乐高四第五十课 新石器时代,轻装上阵之EasyX窗口绘图_baita96的博客-CSDN博客”。

重点请参考A49课。

A56.15 CChart数据量问题

问:CChart最大可以支持多少数据点?

答:理论上,CChart支持的数据点由系统的内存决定。一个数据点由两个double数据组成,共占据16Byte。因此,32位版总共大致能用2G内存,可以支持的数据点数大概是几千万个,对于64位版,则基本没有限制。试验也可以发现,32位版如果数据点达到亿量级,程序直接崩溃,而64位版则没有问题。

在实用层面,还要考虑软件的响应速度等问题,因此支持的数据点没有上面那么多。

这里要分三种情况分析。

情况1、静态图像,无消息响应。

静态图像是指图像中不需要动态增删数据点。

在这种情况下,CChart支持的数据点可以达到理论上那么多。基本上,支持千万量级数据点是没有问题的,64位版甚至可以支持10亿、百亿。当然,数据点太多,您在程序开始读入数据的时候要花较长的时间。

情况2、静态图像,有消息响应。

这种情况下,由于消息响应时图像可能需要重绘,大数据量时重绘也比较耗时。

CChart对这种情况下的重绘进行了优化,如果数据量为几百万,同时图像不改变大小,一般情况下重绘时间不会超过1秒,这是可以接受的。

如果图像大小改变,重绘时间会长一些。只要不是经常发生,我们认为改变图像大小的情况可以忽略。

因此,在这种情况下,CChart支持的数据量大概为百万量级。

情况3、动态图像。

动态图像是指图像中不断增删数据点。

这种情况下,一般数据量达到10万,可能就能感觉到一些卡顿了。

因此,此时CChart支持的数据量大概为十万量级。

作为一款免费开源软件,CChart能达到这个水平,笨笨已经做了很大努力。

这里对比一款商业软件ProEssentials的情况。ProEssentials有三种版本:Pro、Standard和Lite。Pro版是最完整的版本,开发无任何限制;Standard版最多支持8000个数据点和800个注释;Lite版支持1000个数据点和100个注释。可以看到,如果不买最贵的Pro版,您花了钱还受到了很多限制。同时笨笨认为,大量数据点主要用于曲线图绘制,单就曲线图绘制来看,CChart的功能并不比ProEssentials弱。当然其它类型的图像的确不是CChart的强项。

为了提高大数据量时的性能,笨笨在CChart的基础上,专门开发了一个拓展库,名为CHugeChart,这个库在千万数据量的情况下,无论是键盘鼠标消息还是增删数据,响应都很丝滑,也有朋友把这个库用到了项目中,反应良好。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-06-25 17:54:42  更:2022-06-25 17:54:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 15:28:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码