MFC消息映射浅谈(二)

前面一文中,可以看到,处理消息的窗口函数是一个switch-case结构,当然这不是处理多分支程序的唯一结构。下面将会给出一种更模块化的结构。

首先,为了使Windows SDK程序结构更清晰,利用C函数把程序模块化,对Windows程序进行封装。

程序代码可按如下设计:

#include<windows.h>

//定义全局变量--------------------------------------------------------------------------------

HINSTANCE        hInst;    

HWND             hWnd;        

MSG            msg;

char lpszClassName[]="窗口";

char*ShowText;

//声明函数原型--------------------------------------------------------------------------------------

ATOM            MyRegisterClass(HINSTANCE hInstance);//注册窗口类函数

BOOL            Create(HINSTANCE, int);              //程序实例初始化函数

int                Run();                            //消息循环函数

LRESULT CALLBACK    WndProc(HWND, UINT,   

WPARAM, LPARAM);                      //窗口函数

void OnLButtonDown(HWND hWnd, UINT message, 

                WPARAM wParam, LPARAM lParam);

void OnPaint(HWND hWnd, UINT message, 

                WPARAM wParam, LPARAM lParam);

void OnDestroy(HWND hWnd, UINT message, 

                WPARAM wParam, LPARAM lParam);

//主函数-----------------------------------------------------------------------------------------

int APIENTRY WinMain(HINSTANCE hInstance,

                     HINSTANCE hPrevInstance,

                     LPSTR     lpCmdLine,

                     int       nCmdShow)

{

    

    MyRegisterClass(hInstance);                  //定义和注册窗口类

    Create(hInstance, nCmdShow);                //创建窗口

    ShowWindow(hWnd, nCmdShow);                //显示窗口

    UpdateWindow(hWnd);                        //更新屏幕显示

    return Run();                                    //消息循环

}

//注册窗口类函数的实现--------------------------------------------------------------------------

ATOM MyRegisterClass(HINSTANCE hInstance)

{

    WNDCLASS wc;

    wc.style=0;

    wc.lpfnWndProc=WndProc;

    wc.cbClsExtra=0;

    wc.cbWndExtra=0;

    wc.hInstance=hInstance;

    wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);

    wc.hCursor=LoadCursor(NULL,IDC_ARROW);

    wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

    wc.lpszMenuName=NULL;

    wc.lpszClassName=lpszClassName;

    return RegisterClass(&wc);

}

//创建窗口函数的实现-----------------------------------------------------------------------------

BOOL Create(HINSTANCE hInstance, int nCmdShow)

{

    hWnd=CreateWindow(    lpszClassName,

                        "Windows",

                        WS_OVERLAPPEDWINDOW,

                        400,300,180,160,

                        NULL,

                        NULL,

                        hInstance,

                        NULL);

   return TRUE;

}

//消息循环函数的实现-----------------------------------------------------------------------------

int Run( )

{

    while (GetMessage(&msg, NULL, 0, 0)) 

    {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

    return msg.wParam;

}

//窗口函数的实现--------------------------------------------------------------------------------------

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, 

WPARAM wParam, LPARAM lParam)

{

    switch (message) 

    {

    case WM_LBUTTONDOWN:    OnLButtonDown(hWnd, message, wParam, lParam);    

        break;

    case WM_PAINT:            OnPaint(hWnd, message,wParam, lParam);

        break;

    case WM_DESTROY:        OnDestroy(hWnd, message, wParam, lParam);

        break;

    default:

        return DefWindowProc(hWnd, message, wParam, lParam);

   }

   return 0;

}

void OnLButtonDown(HWND hWnd, UINT message, 

                WPARAM wParam, LPARAM lParam)

{

    ShowText="Hello!";

    InvalidateRect(hWnd,NULL,1);

}

void OnPaint(HWND hWnd, UINT message, 

                WPARAM wParam, LPARAM lParam)

{

    PAINTSTRUCT ps;

    HDC hdc;

    hdc = BeginPaint(hWnd, &ps);

    TextOut(hdc,50,50,ShowText,6);

    EndPaint(hWnd, &ps);

}

void OnDestroy(HWND hWnd, UINT message, 

                WPARAM wParam, LPARAM lParam)

{

    PostQuitMessage(0);

}

从上面代码可以看出,程序由两大部分组成:主函数部分和窗口函数部分。主函数由五个函数组成,窗口函数由四个函数组成。这样使得程序的结构更见清晰。

