深入浅出CChart 每日一课——快乐高四第十八课 旧貌换新颜,锦上添花之自定义消息响应

CChart编程非常灵活。前面高四第四课介绍了插件菜单,第五课介绍了客户区自绘,本节课笨笨来介绍另一种可以自定义的因素,那就是——消息响应!

首先看看下列函数。

// 用户自定义鼠标移动前操作,返回true跳过默认例程
void		SetPreMouseMoveFunc(bool	(*fcnPreMouseMove)( void *plot, HDC hDC, POINT point, UINT ctrlKey, void *para, bool &bContinue ), void *pPara);
// 用户自定义鼠标单击前操作,返回true跳过默认例程
void		SetPreLButtonDownFunc(bool	(*fcnPreLButtonDown)( void *plot, HDC hDC, POINT point, UINT ctrlKey, void *para, bool &bContinue ), void *pPara);
// 用户自定义鼠标抬起前操作,返回true跳过默认例程
void		SetPreLButtonUpFunc(bool	(*fcnPreLButtonUp)( void *plot, HDC hDC, POINT point, UINT ctrlKey, void *para, bool &bContinue ), void *pPara);
// 用户自定义鼠标双击前操作,返回true跳过默认例程
void		SetPreLButtonDblClkFunc(bool	(*fcnPreLButtonDblClk)( void *plot, HDC hDC, POINT point, UINT ctrlKey, void *para, bool &bContinue ), void *pPara);
// 用户自定义按键前操作,返回true跳过默认例程
	void		SetPreKeyDownFunc(bool	(*fcnPreKeyDown)( void *plot, HDC hDC, UINT key, void *para, bool &bContinue ), void *pPara);

// 用户自定义鼠标移动后操作,返回值没有关系
void		SetPostMouseMoveFunc(bool	(*fcnPostMouseMove)( void *plot, HDC hDC, POINT point, UINT ctrlKey, void *para, bool &bContinue ), void *pPara);
// 用户自定义鼠标单击后操作,返回值没有关系
void		SetPostLButtonDownFunc(bool	(*fcnPostLButtonDown)( void *plot, HDC hDC, POINT point, UINT ctrlKey, void *para, bool &bContinue ), void *pPara);
// 用户自定义鼠标抬起后操作,返回值没有关系
void		SetPostLButtonUpFunc(bool	(*fcnPostLButtonUp)( void *plot, HDC hDC, POINT point, UINT ctrlKey, void *para, bool &bContinue ), void *pPara);
// 用户自定义鼠标双击后操作,返回值没有关系
void		SetPostLButtonDblClkFunc(bool	(*fcnPostLButtonDblClk)( void *plot, HDC hDC, POINT point, UINT ctrlKey, void *para, bool &bContinue ), void *pPara);
// 用户自定义按键后操作,返回值没有关系
void		SetPostKeyDownFunc(bool	(*fcnPreKeyDown)( void *plot, HDC hDC, UINT key, void *para, bool &bContinue ), void *pPara);

这里共有10个函数。分别处理WM_LBUTTONDOWN、WM_LBUTTONUP、WM_LBUTTONDBLCLK、WM_MOUSEMOVE、WM_KEYDOWN这五个消息,每个消息可以设置两个处理函数,分别处理消息开始和消息结束的动作。

这10个函数的参数都是两个,第一个是函数指针,第二个是准备传递给函数指针的参数。

函数指针的格式如下:

bool	(*fcnMouseFunc)( void *plot, HDC hDC, POINT point, UINT ctrlKey, void *para, bool &bContinue );
bool	(*fcnKeyFunc)( void *plot, HDC hDC, UINT ctrlKey, void *para, bool &bContinue );

这个函数的参数里,plot是保留参数,不管;hDC是绘图设备环境;point是鼠标位置;ctrlKey是按键值;para用于接收外部传入的指针;bContinue表示是否把消息往后传递,以便系统继续处理。

下面先建立一个和第一课一模一样的程序。

下面我们让程序的状态栏显示鼠标的坐标和数据信息。

首先需要创建一个状态栏。

添加一个HWND变量,和一个函数。

