也说MFC消息响应机制
来源:互联网 发布:windows 显卡切换 编辑:程序博客网 时间:2024/04/25 03:24
【问题描述】MFC是C++的经典框架,基于消息响应机制。网上介绍MFC消息响应的文章很多。而我认为,是否理解MFC,有一点很重要,那就是看能否脱离界面编辑器,编写对话框的代码。本文介绍两个方面:
(1)如何利用代码编写对话框;
(2)消息映射如何实现。
【解析】
1 利用代码编写对话框
先看代码:
main.cpp
#include "stdafx.h"#include "resource.h"#include "tchar.h"#define MAX_LOADSTRING 100// Global Variables:HINSTANCE hInst;// current instanceTCHAR szTitle[MAX_LOADSTRING];// The title bar textTCHAR szWindowClass[MAX_LOADSTRING];// The title bar text// Foward declarations of functions included in this code module:ATOMMyRegisterClass(HINSTANCE hInstance);BOOLInitInstance(HINSTANCE, int);LRESULT CALLBACKWndProc(HWND, UINT, WPARAM, LPARAM);LRESULT CALLBACKAbout(HWND, UINT, WPARAM, LPARAM);int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){// TODO: Place code here.MSG msg;HACCEL hAccelTable;// Initialize global stringsLoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadString(hInstance, IDC_BTNTEST, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);// Perform application initialization:if (!InitInstance (hInstance, nCmdShow)) {return FALSE;}hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_BTNTEST);// Main message loop:while (GetMessage(&msg, NULL, 0, 0)) {if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {TranslateMessage(&msg);DispatchMessage(&msg);}}return msg.wParam;}//// FUNCTION: MyRegisterClass()//// PURPOSE: Registers the window class.//// COMMENTS://// This function and its usage is only necessary if you want this code// to be compatible with Win32 systems prior to the 'RegisterClassEx'// function that was added to Windows 95. It is important to call this function// so that the application will get 'well formed' small icons associated// with it.//ATOM MyRegisterClass(HINSTANCE hInstance){WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX); wcex.style= CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc= (WNDPROC)WndProc;wcex.cbClsExtra= 0;wcex.cbWndExtra= 0;wcex.hInstance= hInstance;wcex.hIcon= LoadIcon(hInstance, (LPCTSTR)IDI_BTNTEST);wcex.hCursor= LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName= (LPCSTR)IDC_BTNTEST;wcex.lpszClassName= szWindowClass;wcex.hIconSm= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);return RegisterClassEx(&wcex);}//// FUNCTION: InitInstance(HANDLE, int)//// PURPOSE: Saves instance handle and creates main window//// COMMENTS://// In this function, we save the instance handle in a global variable and// create and display the main program window.//BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){HWND hWnd;hInst = hInstance; // Store instance handle in our global variable//menustatic HMENU hMenu,hMenuPop1,hMenuPop2;hMenu = CreateMenu();hMenuPop1 = CreateMenu();hMenuPop2 = CreateMenu();AppendMenu(hMenuPop1, MF_STRING, IDM_TEST, "&测试");AppendMenu(hMenuPop2, MF_STRING, IDM_ABOUT, "&关于");AppendMenu(hMenuPop2, MF_STRING, IDM_EXIT, "&退出");AppendMenu(hMenu, MF_POPUP, (UINT)hMenuPop1, "&菜单1");AppendMenu(hMenu, MF_POPUP, (UINT)hMenuPop2, "&菜单2");hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, hMenu, hInstance, NULL);if (!hWnd){return FALSE;}ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return TRUE;}//// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)//// PURPOSE: Processes messages for the main window.//// WM_COMMAND- process the application menu// WM_PAINT- Paint the main window// WM_DESTROY- post a quit message and return////#define btn1 1#define btn2 2LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){int wmId, wmEvent;PAINTSTRUCT ps;HDC hdc;TCHAR szHello[MAX_LOADSTRING];LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);switch (message) {case WM_CREATE:{//buttonHWND hButton1 = CreateWindow(_T("button"), _T("Btn1"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 100, 100, 100, 30, hWnd, (HMENU)btn1, hInst, NULL);HWND hButton2 = CreateWindow(_T("button"), _T("Btn2"),WS_CHILD|WS_VISIBLE|BS_BITMAP, 100, 200, 100, 30, hWnd, (HMENU)btn2, hInst, NULL);HBITMAP hbmp=LoadBitmap(hInst,MAKEINTRESOURCE(IDB_Btn2));SendMessage(hButton2, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbmp);}break;case WM_COMMAND:wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections:switch (wmId){case btn1:MessageBox(hWnd, _T("Button1 press!"), _T("Message"), MB_OK|MB_ICONINFORMATION);break;case btn2:MessageBox(hWnd, _T("Button2,press!"), _T("Message"), MB_OK|MB_ICONINFORMATION);break;case IDM_TEST:MessageBox(hWnd, _T("菜单测试"), _T("菜单测试"), MB_OK|MB_ICONINFORMATION);break;case IDM_ABOUT:DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);break;case IDM_EXIT:DestroyWindow(hWnd);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}break;case WM_PAINT:hdc = BeginPaint(hWnd, &ps);// TODO: Add any drawing code here...RECT rt;GetClientRect(hWnd, &rt);DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);EndPaint(hWnd, &ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;}// Mesage handler for about box.LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){switch (message){case WM_INITDIALOG:return TRUE;case WM_COMMAND:if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {EndDialog(hDlg, LOWORD(wParam));return TRUE;}break;} return FALSE;}
resource.h
//{{NO_DEPENDENCIES}}// Microsoft Developer Studio generated include file.// Used by Test2.rc//#define IDS_APP_TITLE 1#define IDC_BTNTEST 2#define IDS_HELLO 3#define IDI_BTNTEST 101#define IDI_SMALL 102#define IDD_ABOUTBOX 103#define IDR_MENU1 110#define IDB_Btn2 201#define IDM_ABOUT 1001#define IDM_EXIT 1002#define IDM_TEST1003// Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE 113#define _APS_NEXT_COMMAND_VALUE 40001#define _APS_NEXT_CONTROL_VALUE 1000#define _APS_NEXT_SYMED_VALUE 101#endif#endif
实现步骤如下所述:
(1)设计窗口类
WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX); wcex.style= CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc= (WNDPROC)WndProc;wcex.cbClsExtra= 0;wcex.cbWndExtra= 0;wcex.hInstance= hInstance;wcex.hIcon= LoadIcon(hInstance, (LPCTSTR)IDI_BTNTEST);wcex.hCursor= LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName= (LPCSTR)IDC_BTNTEST;wcex.lpszClassName= szWindowClass;wcex.hIconSm= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
最为重要的一行代码:
wcex.lpfnWndProc= (WNDPROC)WndProc;
该行代码传递了消息响应处理函数。
(2)注册窗口类
return RegisterClassEx(&wcex);
(3) 添加菜单
static HMENU hMenu,hMenuPop1,hMenuPop2;hMenu = CreateMenu();hMenuPop1 = CreateMenu();hMenuPop2 = CreateMenu();AppendMenu(hMenuPop1, MF_STRING, IDM_TEST, "&测试");AppendMenu(hMenuPop2, MF_STRING, IDM_ABOUT, "&关于");AppendMenu(hMenuPop2, MF_STRING, IDM_EXIT, "&退出");AppendMenu(hMenu, MF_POPUP, (UINT)hMenuPop1, "&菜单1");AppendMenu(hMenu, MF_POPUP, (UINT)hMenuPop2, "&菜单2");
(4)创建窗口
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, hMenu, hInstance, NULL);if (!hWnd){return FALSE;}
(5)显示和更新窗口
ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);
(6)创建消息循环
while (GetMessage(&msg, NULL, 0, 0)) {if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {TranslateMessage(&msg);DispatchMessage(&msg);}}
获取的消息是虚键消息。TranslateMessage的功能是将虚拟键消息转换为字符消息。DispatchMessage将消息分发给窗口程序。
(7)实现消息响应函数
#define btn1 1#define btn2 2LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){int wmId, wmEvent;PAINTSTRUCT ps;HDC hdc;TCHAR szHello[MAX_LOADSTRING];LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);switch (message) {case WM_CREATE:{//buttonHWND hButton1 = CreateWindow(_T("button"), _T("Btn1"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 100, 100, 100, 30, hWnd, (HMENU)btn1, hInst, NULL);HWND hButton2 = CreateWindow(_T("button"), _T("Btn2"),WS_CHILD|WS_VISIBLE|BS_BITMAP, 100, 200, 100, 30, hWnd, (HMENU)btn2, hInst, NULL);HBITMAP hbmp=LoadBitmap(hInst,MAKEINTRESOURCE(IDB_Btn2));SendMessage(hButton2, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbmp);}break;case WM_COMMAND:wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections:switch (wmId){case btn1:MessageBox(hWnd, _T("Button1 press!"), _T("Message"), MB_OK|MB_ICONINFORMATION);break;case btn2:MessageBox(hWnd, _T("Button2,press!"), _T("Message"), MB_OK|MB_ICONINFORMATION);break;case IDM_TEST:MessageBox(hWnd, _T("菜单测试"), _T("菜单测试"), MB_OK|MB_ICONINFORMATION);break;case IDM_ABOUT:DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);break;case IDM_EXIT:DestroyWindow(hWnd);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}break;case WM_PAINT:hdc = BeginPaint(hWnd, &ps);// TODO: Add any drawing code here...RECT rt;GetClientRect(hWnd, &rt);DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);EndPaint(hWnd, &ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;}// Mesage handler for about box.LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){switch (message){case WM_INITDIALOG:return TRUE;case WM_COMMAND:if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {EndDialog(hDlg, LOWORD(wParam));return TRUE;}break;} return FALSE;
在WM_CREATE中添加按钮实现代码,在WM_COMMAND中检测按钮响应事件。
示例代码的实现效果如下图所示:
2 消息响应如何实现
在MFC代码中,没有看到WinMain,也没有看到消息响应函数。但可以发现,利用界面设计器添加的类代码都被包含在一对宏定义中。
BEGIN_MESSAGE_MAP(CMayMoodDlg, CDialog)//{{AFX_MSG_MAP(CMayMoodDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_EXIT, OnExit)ON_BN_CLICKED(IDC_BTN_ENCRY, OnBtnEncry)ON_BN_CLICKED(IDC_BTN_DECRY, OnBtnDecry)ON_BN_CLICKED(IDC_BTN_HELP, OnBtnHelp)ON_BN_CLICKED(IDC_BTN_SET, OnBtnSet)ON_BN_CLICKED(IDC_BTN_ABOUT, OnBtnAbout)//}}AFX_MSG_MAPEND_MESSAGE_MAP()
BEGIN_MESSAGE_MAP()宏展开如下:
#ifdef _AFXDLL#define BEGIN_MESSAGE_MAP(theClass, baseClass) \const AFX_MSGMAP* PASCAL theClass::_GetBaseMessageMap() \{ return &baseClass::messageMap; } \const AFX_MSGMAP* theClass::GetMessageMap() const \{ return &theClass::messageMap; } \AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \{ &theClass::_GetBaseMessageMap, &theClass::_messageEntries[0] }; \AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \{ \#else#define BEGIN_MESSAGE_MAP(theClass, baseClass) \const AFX_MSGMAP* theClass::GetMessageMap() const \{ return &theClass::messageMap; } \AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \{ &baseClass::messageMap, &theClass::_messageEntries[0] }; \AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \{ \#endif
END_MESSAGE_MAP()宏展开如下:
#define END_MESSAGE_MAP() \{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \}; \
实际上,这段代码完成了一件事:
在你的类中生成了一个名为_messageEntries的数组,将消息和此消息对应的处理函数填入该数组中。应用程序框架生成的WindowProc接收到一个消息后,会按照一定的原则轮询个各类(CView、CDocument、CFrameWnd、CWinApp)的messageEntries数组,检查该数组中有没有对应的消息,如果有,就调用相应的响应函数;如果没有,就换下一个类继续检查。当所有的有关的类都被检查完后仍未发现响应函数时,便将此消息丢给DefWindowProc处理。
这其实,说明了一件事:通过上述宏定义完成了对象与消息的连接。这个过程类似于Qt的信号与槽机制。
关于WinMain的解释网上很多,此处不再赘述。
【源码下载】
1 http://download.csdn.net/detail/tandesir/4949921
【学习参考】
1 http://blog.csdn.net/zeng622peng/article/details/5589867
2 http://blog.csdn.net/luckyboy101/article/details/6739701
转载请标明出处,仅供学习交流,勿用于商业目的
Copyright @ http://blog.csdn.net/tandesir
- 也说MFC消息响应机制
- MFC消息响应机制
- MFC消息响应机制
- MFC消息响应机制
- MFC消息响应机制
- MFC----消息响应机制
- MFC消息响应机制
- MFC消息响应机制
- MFC消息响应机制分析
- MFC消息响应机制分析
- MFC消息响应机制分析
- MFC消息响应机制分析
- MFC消息响应机制分析
- MFC消息响应机制分析
- MFC消息响应机制说明
- MFC消息响应机制分析
- MFC消息响应机制分析
- MFC中消息响应机制
- linux内核中的get_user和put_user
- chrome 快捷键
- [设计模式]Template模版模式
- 启动和测试oracle是否安装成功
- 【andriod】activity 进入退出动画
- 也说MFC消息响应机制
- jQuery属性篇-attr
- 骑着自行车推广网站你也可以嘛
- Java解惑-互换内容
- 从高中一次半夜不冲厕所的经历谈程序
- JavaScript DOM随手记
- 章家敦同志(《中国即将崩溃》的作者),你辛苦了,中国人民感谢你!!!
- NetBeans IDE 7安装PYTHON插件支持
- 2013-1-1新年新气象,开始博客之旅