C\C++ Windows程序設計[2]:創建一個窗口


上篇文章講了如何編寫一個彈出對話框的程序,這篇文章就來講講如何在C\C++下創建一個窗口。

來簡單介紹下 Windows窗口程序 的創建過程:
首先我們需要注冊一個窗口類,可以使用RegisterClass函數,接着使用CreateWindow創建一個窗口。下一步需要讓窗口在屏幕上面顯示出來,可以使用ShowWindow來完成,接着是更新窗口,注意一定不能漏掉這個步驟!這個闊以使用UpdateWindow來完成。接着就是建立消息循環隊列啦,如果沒有這個,程序就不能響應Windows發來的信息啦。


來康康代碼:
#include <windows.h>

LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ) ;        //聲明用來處理消息的函數

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
{
    static TCHAR szAppName[] = TEXT("MyWindow") ;
    HWND hwnd ;
    MSG msg ;
    WNDCLASS wndclass ;        //聲明一個窗口類對象

    //以下為窗口類對象wndclass的屬性
    wndclass.style = CS_HREDRAW | CS_VREDRAW ;                         //窗口樣式
    wndclass.lpszClassName = szAppName ;                               //窗口類名
    wndclass.lpszMenuName = NULL ;                                     //窗口菜單:無
    wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ;    //窗口背景顏色
    wndclass.lpfnWndProc = WndProc ;                                   //窗口處理函數
    wndclass.cbWndExtra = 0 ;                                          //窗口實例擴展:無
    wndclass.cbClsExtra = 0 ;                                          //窗口類擴展:無
    wndclass.hInstance = hInstance ;                                   //窗口實例句柄
    wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ;               //窗口最小化圖標:使用缺省圖標
    wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ;                 //窗口采用箭頭光標

    if( !RegisterClass( &wndclass ) )
    {    //注冊窗口類, 如果注冊失敗彈出錯誤提示
        MessageBox( NULL, TEXT("窗口注冊失敗"), TEXT("錯誤"), MB_OK | MB_ICONERROR ) ;
        return 0 ;
    }

    hwnd = CreateWindow(               //創建窗口
        szAppName,                     //窗口類名
        TEXT("我的第一個Windows窗口"),   //窗口標題
        WS_OVERLAPPEDWINDOW,           //窗口的風格
        CW_USEDEFAULT,                 //窗口初始顯示位置x:使用缺省值
        CW_USEDEFAULT,                 //窗口初始顯示位置y:使用缺省值
        CW_USEDEFAULT,                 //窗口的寬度:使用缺省值
        CW_USEDEFAULT,                 //窗口的高度:使用缺省值
        NULL,                          //父窗口:無
        NULL,                          //子菜單:無
        hInstance,                     //該窗口應用程序的實例句柄 
        NULL                       
    ) ;

    ShowWindow( hwnd, iCmdShow ) ;        //顯示窗口
    UpdateWindow( hwnd ) ;                //更新窗口

    while( GetMessage( &msg, NULL, 0, 0 ) )        //從消息隊列中獲取消息
    {
        TranslateMessage( &msg ) ;                 //將虛擬鍵消息轉換為字符消息
        DispatchMessage( &msg ) ;                  //分發到回調函數(過程函數)
    }
    return msg.wParam ;
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    HDC hdc ;                //設備環境句柄
    PAINTSTRUCT ps ;         //繪制結構
    RECT rect;               //矩形結構

    switch( message )        //處理得到的消息
    {
        case WM_PAINT:           //處理窗口區域無效時發來的消息
            hdc = BeginPaint( hwnd, &ps ) ;
            GetClientRect( hwnd, &rect ) ;
            DrawText( hdc, TEXT("Hello World"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ;  //文字
            EndPaint( hwnd, &ps ) ;
            return 0 ;
        case WM_DESTROY:         //處理窗口關閉時的消息
            MessageBox( hwnd, TEXT("關閉程序!"), TEXT("結束"), MB_OK | MB_ICONINFORMATION ) ;
            PostQuitMessage( 0 ) ;
            return 0;
    }
    return DefWindowProc( hwnd, message, wParam, lParam ) ;        //DefWindowProc處理我們自定義的消息處理函數沒有處理到的消息
}


編譯(方式同上篇文章),你會看到個Windows窗口,啊恭喜你!你已經編譯出了你人生第一個Windows窗口程序(滑稽)。
由上面的代碼可知Windows窗口的代碼框架:
#include <windows.h>

LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ) ;        //聲明用來處理消息的函數

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow ) //Windows窗口程序的入口函數
{
    //創建窗口、消息循環等
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ){
    //處理消息
    
    return DefWindowProc( hwnd, message, wParam, lParam ) ;
}

觀察上面的代碼,你會發現,哎,main不見了,取而代之的是WinMain,還有一個WndProc!是的你沒看錯,Windows窗口程序不再使用main作為入口函數了,而是使用WinMain來作為主函數。而且WinMain的參數也變了: ```cpp int WINAPI WinMain( //Windows窗口程序入口函數 HINSTANCE hInstance, //實例句柄 HINSTANCE hPrevInstance, //無用參數,總是為NULL(空,即“0”) PSTR szCmdLine, //傳入的命令 int iCmdShow //窗口顯示類型 ) ```
再仔細觀察,你會發現,WinMain旁邊還有個WINAPI,這是什么意思呢?其實,WINAPI是個在windef.h里面定義的標識符: ```cpp #define WINAPI __stdcall ``` 這條語句規定了一種函數調用約定,表明如何生成在堆棧中放置函數調用參數的機器代碼,絕大部分 Windows 函數調用都定義成 WINAPI。

Windows窗口程序工作原理


運行剛才編譯的程序,你會發現不管怎么拖動、縮放來改變 程序 的大小,那段Hello World的文字永遠是在屏幕正中央,這是怎么做到的呢?這就涉及到Windows窗口程序的工作原理了。 其實,用戶調整窗口大小所產生的瑣碎代碼都是 Windows 實現的而並非應用程序,那么應用程序如何知道自己的大小以及被改變了?每當用戶進行拖動窗口或者點擊窗口之類的操作時,Windows都會向程序發送一條消息,這就是上面代碼中的WndProc函數的作用。每當Windows向應用程序發送一條消息,都會觸發WndProc函數,現在來康康WndProc的參數:
LRESULT CALLBACK WndProc(  //處理Windows發送來的消息
    HWND hwnd,             //窗口句柄(后面會講到)
    UINT message,          //Windows發來的消息
    WPARAM wParam,         //傳入的參數,暫時不需要理解
    LPARAM lParam          //傳入的參數,暫時不需要理解
)

顯然,WndProc是對message這個參數進行處理。


現在來一個個解析調用到的Windows API:

函數 意義
LoadIcon 加載圖標
LoadCursor 加載鼠標光標
GetStockObject 獲取圖形對象
RegisterClass 注冊一個窗口類
MessageBox 彈出對話框
CreateWindow 創建一個窗口
ShowWindow 顯示窗口
UpdateWindow 更新窗口
GetMessage 從消息隊列中獲取消息
TranslateMessage 轉換消息
DispatchMessage 將消息分發到回調函數處理
BeginDraw 開始繪圖
GetClientRect 獲取窗口大小
DrawText 繪制文字
EndPaint 結束繪制
PostQuitMessage 插入"退出"消息到消息隊列
DefWindowProc 執行默認的消息處理




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM