簡要說明
MFC是微軟的一個基礎類庫,如果在Windows平台上做GUI的開發,這是一個不錯的選擇。簡單的記錄MFC學習過程中的需要掌握或者后期需要查看的知識點。
Windows消息機制
- 操作系統首先捕獲到來自鍵盤或鼠標等輸入系統的消息,並將獲取到的消息存放到消息隊列中。
- 應用程序一直通過GetMessage()從消息隊列中獲取消息。
- 應用程序再將獲取到的消息通過DispatchMessage()分派到操作系統
- 操作系統再執行“窗口過程”
Windows編程模型
- WinMain函數的定義(WinMain函數是Windows程序的入口)
- 創建一個窗口
- 進行消息循環
- 編寫窗口過程函數
整體框架結構
實現步驟
創建win32項目
- 新建win32項目,選擇“空項目”並完成創建。
- 添加源文件,文件名以“.c”結尾。
- 添加頭文件“windows.h”
- 添加程序入口函數“WindowMain”
//WINAPI 代表__stdcall 參數的傳遞順序:從右到左 以此入棧,並且在函數返回前 清空堆棧
int WINAPI WinMain(
HINSTANCE hInstance, // 應用程序實例句柄
HINSTANCE hPrevInstance, // 上一個應用程序句柄,在win32環境下,參數一般為NULL,不起作用了
LPSTR lpCmdLine, // char * argv[]
int nShowCmd) // 顯示命令 最大化、最小化 正常
{
...
return 0;
}
應用程序過程
- 設計窗口
- 首先實例化一個窗口類,再依次設置其參數
WNDCLASS wc;
wc.cbClsExtra = 0; //類的額外的內存
wc.cbWndExtra = 0; //窗口額外的內存
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 設置背景
wc.hCursor = LoadCursor(NULL, IDC_HAND); //設置光標 如果第一個參數為NULL,代表使用體統提供的光標
wc.hIcon = LoadIcon(NULL, IDI_ERROR);
wc.hInstance = hInstance; //應用程序實例句柄 傳入WinMain中的形參即可
wc.lpfnWndProc = WindowProc;// 回調函數 窗口過程
wc.lpszClassName = TEXT("WIN");//指定窗口類名稱
wc.lpszMenuName = NULL; //NULL代表不使用菜單
wc.style = 0; //顯示風格 0為默認
- 注冊窗口
- 將上述實例化的窗口類進行注冊
RegisterClass(&wc);
- 創建窗口
/*
lpClassName, 類名
lpWindowName, 標題名
dwStyle, 風格 WS_OVERLAPPEDWINDOW
x, 顯示坐標 CW_USEDEFAULT
y,
nWidth, 寬
nHeight, 高
hWndParent, 父窗口
hMenu, 菜單
hInstance, 實例句柄
lpParam 附加值 lp一般為鼠標附加值 NULL
*/
HWND hwnd = CreateWindow(wc.lpszClassName, TEXT("WINDOWS"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, wc.hInstance, NULL);
- 顯示和更新
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
- 通過循環取消息
/*
HWND hwnd; 主窗口句柄
UINT message; 具體消息名稱
WPARAM wParam; 附加消息 鍵盤消息
LPARAM lParam; 附加消息 鼠標消息
DWORD time; 消息產生時間
POINT pt; 附加消息 鼠標消息 x y
*/
MSG msg;
while (1)
{
/*
LPMSG lpMsg, 消息
HWND hWnd, 捕獲窗口 填NULL代表捕獲所有的窗口
UINT wMsgFilterMin, 最小和最大的過濾的消息 一般填入0
UINT wMsgFilterMax 填0代表捕獲所有消息
*/
if (GetMessage(&msg, NULL, 0, 0) == FALSE)
{
break;
}
// 翻譯消息
TranslateMessage(&msg);
// 分發消息
DispatchMessage(&msg);
}
- 消息處理(窗口過程)
//CALLBACK 代表__stdcall 參數的傳遞順序:從右到左 以此入棧,並且在函數返回前 清空堆棧
LRESULT CALLBACK WindowProc(
HWND hwnd, // 消息所屬的窗口句柄
UINT uMsg, // 具體消息名稱 WM_XXXXXXXX 消息名
WPARAM wParam, // 鍵盤附加消息
LPARAM lParam // 鼠標附加消息
)
{
switch (uMsg)
{
case WM_CLOSE:
//所有xxxWindow為結尾的方法,都不會進入到消息隊列中,而是直接執行
DestroyWindow(hwnd); //DestroyWindow 發送另一個消息 WM_DESTROY
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_LBUTTONDOWN:
{
int xPos = LOWORD(lParam);
int yPos = HIWORD(lParam);
char buf[1024];
wsprintf(buf, TEXT("x = %d, y = %d"), xPos, yPos);
MessageBox(hwnd, buf, TEXT("鼠標左鍵按下"), MB_OK);
break;
}
case WM_KEYDOWN:
MessageBox(hwnd, TEXT("鍵盤按下"), TEXT("鍵盤按下"), MB_OK);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 100, 100, TEXT("HELLO"), strlen("HELLO"));
EndPaint(hwnd, &ps);
break;
}
default:
break;
}
大概流程如下
小結
- 首先要對整個創建流程有個整體的把握
- 學會查看msdn文檔,不知道的參數及方法都可以從中獲取
- 學習很重要,要好好學習