【二】Windows API 零门槛编程指南——CreateWindow 窗口创建 “万字长篇专业术语全解”
本系列博文幾乎沒有難啃的“專業術語”,盡量讓讀者能夠看明白文章所述內容,是本系列博文的核心宗旨之一。(由于本人也是由于項目需要,所以才來查閱相關資料,文中出現的錯誤歡迎指出,共同進步!謝謝!)
讀本系列博文的讀者必須具備以下的知識儲備:
- C/C++語言基礎語法及了解面向對象概念
窗口在 Windows 中指一個矩形區域,一般情況下這個區域是用戶與應用程序交互的樞紐;上一小節使用 MessageBox 創建的簡單窗口也是與用戶交互的一個窗口,該窗口的功能有限,只能夠簡單的展示一些想要表達的信息,想創建一個能表達更多信息的窗口,可以使用 CreateWindow 函數創建。
開始創建
創建 Windows 桌面應用程序需要 windows.h,在頭部引入 windows.h 頭文件。
#include <windows.h>WinMain
在C語言中,每個C語言程序都有一個入口函數,在Windows桌面程序中,這個入口函數是 WinMain ,具體聲明如下:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow);在程序中,緊接著在頭部文件后,我們使用 WinMain作為程序的入口函數:
#include <windows.h> int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {}寫好入口函數后,必須要使用 RegisterClassEx 注冊一個新的窗口類型,再使用 CreateWindow 進行創建。
WNDCLASSEX
在注冊新窗口前,我們可以使用一個 WNDCLASSEX 結構用來描述創建的Windows,這是窗口類;微軟開發中心對WNDCLASSEXA的描述:“Contains window class information. It is used with the RegisterClassEx and GetClassInfoEx functions.”;WNDCLASSEXA 是包含窗口信息的結構。語法如下:
typedef struct tagWNDCLASSEXA {UINT cbSize;UINT style;WNDPROC lpfnWndProc;int cbClsExtra;int cbWndExtra;HINSTANCE hInstance;HICON hIcon;HCURSOR hCursor;HBRUSH hbrBackground;LPCSTR lpszMenuName;LPCSTR lpszClassName;HICON hIconSm; } WNDCLASSEXA, *PWNDCLASSEXA, *NPWNDCLASSEXA, *LPWNDCLASSEXA;結構成員:
- cbSize 窗口的大小:為 WNDCLASSEX 這個結構的字節數大小,賦值為 sizeof(WNDCLASSEX)
- style 窗口的風格:為該窗口的樣式,取值為 CS_HREDRAW | CS_VREDRAW
- lpfnWndProc 窗口處理指針:為指向窗體的的過程函數,為指針,使用 WndProc 處理應用程序在發生事件時從 Windows 接收的消息,以下將會講解 WndProc
- cbClsExtra 窗口類結構后的附加字節數,一般為0
- cbWndExtra 窗口事例后的附加字數,一般為0
- hInstance 當前實例句柄,直接把WinMain參數 hInstance(表示當前實例句柄) 賦值給 hInstance 即可
- hIcon 圖標的句柄,暫時賦值為NULL
- hCursor 光標的句柄:使用 LoadCursor 加載光標,以下講解語法
- lpszClassName: 類別名稱的指針賦值為static TCHAR szWindowClass[] = _T("CSDN @1_bit");
- hIconSm: 窗口類關聯的小圖標,使用 LoadIcon函數加載,不過在文檔中提示,這個函數已過時,可以使用 LoadImage 函數加載,本篇使用的是 LoadIcon ,LoadImage 后面再做補充;LoadIcon 函數語法將會在以下講解
- hbrBackground 背景畫刷的句柄,將會在以下給出設置的值參考
- lpszMenuName 指向菜單資源名的指針,為NULL即可
代碼實現如下:
WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));wcex.hCursor = LoadCursor(NULL, IDC_CROSS);wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);wcex.lpszMenuName = NULL;wcex.lpszClassName = szWindowClass;wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));——————————————————————————————————
WNDCLASSEX hbrBackground
值參考:
——————————————————————————————————
LoadCursor
LoadCursor 返回類型為 HCURSOR:的語法如下:
HCURSOR LoadCursorW(HINSTANCE hInstance,LPCWSTR lpCursorName );參數說明:
- hInstance :可賦值當前實例
- lpCursorName:要加載的游標資源的名稱
在微軟的參考文檔中說明,lpCursorName 的可設置為以下值:
——————————————————————————————————
lpfnWndProc
lpfnWndProc 為接收窗口處理的指針,使用 WndProc 處理應用程序在發生事件時從 Windows 接收的消息。在微軟的文檔中寫道:“WndProc 是每個 Windows 桌面應用程序必須的窗口過程功能。 此函數通常命名為WndProc,但您可以隨心所欲地命名它。 例如,如果用戶在應用程序中選擇"確定"按鈕,Windows 會向您發送消息,您可以在WndProc函數內編寫代碼,執行任何適當的操作。 這稱為處理事件。 您只處理與應用程序相關的事件。WndProc 具有以下語法”;如下:。
LRESULT CALLBACK WndProc(_In_ HWND hWnd,_In_ UINT message,_In_ WPARAM wParam,_In_ LPARAM lParam );那我們在程序中聲明也如此聲明,那么定義如下(使用微軟文檔示例):
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {PAINTSTRUCT ps;HDC hdc;TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主頁:https://me.csdn.net/A757291228 ");switch (message){case WM_PAINT:hdc = BeginPaint(hWnd, &ps);TextOut(hdc,5, 5,greeting, _tcslen(greeting));EndPaint(hWnd, &ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);break;}return 0; }在以上 WndProc 的實現中,使用了 switch 語句,在 switch 中判斷了 WM_PAINT 消息;WM_PAINT 消息為繪制主窗體,在文檔中寫到:
要處理的一條重要信息是WM_PAINT消息。 當必須更新其顯示WM_PAINT窗口的一部分時,應用程序將接收消息。
當用戶在窗口前面移動窗口,然后再次將其移開時,可能會發生此事件。 您的應用程序不知道這些事件何時發生。 只有 Windows
知道,因此它會通過消息WM_PAINT通知你的應用。 首次顯示窗口時,必須更新所有窗口。 要處理 WM_PAINT 消息,首先應調用
BeginPaint,然后處理所有的邏輯以在窗口中布局文本、按鈕和其他控件,然后調用 EndPaint。
——————————————————————————————————
BeginPaint
BeginPaint 的語法為:
HDC BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint );參數說明:
- HWND:處理要重繪的窗口
- lpPaint:接收繪制的接收繪畫信息的 **PAINTSTRUCT**結構的指針
——————————————————————————————————
EndPaint
該調用EndPaint函數標記指定窗口畫的結束。每次調用BeginPaint函數都需要此函數,但是僅在繪制完成之后。
語法:
BOOL EndPaint(HWND hWnd,const PAINTSTRUCT *lpPaint );參數說明:
- hWnd:處理的窗口
- lpPaint:指向PAINTSTRUCT結構的指針
——————————————————————————————————
PostQuitMessage
向系統指示線程已請求終止(退出)。通常用于響應WM_DESTROY消息。
語法:
void PostQuitMessage(int nExitCode );參數說明:
- nExitCode:應用程序退出代碼。此值用作WM_QUIT消息的wParam參數。
——————————————————————————————————
DefWindowProc
調用默認窗口過程以為應用程序未處理的任何窗口消息提供默認處理。此功能確保處理所有消息。DefWindowProc用窗口過程接收到的相同參數調用。
語法:
LRESULT LRESULT DefWindowProcA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam );參數說明:
- hWnd:窗口句柄
- Msg:消息
- wParam:附加消息
- lParam:附加消息信息
——————————————————————————————————
TextOut
所述的TextOut函數在指定位置寫入的字符串,利用當前選擇的字體,背景顏色和文本顏色。
語法:
BOOL TextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int c );參數說明:
- hdc:上下文句柄
- x,y:對齊字符串的x,y坐標
- lpString:字符串指針,指向字符串
- c:字符串長度
——————————————————————————————————
HDC
引用文檔解釋:
HDC代碼中是設備上下文的句柄,這是 Windows 用于使應用程序與圖形子系統通信的數據結構。
WM_DESTROY
銷毀窗口時發送。從窗口中刪除窗口后,它將被發送到銷毀窗口的窗口過程。
此消息首先發送到被銷毀的窗口,然后發送到被銷毀的子窗口(如果有)。在處理消息期間,可以假定所有子窗口仍然存在。
WM_DESTROY 在 WndProc 函數中使用
——————————————————————————————————
補充
WM_CREATE
當應用程序通過調用CreateWindowEx或CreateWindow函數請求創建窗口時發送。(在函數返回之前發送消息。)在創建窗口之后,但在該窗口變為可見之前,新窗口的窗口過程會收到此消息。
——————————————————————————————————
RegisterClassEx
之后注冊該窗口,使用 RegisterClassEx:
RegisterClassEx(&wcex);注冊后使用 CreateWindow 進行注冊的窗口創建語法如下:
HWND CreateWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HANDLE hInstance, PVOID lpParam );參數說明:
- lpClassName:應用程序窗體名
- lpWindowName:標題名
- DWORD dwStyle:窗口類型風格
- x,y:初始位置(x,y)
- nWidth, nHeight:初始尺寸
- hWndParent,:窗體父級,可為NULL
- hMenu,:菜單欄,可為NULL
- hInstance:當前實例
- lpParam:應用程序使用,可為NULL
創建窗體:
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1000, 1000, NULL, NULL, hInstance, NULL);應用窗體名為 szWindowClass:
static TCHAR szWindowClass[] = _T("win32 Demo");應用窗體名為 szTitle:
static TCHAR szTitle[] = _T("This Win32");窗體風格類型為:WS_OVERLAPPEDWINDOW
初始位置為:CW_USEDEFAULT,默認左上角出現
尺寸為:1000, 1000
父級及菜單欄都為:NULL
hInstance為:當前實例 hInstance
lpParam應用程序使用為:NULL
代碼如下:
#include <windows.h> #include <tchar.h> static TCHAR szWindowClass[] = _T("CSDN @1_bit"); static TCHAR szTitle[] = _T("Win32 桌面應用程序"); HINSTANCE hInst;LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));wcex.hCursor = LoadCursor(NULL, IDC_CROSS);wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);wcex.lpszMenuName = NULL;wcex.lpszClassName = szWindowClass;wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));RegisterClassEx(&wcex);hInst = hInstance;HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);} LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {PAINTSTRUCT ps;HDC hdc;TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主頁:https://me.csdn.net/A757291228 ");switch (message){case WM_PAINT:hdc = BeginPaint(hWnd, &ps);TextOut(hdc,5, 5,greeting, _tcslen(greeting));EndPaint(hWnd, &ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);break;}return 0; }——————————————————————————————————
ShowWindow
完成以上代碼后,還需使用 ShowWindow 讓Windows窗體指定如何顯示,代碼如下:
ShowWindow(hWnd, nCmdShow);語法:
BOOL ShowWindow(HWND hWnd,int nCmdShow );參數說明:
- hWnd:窗口句柄
- nCmdShow:窗口的顯示方式
nCmdShow 參考:
——————————————————————————————————
UpdateWindow
使用 UpdateWindow 發送 WM_PAINT 消息,更新指定窗口。
語法:
參數:
- hWnd:窗口句柄
整體代碼如下:
#include <windows.h> #include <tchar.h> static TCHAR szWindowClass[] = _T("CSDN @1_bit"); static TCHAR szTitle[] = _T("Win32 桌面應用程序"); HINSTANCE hInst;LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));wcex.hCursor = LoadCursor(NULL, IDC_CROSS);wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);wcex.lpszMenuName = NULL;wcex.lpszClassName = szWindowClass;wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));RegisterClassEx(&wcex);hInst = hInstance;HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return 0; }LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {PAINTSTRUCT ps;HDC hdc;TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主頁:https://me.csdn.net/A757291228 ");switch (message){case WM_PAINT:hdc = BeginPaint(hWnd, &ps);TextOut(hdc,5, 5,greeting, _tcslen(greeting));EndPaint(hWnd, &ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);break;}return 0; }運行程序,發現出現了一閃而過的窗口,這個很像剛學習C語言的時候,沒有加上停止;那我們就循環偵聽 Windows 發送的消息即可:
MSG msg; while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg); }return (int) msg.wParam;——————————————————————————————————
GetMessage
GetMessage
從調用線程的消息隊列中檢索消息。該函數分派傳入的已發送消息,直到已發布的消息可供檢索為止。
語法:
BOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax );參數說明:
- lpMsg:指向
MSG
結構的指針,該結構從線程的消息隊列接收消息信息。 - hWnd:獲取消息的的窗口句柄,文檔中解釋到:“如果hWnd為NULL,則GetMessage檢索屬于當前線程的任何窗口的消息,以及當前線程的消息隊列中hwnd值為NULL的消息(請參閱MSG結構)。因此,如果hWnd為NULL,則將同時處理窗口消息和線程消息。”
- wMsgFilterMin,wMsgFilterMax:要檢索的最低、最高消息值的整數值“**
- wMsgFilterMin 和 wMsgFilterMax 都為零,則 GetMessage 返回所有可用消息**”
——————————————————————————————————
完整代碼
#include <windows.h> #include <tchar.h> static TCHAR szWindowClass[] = _T("CSDN @1_bit"); static TCHAR szTitle[] = _T("Win32 桌面應用程序"); HINSTANCE hInst;LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));wcex.hCursor = LoadCursor(NULL, IDC_CROSS);wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);wcex.lpszMenuName = NULL;wcex.lpszClassName = szWindowClass;wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));RegisterClassEx(&wcex);hInst = hInstance;HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return (int)msg.wParam; }LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {PAINTSTRUCT ps;HDC hdc;TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主頁:https://me.csdn.net/A757291228 ");switch (message){case WM_PAINT:hdc = BeginPaint(hWnd, &ps);TextOut(hdc,5, 5,greeting, _tcslen(greeting));EndPaint(hWnd, &ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);break;}return 0; }運行結果如下:
總結
以上是生活随笔為你收集整理的【二】Windows API 零门槛编程指南——CreateWindow 窗口创建 “万字长篇专业术语全解”的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【一】Windows API 零门槛编程
- 下一篇: java信息管理系统总结_java实现科