CChart的交互功能很强,笨笨一向引为自豪。交互功能的一个重要组成部分就是右键菜单。
同学们试一试就能知道,CChart的右键菜单功能是非常丰富的。尤其是还有很多功能在包装类中暂时还没有,只能在右键菜单或对话框中使用。
虽然默认的右键菜单功能已经令笨笨自己满意了,但不见得能让所有的人满意。怎么办呢?那就需要用户自己定制。
定制的方法有两种。
一种方法是革命性的的,那就是把默认的菜单全部替换掉。这个想法非常非常好,但是看起来好像不那么容易,是不是要改源码呀?Oh,NO。完全不需要,笨笨已经贴心地为大家提供了子类化功能。子类化不仅可以修改右键菜单,也可以改变默认的消息响应,甚至显示的图像也可以完全按要求定制。关于子类化功能,以后会专门介绍。
另一种方法那就是康有为、梁启超的办法,改良,君主立宪,不修改默认菜单,而是往菜单里面添加新的菜单项。这个看起来似乎更难了,真的是这样吗?
(注:CChart4.8.0.3版本已经增加了一个接口函数,不用子类化也可以完全替换右键菜单,见本节课后续内容。)
下面笨笨就给大家介绍第二种方法,在右键菜单中增添插件菜单。
第一步,按照第一课的方法建立一个工程,名为LessonA04,具体步骤不再详述。同时按第二课的介绍,激活鼠标双击功能。
第二步,定义一个菜单的标识ID。
既然是菜单,就必然有ID。
在WndProc函数的上面定义菜单ID,代码如下。
const int menuID = 40000;
这里定义的ID比较大,是为了避免和CChart默认菜单的ID冲突。一般大于32768即可,当然不能大于65535。
第三步,编写建立插件菜单项的函数。
void AddPluginMenu( void *plot, HMENU addMenu )
{
AppendMenu(addMenu, MF_SEPARATOR, 0, (LPCTSTR)0 );
AppendMenu(addMenu, MF_STRING, menuID, _TEXT("附加菜单项1"));
HMENU subMenu = CreatePopupMenu();
AppendMenu(subMenu, MF_STRING, menuID+1, _TEXT("附加菜单项2"));
AppendMenu(addMenu, MF_POPUP, (UINT) subMenu, _TEXT("附加弹出项"));
DestroyMenu(subMenu);
}
注意函数的形式,包括参数和返回值必须和上面一模一样,否则程序崩溃莫得商量。
可以看见,上面的代码实际增加了两个菜单项,ID分别是menuID和menuID+1,名字分别为“附加菜单项1”和“附加菜单项2”,其中第二个菜单项是放在一个弹出菜单“附加弹出项”中的。
这一套完全是Win32API的玩法,CChart内部所有的右键菜单都是这么做出来的。
第四步,建立菜单项的处理函数。
int IntPluginMenu( void *plot, HWND hWnd, int result )
{
CChart *pChart = (CChart *)plot;
if(result == menuID)
{
const TCHAR *title = pChart->GetTitle();
TCHAR str[128];
_stprintf(str, _T("图像标题为:%s"), title);
MessageBox(hWnd, str, _T("附加菜单"), MB_OK);
return -3;
}
else if(result == menuID + 1)
{
static int count = 4;
pChart->AddPoint2D((double)count, (double)count*count);
count++;
return -3;
}
return -2;
}
(注:CChart 4.8.0.3以前的版本,由于一个小Bug,GetTitle函数总是返回空字符串,上述代码工作不正常。目前已修订。)
注意上面的代码中,把一个void*指针转换成了我们需要的CChart*指针,有了这个CChart*指针,我们想干啥就可以干啥了,上面第一个菜单项获取了图像标题并显示在消息框里,第二个菜单项在屏幕的曲线上增加一个数据点。真的是很方便呀。
那么,这个指针是从哪里来的呢?别慌,答案在第五步。
还有这里返回值的含义,-3表示更新视图,-2表示不动作,-1表示出错。
由于使用了sprintf,需要在LessonA04.cpp的头部附近增加一行。
#include <stdio.h>
第五步,在WM_CREATE的处理例程中增加一行。
chartWnd.GetChart()->SetPluginMenu(AddPluginMenu, IntPluginMenu, chartWnd.GetChart());
注意了,SetPluginMenu有三个参数,前两个参数就是前两步编写的那两个函数,分别建立菜单和处理菜单。特别要注意第三个参数了。看到了吧,这里传进去就是一个CChart*指针。
大家要小心,如果那两个函数定义的方式(包括返回值和形参)不对,或者第三个参数传递不匹配,程序崩溃无商量。
OK,大功告成。
为了确认大家的代码和笨笨的一样,请检查WM_CREATE处理例程是不是下面这样的。
case WM_CREATE:
chartWnd.Attach(hWnd, kTypeXY);
chartWnd.GetChart()->SetPluginMenu(AddPluginMenu, IntPluginMenu, chartWnd.GetChart());
chartWnd.GetChart()->AddPoint2D(-3.0, 9.0);
chartWnd.GetChart()->AddPoint2D(-2.0, 4.0);
chartWnd.GetChart()->AddPoint2D(-1.0, 1.0);
chartWnd.GetChart()->AddPoint2D(0.0, 0.0);
chartWnd.GetChart()->AddPoint2D(1.0, 1.0);
chartWnd.GetChart()->AddPoint2D(2.0, 4.0);
chartWnd.GetChart()->AddPoint2D(3.0, 9.0);
chartWnd.GetChart()->SetTitle(_T("Hello World,我的第一个CChart程序!"));
break;
这段代码主要就是从第一课拷贝过来的,呵呵。
下面看看劳动成果。
大家可以看看两个新菜单项的功能是不是如我们所愿。如果有所差别,肯定是上面的代码写得不一样了,呵呵。
如果我们只想显示新菜单,不想显示默认的菜单项,也就是完全替换右键菜单,可以实现吗?
完全可以!新版CChart贴心地提供了一个简单的接口。
在上面的代码中,SetPluginMenu的附近,增加下面一行:
chartWnd.GetChart()->SetPluginMenuOnly(true);
这时结果如下:
可以看到,现在右键菜单只有我们添加的项了。
本节课笨笨给大家介绍了CChart的插件菜单功能,这个功能可能不见得能有多实用,但可以展示CChart的强大内核。
下一课笨笨将介绍一个非常实用的功能——客户区自绘,改变CChart的默认显示状态。这个功能应该在非常多的场合都能用到,敬请期待。
提请注意,请到www.cchart.net网站下载最新版本的CChart。旧版本不保证能实现本节课的功能。