Windows程序是事件驱动的,操作系统将每个事件记录在一条消息中。Windows程序必须包含专门处理这些消息的函数。在VC下,消息响应函数一般是通过找到相应的message,添加现成的消息相应函数实现的。但至少两种情况下,无法实现这样的处理。1、系统没有你需要的这种消息;2、产生消息和处理消息不在同一个线程里。比如你想在CView类里处理一条在CFrame类里产生的Edit控件发生改变的消息,并得到Edit中的文本内容。通常是利用GetWindowText ()函数来实现,但是这个函数GetWindowText cannot retrieve the text of a control in another application.
这时我们就可以利用SendMessage()函数从框架里发送消息,然后在视图中接收并处理。函数原型为:
LRESULT SendMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);
其中hWnd :Handle to the window whose window procedure will receive the message.就是目标视图CView的句柄。
Msg: Specifies the message to be sent.
wParam:Specifies additional message-specific information.
lParam: Specifies additional message-specific information.
Msg是消息类型,可以是自定义的和。wParam和lParam是消息的附加信息。
这样,我们首先要做的,就是在框架里得到目标视图的句柄。
view类属于框架管理的窗口类,构造函数是受保护的,无法直接创建实例。即使要在框架类里使用试图类对象的功能,也应该定义一个指针,并为其赋值。即先通过AfxGetMainWnd()函数获得主框架的指针pMainFrame, 然后从pMainFrame->GetActiveView()得到当前视图的指针(如果是SDI的话)。有了当前视图指针,就可以利用这个指针调用SendMessage()函数。注意,这时调用的SendMessage只有三个参数:Msg、wParam和lParam。默认句柄为调用该函数的指针所带句柄,即当前视图句柄。语句如下:
CMainFrame* pMainFrame = dynamic_cast<CMainFrame*>(::AfxGetMainWnd());
if (pMainFrame != NULL)
{
CGLEasyView *pIFView = dynamic_cast<CGLEasyView*>(pMainFrame->GetActiveView());
pIFView->SendMessageA(WM_INTEGRATION_TIME_CHANGE, 0L, 0L);
}
这里利用了类和类的指针间转化用的C++风格转化符dynamic_cast。
其中WM_INTEGRATION_TIME_CHANGE就是自定义的消息,需要在视图类头文件里添加宏定义
#define WM_INTEGRATION_TIME_CHANGE WM_USER+1
当然,如有更多的自定义消息,也可接着
#define WM_YOUR_MESSAGE WM_USER+2
然后,在框架类的cpp文件中添加包含视图类头文件,我这里是
#include "gleasvw.h"
这时如果编译的话,会出现类似以下编译错误。
error C2065: 'CGLEasyDoc' : undeclared identifier
说明文档类未知。这时需要在视图类头文件中包含文档类,由于这不是继承关系,而且是互相包含,所以,在视图类头文件中要以声明的方式取代头文件包含,添加这样一条语句以加入文档类:
class CGLEasyDoc;
具体可参见reference webpages中的“C++中基础类互相引用带来的问题”。这样就告诉编译器,这是文档类的一个实际调用,不用再次进行包含和编译。
此时,发消息的工作完成,该做消息接受处理的工作。
消息处理函数经常被称作WndProc()或WindowProc(),不过该函数不必拥有特定的名称,因为Windows是利用我们提供的函数指针访问该函数的。所以这里有两种方法进行消息接收处理。
一、重写WindowProc虚函数,即首先在视图类头文件中添加声明:
protected:
virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam);
然后在cpp文件中加入该虚函数的实现:
LRESULT CGLEasyView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INTEGRATION_TIME_CHANGE:
//add your code here
return 0;
default:
LRESULT lResult = 0;
if (!OnWndMsg(message, wParam, lParam, & lResult))
lResult = DefWindowProc(message, wParam, lParam);
return lResult;
}
}
这里要注意,在我们筛选自己要处理的消息后,记着把其余消息回传给Windows,仍以其原来默认的方式去处理,否则将发现应用程序没有了诸如最小化、响应鼠标等功能。这是靠调用DefWindowProc()函数实现的。即上段代码中的
lResult = DefWindowProc(message, wParam, lParam);
二、或者用第二种方法,自己添加消息响应函数。先在视图类头文件中声明消息响应函数:
protected:
//{{AFX_MSG(CGLEasyView)
afx_msg LRESULT IntegrationTimeChange(WPARAM wParam,LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
然后在视图类cpp文件中BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间插入以下代码
BEGIN_MESSAGE_MAP(CGLEasyView, CView)
//{{AFX_MSG_MAP(CGLEasyView)
//指定自定义消息WM_INTEGRATION_TIME_CHANGE的消息响应函数指针
ON_MESSAGE(WM_INTEGRATION_TIME_CHANGE,IntegrationTimeChange)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
最后在视图类cpp文件中添加函数定义即可:
LRESULT CGLEasyView::IntegrationTimeChange(WPARAM wParam,LPARAM lParam)
{
//add your code here
return 0;
}
Reference webpages:
SDI中如何获得视图VIEW的句柄?http://topic.csdn.net/t/20040908/09/3350490.html
在MFC类中各种类的指针的获取和应用: http://www.chinaitpower.com/A/2005-04-26/133533.html
MDI中使用GetActiveView:http://topic.csdn.net/t/20060222/09/4569740.html
http://topic.csdn.net/t/20020328/16/606708.html
如何使用SendMessage自定义消息函数:http://winterisnotcold.blog.hexun.com/30151239_d.html
C++中基础类互相引用带来的问题:http://blog.csdn.net/sumless/articles/855694.aspx
对于VC++中的头文件包含值得注意的一点:http://blog.csdn.net/sumless/archive/2006/05/07/711965.aspx