上面随实现了部分功能,但并没有从根本上处理消息处理,下面展示一种接近MFC的处理过程。

1.先把各个消息处理程序封装成函数,制作一个如图1-1的消息与消息处理函数之间的对应关系,这个表可以叫做消息映射表。

消息标示         消息处理函数      
WM_LBUTTONDOWN   On_LButtonDown
WM_PAINT On_Paint
WM_RESTROY On_Restroy

图1-1 消息映射表

在程序中,可以用数组或者链表来实现这个表,这里简单用数组实现,然后设计数组结构如下:

struct MSGMAP_ENTRY

{

    UINT nMessage;                //消息标示

    void (*pfn)(HWND, UINT, WPARAM, LPARAM);  //消息处理函数指针

};

于是,作为消息映射表的数组应该为:

struct MSGMAP_ENTRY messageEntres[] = 

{

    WM_LBUTTONDOWN, On_LButtonDown,

    WM_PAINT,       On_Paint,

    WM_DESTROY,     On_Destroy,

};

2.这样窗口函数就可以这样设计:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

    int i;

    int n = sizeof (messageEntres) / sizeof(messageEntres[0]);

    for (i = 0; i < n; i ++)

    {

        if (message == messageEntres[i].nMessage)

            (*messageEntres[i].pfn)(hWnd, message, wParam, lParam);

    }



    return DefWindowProc(hWnd, message, wParam, lParam);



}

这样,无论需要处理多少消息,窗口函数的结构都被固定成这种格式。于是就可以再编程是自动产生这个函数,而用户所需要做的工作就是编写消息处理函数,并按上面消息结构将消息和消息处理函数填入MSGMAP_ENTRY中。

为了使程序结构更接近MFC,我们一步步进行处理,将这些消息处理定义为宏。这样代码将如下:

//头文件

#ifndef MYWINDOWS

#define MYWINDOWS

#include <Windows.h>



struct MSGMAP_ENTRY

{

    UINT nMessage;

    void (*pfn)(HWND, UINT, WPARAM, LPARAM);

};



ATOM MyRegisterClass(HINSTANCE hInstance);

HWND Create(HINSTANCE, int);

int    Run();

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

void On_LButtonDown(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

void On_Paint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

void On_Destroy(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);



#define DECLARE_MESSAGE_MAP() \

struct MSGMAP_ENTRY messageEntres[]; \



#define BEGIN_MESSAGE_MAP() \

struct MSGMAP_ENTRY messageEntres[] = \

{ \



#define ON_WM(messageID, msgFuc) \

    messageID, msgFuc, 

#define END_MESSAGE_MAP() \

}; \





#endif
//实现文件



#include "feizhuang.h"



MSG    msg;

char lpszClassName[] = "窗口";

char *ShowText;

HINSTANCE hInstance;

HWND hWnd;



//声明消息映射表

DECLARE_MESSAGE_MAP()
//实现消息映射表 BEGIN_MESSAGE_MAP() ON_WM(WM_LBUTTONDOWN, On_LButtonDown) ON_WM(WM_PAINT, On_Paint) ON_WM(WM_DESTROY, On_Destroy) END_MESSAGE_MAP() ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASS wc; wc.style
= 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL,IDI_APPLICATION); wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = lpszClassName; return RegisterClass(&wc); } HWND Create(HINSTANCE hInstance, int nCmdShow) { hWnd = CreateWindow(lpszClassName, "Windows", WS_OVERLAPPEDWINDOW, 400,300,500,500, NULL, NULL, hInstance, NULL); return hWnd; } int Run() { while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {

   int i;
    int n = sizeof (messageEntres) / sizeof(messageEntres[0]);
   for (i = 0; i < n; i ++)
   {
     if (message == messageEntres[i].nMessage)
      (*messageEntres[i].pfn)(hWnd, message, wParam, lParam);
     }

     return DefWindowProc(hWnd, message, wParam, lParam);

}



void On_LButtonDown(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

    ShowText = "Hello!";

    InvalidateRect(hWnd,NULL,1);

}



void On_Paint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

    PAINTSTRUCT ps;

    HDC hdc;

    hdc = BeginPaint(hWnd, &ps);

    TextOut(hdc, 50, 50, ShowText, 6);

    EndPaint(hWnd, &ps);

}



void On_Destroy(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

    PostQuitMessage(0);

}

下一篇,可以使用C++特性将这些处理封装成类。

 

 

 

你可能感兴趣的:(mfc)