MFC 自定义消息

WIN32编程回忆

在MFC中,听得最多的莫过于“消息”这词,透彻理解MFC的消息机制对学习MFC大有裨益。

依稀记得,在纯C的win32编程中,写的最多就是WinMain和win消息处理函数, 我当时有个模板,每每建立一个win32的工程,我就把他复制进去,大概的如下:

#include <windows.h>

#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日星期六

 

 

原文地址:https://www.cnblogs.com/daoluanxiaozi/p/2330527.html