MFC 自定义消息
2012-01-28 15:12 捣乱小子 阅读(2817) 评论(1) 编辑 收藏 举报WIN32编程回忆
在MFC中,听得最多的莫过于“消息”这词,透彻理解MFC的消息机制对学习MFC大有裨益。
依稀记得,在纯C的win32编程中,写的最多就是WinMain和win消息处理函数, 我当时有个模板,每每建立一个win32的工程,我就把他复制进去,大概的如下:
#define CLSNAME ""
#define WNDNAME ""
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR szCmdLine,
int iCmdShow)
{
static TCHAR clsname[] = TEXT(CLSNAME);
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WindowProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = clsname ;
if(!::RegisterClass(&wndclass))
{
MessageBox ( NULL,
TEXT ("This program requires Windows NT!"),
clsname,
MB_ICONERROR) ;
return 0 ;
}
HWND hwnd;
hwnd = ::CreateWindow(clsname,TEXT(WNDNAME),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
::ShowWindow(hwnd,SW_SHOW);
::UpdateWindow(hwnd);
MSG msg;
while(::GetMessage(&msg,NULL,0,0)){
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
HDC hdc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
switch(uMsg)
{
case WM_DESTROY:
::PostQuitMessage(0);
return 0;
case WM_PAINT:
hdc = ::BeginPaint(hwnd,&ps);
::EndPaint(hwnd,&ps);
return 0;
}
return ::DefWindowProc(hwnd,uMsg,wParam,lParam);
}
为了偷懒,就把窗口类名CLSNAME和窗口标题WNDNAME直接在文件头部define(定义),阅读过《windows程序设计》都应该这样偷懒过。WinMain主函数里面的东西也不用怎么改,像上面原样照搬没有多大的问题,除非要修改窗口类的属性。需要大动干戈的地方,在WindowProc里,这里才是实现你编程梦想的地方。switch语法在展现的淋漓尽致,每个case都是一个windows消息,所以用一句话说明白:windows编程就是基于消息传递的,而消息的传递是有系统负责的,我们负责的是如何去响应系统发出的消息,也就是编写消息响应函数 。
MFC的思想很类似,不过MFC结合了C++,所以MFC的消息机制比起win32编程,会复杂的多,这也让一个很普遍的现象很直观:市面上的很多关于MFC教程的书籍,都对MFC的消息机制一笔带过,能减则减;他们最最擅长就是拖控件。
MFC自定义窗口消息
在winuser.h头文件中定义了这些消息,但是总有不尽人意的地方,这些消息满足不了我们。MFC有给我们留后路,在winuser.h中WM_USER被定义为0x0400,意味着我们可以定义自己的消息。
根据以下步骤可以定义一般的消息:
-
定义消息的标号。就像我们经常看到的WM_PAINT等消息一样,他们实际上都有一个标号,#define赋予他们这些标号。#define WM_MY_MESSAGE1 WM_USER+0
#define WM_MY_MESSAGE2 WM_USER+1#define WM_USER 0x0400 -
添加消息映射函数。这个消息映射函数有一定的规格,MSDN上有硬性的规定:并且在这些函数的定义实现中实现响应的过程。
The type of the function must be afx_msg LRESULT (CWnd::*)(WPARAM, LPARAM).也就是说你的消息响应函数也必须写成是这种形式。因此你的窗口类中必须声明下面的函数原型,函数名可以自由变通,
afx_msg LRESULT OnMyMessage1(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnMyMessage2(WPARAM wParam, LPARAM lParam);
-
在消息映射表BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()之间添加消息和消息处理函数的映射。用到了MFC当中的一个宏,ON_MESSAGE(message, memberFxn) ,message是定义的消息,而memberFxn就是消息响应函数,因此:ON_MESSAGE(WM_MY_MESSAGE1,OnMyMessage1)
ON_MESSAGE(WM_MY_MESSAGE2,OnMyMessage2) -
窗口与窗口之间实现通信:::SendMessage(hWnd,WM_MY_MESSAGE1,0,0);
::SendMessage(hWnd,WM_MY_MESSAGE2,0,0);
这种消息机制可以带来很多的好处,方便实现窗口与窗口之间的通信,特别当两个窗口是父子关系的时候,也就是说一个窗口从属于另一个窗口。子窗口可以在任意时刻通过SendMessage来向父窗口发送消息。
捣乱小子 2012年1月28日星期六