HWND hWndStatus;
HWND CreateStatusBar(HWND hParentWnd)
{
	const int PANEL_NUM = 3;
  int array[PANEL_NUM]={400,500,-1};
  HINSTANCE hInst = GetModuleHandle(NULL);
  //创建Statusbar控件
  HWND hWndStatus = CreateWindowEx(0, STATUSCLASSNAME, TEXT(""), WS_CHILD|WS_BORDER|WS_VISIBLE, 0, 0, 0, 0, hParentWnd, (HMENU)IDC_STATUSBAR, hInst, NULL);
  if (hWndStatus)
  {
SendMessage(hWndStatus,SB_SETPARTS,(WPARAM)PANEL_NUM,(LPARAM)array); //设置面板个数
SendMessage(hWndStatus,SB_SETTEXT,(LPARAM)1,(WPARAM)TEXT("欢迎使用")); //设置第二个面板内容
SendMessage(hWndStatus,SB_SETTEXT,(LPARAM)2,(WPARAM)TEXT("CChart数据可视化软件库")); //设置第三个面板内容
  }
  return hWndStatus;
}

然后在WM_Create消息里添加一句:

hWndStatus = CreateStatusBar(hWnd);

现在的问题是状态栏的位置和CChart的绘图有冲突。

为解决这个问题,修改一下Attach的方式:

GetWindowRect(hWndStatus, &rct1);
GetClientRect(hWnd, &rect);
rect.bottom -= (rct1.bottom-rct1.top);
chartWnd.Attach(hWnd, rect, kTypeXY);

这里需要在前面定义两个RECT变量。

RECT rect, rct1;

同时响应一下WM_SIZE消息:

case WM_SIZE:
		SendMessage(hWndStatus, WM_SIZE, 0, 0);
		GetWindowRect(hWndStatus, &rct1);
		GetClientRect(hWnd, &rect);
		rect.bottom -= (rct1.bottom-rct1.top);
		chartWnd.GetChart()->SetConfineRect(rect);
		break;

有同学要问了,Attach之后,消息不都是被接管了吗?这里怎么还能响应WM_SIZE消息呢?

说的没错!但实际上CChartWnd只处理了少量必要消息,其余消息仍然传递出来了的!

现在显示正常了。

下面创建一个响应WM_MOUSEMOVE的函数。

bool	PreMouseMove( void *plot, HDC hDC, POINT point, UINT ctrlKey, void *pPara, bool &bContinue )
{
	if(!pPara)return false;
	
	CChart *pChart = (CChart *)pPara;
	
	RECT plotRect = pChart->GetLastPlotRect();
	if(!PtInRect(&plotRect, point))return false;
	
	double data[2];
	pChart->ClientToData(&point, data);

	TCHAR str[64];
	_stprintf(str, _T("鼠标位置在(%d, %d), 对应的数据值是(%g, %g)"), point.x, point.y, data[0], data[1] );
	SendMessage(hWndStatus,SB_SETTEXT,(LPARAM)0,(WPARAM)str); //设置第一个面板内容
	
	return true;
}

注意这里的参数,plot指针是保留参数;hDC是绘图设备环境;point是鼠标位置;ctrlKey是按键信息;pPara指针是关键参数,我们从这里传入了一个CChart类指针,这才获得了绘图的相关数据;bContinue表示消息是否继续传递。

下面在WM_CREATE消息里面把上面这个函数插入到CChart的消息响应序列里。

chartWnd.GetChart()->SetPreMouseMoveFunc(&PreMouseMove, chartWnd.GetChart());

注意到,这里用SetPreMouseMoveFunc的第二个参数,把CChart的指针传递给了PreMouseMove函数。

好了,看看效果吧!

正如我们设计的,在状态栏的第一个窗格里面,显示了鼠标位置信息和相应的数据信息。

同学们可以试试看在PreMouseMove函数把bContinue设置成false会怎么样。

好了,这节课介绍了消息响应的自定义方法,下节课将重磅推出CChart的子类化编程,进行更彻底的自定义,敬请期待。

猜你喜欢

转载自blog.csdn.net/baita96/article/details/88761356