一. Win32的界面编写
1. 实现一个带按钮并响应点击事件的界面,代码如下:
1 #include <tchar.h> 2 #include <windows.h> 3 #include "CommCtrl.h" 4 5 #define IDC_BTN_TEST (101) 6 7 //窗口过程函数 8 LRESULT CALLBACK pfnWndProc(HWND stHwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) 9 { 10 switch (uiMsg) 11 { 12 case WM_CREATE: 13 ::CreateWindow(WC_BUTTON, _T("按钮测试"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 200, 200, 120, 50, stHwnd, (HMENU)IDC_BTN_TEST, NULL, NULL); 14 break; 15 case WM_COMMAND: 16 if ((IDC_BTN_TEST == LOWORD(wParam)) && (BN_CLICKED == HIWORD(wParam)))//点击按钮响应 17 { 18 ::MessageBox(NULL, _T("你点击了测试按钮"), _T("点击测试"), MB_OK); 19 } 20 break; 21 case WM_DESTROY: 22 PostQuitMessage(0); 23 break; 24 default: 25 return DefWindowProc(stHwnd, uiMsg, wParam, lParam); 26 } 27 28 return 0; 29 } 30 31 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) 32 { 33 MSG stMsg; 34 memset(&stMsg, 0, sizeof (stMsg)); 35 HWND stHwnd; 36 memset(&stHwnd, 0, sizeof (stHwnd)); 37 WNDCLASS stWndClass; 38 memset(&stWndClass, 0, sizeof (stWndClass)); 39 const TCHAR szAppName[] = _T("windowsUI"); 40 41 stWndClass.style = CS_HREDRAW | CS_VREDRAW; 42 stWndClass.lpfnWndProc = pfnWndProc; 43 stWndClass.cbClsExtra = 0; 44 stWndClass.cbWndExtra = 0; 45 46 stWndClass.hInstance = hInstance; 47 stWndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 48 stWndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 49 stWndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 50 stWndClass.lpszMenuName = NULL; 51 stWndClass.lpszClassName = szAppName; 52 53 if (!RegisterClass(&stWndClass))//注册窗口类 54 { 55 MessageBox(NULL, _T("Regiester failure"), szAppName, MB_ICONERROR); 56 return 0; 57 } 58 59 stHwnd = CreateWindow(szAppName, //创建窗口 60 _T("windows UI"), 61 WS_OVERLAPPEDWINDOW, 62 CW_USEDEFAULT, 63 CW_USEDEFAULT, 64 800, 65 600, 66 NULL, 67 NULL, 68 hInstance, 69 NULL); 70 71 ShowWindow(stHwnd, iCmdShow); //显示窗口 72 UpdateWindow(stHwnd); 73 74 while (GetMessage(&stMsg, NULL, 0, 0))//消息循环 75 { 76 TranslateMessage(&stMsg); 77 DispatchMessage(&stMsg); 78 } 79 80 return stMsg.wParam; 81 }View Code
2. 代码量大?记不住?为嘛不使用MFC实现?
-
- 不用记这些参数什么的,但是UI流程必须要理解:注册窗口类---->创建窗口---->显示窗口---->消息循环---->窗口过程;
- MFC本质是对windows的原生控件进行了封装,为了更好地使用MFC,可以多熟悉CommCtrl.h文件;
二. MFC界面编写
1. 同样实现一个带按钮并点击事件的界面(代码就不贴了,比较简单),生成两个重要文件MfcTest.cpp和MfcTestDlg.cpp
2. 代码入口在哪?也就是WinMain函数在哪?我要怎么写界面?
-
- CUI(控制台)入口函数:main GUI(win32)入口函数:WinMain Dll(动态库)入口函数:DllMain;
- MFC除了对原生界面进行封装外,还对线程,文件,网络,字符串,STL等都进行了封装,但本质是win32程序;
- MfcTest.cpp主线程类,MfcTestDlg.cpp主窗口类;
3. MfcTest.cpp主线程类分析:
-
- 通过“调用堆栈”可以追溯到WinMain函数,通过一步步调用,最后调用到MfcTest.cpp的InitInstance函数,那我们就可以认为InitInstance == WinMain
1 _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 2 _In_ LPTSTR lpCmdLine, int nCmdShow) 3 #pragma warning(suppress: 4985) 4 { 5 // call shared/exported WinMain 6 return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); 7 }View Code
-
- 入口函数找到了,那么像win32那样的界面是怎么创建的呢?在主线程里我们继续分析,可以找到窗口生成的如下代码:
1 CMfcTestDlg dlg; 2 m_pMainWnd = &dlg; 3 INT_PTR nResponse = dlg.DoModal(); 4View Code
4. MfcTestDlg.cpp主窗口类分析:
-
- 窗口是怎么生成的?我们看下代码对比:
1 //win32 2 if (!RegisterClass(&stWndClass))//注册窗口类 3 { 4 MessageBox(NULL, _T("Regiester failure"), szAppName, MB_ICONERROR); 5 return 0; 6 } 7 8 stHwnd = CreateWindow(szAppName, //创建窗口 9 _T("windows UI"), 10 WS_OVERLAPPEDWINDOW, 11 CW_USEDEFAULT, 12 CW_USEDEFAULT, 13 800, 14 600, 15 NULL, 16 NULL, 17 hInstance, 18 NULL); 19 20 ShowWindow(stHwnd, iCmdShow); //显示窗口 21 UpdateWindow(stHwnd); 22 23 ... ... 24 25 //MFC 26 CMfcTestDlg dlg; 27 m_pMainWnd = &dlg; 28 INT_PTR nResponse = dlg.DoModal(); 29 30 //这里不纠结模态与非模态对面框View Code
-
- 那么窗口过程呢?怎么找不到,我们再来对比下:
1 //窗口过程函数 2 LRESULT CALLBACK pfnWndProc(HWND stHwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) 3 { 4 switch (uiMsg) 5 { 6 case WM_CREATE: 7 OnInitDialog();//CMfcTestDlg 8 break; 9 case WM_COMMAND: 10 OnSysCommand();//CMfcTestDlg,先不作判断,只是简单对比 11 break; 12 case WM_PAINT: 13 OnPaint();//CMfcTestDlg 14 break; 15 case WM_QUERYDRAGICON: 16 OnQueryDragIcon();//CMfcTestDlg 17 break; 18 case WM_DESTROY: 19 PostQuitMessage(0); 20 break; 21 default: 22 return DefWindowProc(stHwnd, uiMsg, wParam, lParam); 23 } 24 25 return 0; 26 }View Code
-
- 通过对比,我们知道MFC只是对win32的窗口生成和窗口消息进行了二次封装,最后我们再分析下消息列表是怎么回事:
1 BEGIN_MESSAGE_MAP(CMfcTestDlg, CDialogEx) 2 ON_WM_SYSCOMMAND() 3 ON_WM_PAINT() 4 ON_WM_QUERYDRAGICON() 5 ON_BN_CLICKED(IDC_BTN_TEST1, &CMfcTestDlg::OnBnClickedBtnTest) 6 ON_BN_CLICKED(IDC_BTN_TEST2, &CMfcTestDlg::OnBnClickedBtnTest2) 7 ON_MESSAGE(WM_USER_BTN, &CMfcTestDlg::OnUserBtnTest) 8 END_MESSAGE_MAP()View Code
-
- F12跟进里面各种宏头都看晕了,但是说白了就是将消息ID与消息处理函数绑定起来,想想C11里的std::bind性能或者委托模式的CDelegate实现;
5. 窗口消息之间的相互传递
-
- 在这里只说下自定义消息的传递SendMessage(同步)和PostMessage(异步),代码如下:
1 //自定义消息 2 #define WM_USER_BTN (WM_USER + 100) 3 4 ... ... 5 6 BEGIN_MESSAGE_MAP(CMfcTestDlg, CDialogEx) 7 ... ... 8 ON_MESSAGE(WM_USER_BTN, &CMfcTestDlg::OnUserBtnTest) 9 END_MESSAGE_MAP() 10 11 ... ... 12 13 LRESULT CMfcTestDlg::OnUserBtnTest(WPARAM wParam, LPARAM lParam) 14 { 15 MessageBox(_T("收到自定义消息")); 16 17 return NULL; 18 }View Code