日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

一个完整的Windows程序框架

發布時間:2025/3/12 windows 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一个完整的Windows程序框架 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面我們演示了帶界面的Windows程序,但那僅僅是一個彈窗,調用MessageBox函數就可以實現,不是一個真正意義上的窗口。我們通常所說的窗口包含最大化、最小化、關閉按鈕,也包含菜單、單選框、圖像等各種控件。

一個完整的Windows程序框架:

  • #include <windows.h>
  • ?
  • LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  • ?
  • int WINAPI WinMain(
  • HINSTANCE hInstance,
  • HINSTANCE hPrevInstance,
  • PSTR szCmdLine,
  • int iCmdShow
  • ){
  • static TCHAR szClassName[] = TEXT("HelloWin"); //窗口類名
  • HWND hwnd; //窗口句柄
  • MSG msg; //消息
  • WNDCLASS wndclass; //窗口類
  • ?
  • /**********第①步:注冊窗口類**********/
  • //為窗口類的各個字段賦值
  • wndclass.style = CS_HREDRAW | CS_VREDRAW; //窗口風格
  • wndclass.lpfnWndProc = WndProc; //窗口過程
  • wndclass.cbClsExtra = 0; //暫時不需要理解
  • wndclass.cbWndExtra = 0; //暫時不需要理解
  • wndclass.hInstance = hInstance; //當前窗口句柄
  • wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); //窗口圖標
  • wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); //鼠標樣式
  • wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH); //窗口背景畫刷
  • wndclass.lpszMenuName = NULL ; //窗口菜單
  • wndclass.lpszClassName= szClassName; //窗口類名
  • ?
  • //注冊窗口
  • RegisterClass(&wndclass);
  • ?
  • /*****第②步:創建窗口(并讓窗口顯示出來)*****/
  • hwnd = CreateWindow(
  • szClassName, //窗口類的名字
  • TEXT("Welcome"), //窗口標題(出現在標題欄)
  • WS_OVERLAPPEDWINDOW, //窗口風格
  • CW_USEDEFAULT, //初始化時x軸的位置
  • CW_USEDEFAULT, //初始化時y軸的位置
  • 500, //窗口寬度
  • 300, //窗口高度
  • 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("你好,歡迎來到C語言中文網"),
  • -1,
  • &rect,
  • DT_SINGLELINE | DT_CENTER | DT_VCENTER
  • );
  • EndPaint (hwnd, &ps) ;
  • return 0 ;
  • ?
  • //窗口銷毀消息
  • case WM_DESTROY:
  • PostQuitMessage(0) ;
  • return 0 ;
  • }
  • return DefWindowProc(hwnd, message, wParam, lParam) ;
  • }
  • 運行結果:


    對于初學者,這段代碼“又臭又長”,難于理解,有點嚇人。但這是一個Windows程序的基本框架,只不過不像C語言的框架那么簡單,幾行代碼搞定。大家不要急于理解每行代碼的含義,大部分代碼直接拿來使用就可以。

    1) 注冊窗口類

    在Windows中,調用 CreateWindow() 函數可以創建一個窗口(請看上面的代碼)。窗口有很多屬性,比如大小、位置、標題、背景顏色、鼠標樣式、圖標等,在創建窗口時都需要指定。這些屬性比較多,超過10個,但是有一部分是通用的,不同的窗口,它們的值一般相同,Windows將這些通用的屬性抽取出來,用一個結構體表示,就是上面代碼中WNDCLASS(window class縮寫):

  • WNDCLASS wndclass; //定義窗口類
  • //為窗口類的各個字段賦值
  • wndclass.style = CS_HREDRAW | CS_VREDRAW; //窗口風格
  • wndclass.lpfnWndProc = WndProc; //窗口過程
  • wndclass.cbClsExtra = 0; //暫時不需要理解
  • wndclass.cbWndExtra = 0; //暫時不需要理解
  • wndclass.hInstance = hInstance; //當前窗口句柄
  • wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); //窗口圖標
  • wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); //鼠標樣式
  • wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH); //窗口背景畫刷
  • wndclass.lpszMenuName = NULL ; //窗口菜單
  • wndclass.lpszClassName= szClassName; //窗口類名
  • 這個結構體,我們稱之為窗口類。如果你有面向對象的編程經驗,那么會很容易理解,沒有的話也沒關系,你可以認為,基于該結構體創建的窗口屬于同一個類別,有很多屬性是相同的。

    注意最后的字段lpszClassName,它指明了當前窗口類的名字,將這個名字傳遞給?CreateWindow() 函數,就能根據該窗口類來創建窗口。也就是說,以后想使用窗口類,只要知道它的名字就可以(也就是字段lpszClassName的值)。

    窗口類僅僅是一個結構體,如果只是定義了結構體變量,那么在使用時并不能通過?lpszClassName 字段的值找到這個結構體。所以還要調用 RegisterClass() 來注冊,讓系統知道窗口類的名字,下次使用時才能找到。

    作為簡明教程,我們并不打算深入研究窗口類的每一個字段的含義,下面是對它們的簡要說明:

    字段說明
    style窗口風格。對于初學者,常用的取值為CS_HREDRAW | CS_VREDRAW,表示當窗口大小改變時重繪窗口,這樣才能保證文字始終處于窗口中間。style還有很多取值,這里不一一講解,有興趣的讀者可以查看:WNDCLASS中style字段的取值(wndclass.style的取值)
    lpfnWndProc窗口處理過程,下面會詳細講解。
    hInstance當前窗口句柄。
    hIcon窗口圖標。也就是程序運行時在左上角和任務欄看到的圖標,需要通過LoadIcon函數加載。
    hCursor鼠標樣式。需要通過LoadCursor函數加載。
    hbrBackground窗口背景畫刷。也就是窗口背景的填充顏色,后面我們會講解畫筆、畫刷和畫布的概念。
    lpszMenuName窗口菜單。也就是標題欄下方看到的多種多樣的菜單,上面的程序沒有菜單,所以值為 NULL。
    lpszClassName窗口類的名字。每個窗口類的名字都是不同的,以便與其他窗口類區分。

    2) 創建窗口

    有了窗口類,就可以根據它來創建窗口了。創建窗口使用 CreateWindows() 函數,如下所示:

  • hwnd = CreateWindow(
  • szClassName, // 窗口類的名字
  • TEXT("Welcome"), //窗口標題(出現在標題欄)
  • WS_OVERLAPPEDWINDOW, //窗口風格
  • CW_USEDEFAULT, //初始化時窗口x軸坐標
  • CW_USEDEFAULT, //初始化時窗口y軸坐標
  • 500, //窗口寬度
  • 300, //窗口高度
  • NULL, //父窗口句柄。這里沒有父窗口,所以為 NULL
  • NULL, //窗口菜單句柄。當前窗口沒有菜單,所以為 NULL
  • hInstance, //當前窗口的句柄,通過 WinMain 函數傳入。
  • NULL //不使用該值
  • );
  • 幾點說明:
    A) CreateWindow 的第一個參數就是窗口類的名字,通過這個名字可以找到剛才注冊的窗口類,然后再根據它來創建窗口。

    B) 顯示器上的坐標與數學中的不同,顯示器的左上角是坐標原點,從原點向右是x軸,向下是y軸,都是正坐標,沒有負數。如下圖所示:


    C) 參數 hInstance 是通過主函數 WinMain 傳入的。

    注意:通過 CreateWindows() 函數創建窗口后,僅僅是為窗口分配了內存空間,獲得了句柄,但窗口并沒有顯示出來,所以還需要調用?ShowWindow() 函數來顯示窗口。

    而調用了 ShowWindow() 函數又僅僅是將窗口顯示出來,但不會進行客戶區的繪制,所以還需要調用 UpdateWindow() 函數,生成 VM_PAINT 消息,將客戶區中的各種控件繪制出來,下面會講解。

    至此,一個窗口的創建工作就已經完成了。窗口的各種屬性,在窗口類和 CreateWindow() 函數的參數中都進行了說明。

    注意:在窗口類 wndclass 中指定的窗口樣式以 CS 開頭,是通用的;而在 CreateWindow 函數中指定的窗口樣式以 WS 開頭,只對當前窗口有效,詳情請查看《CreateWindow窗口風格取值》。

    3) 進行消息循環

    在 UpdateWindow 函數被調用之后,新建的窗口在屏幕中就可以顯示了。此時,程序必須能夠接受用戶的鍵盤或鼠標事件,例如按下回車鍵、右擊鼠標等。

    在《與windows編程有關的重要概念》一節中講到了Windows的消息機制。Windows 會為每個應用程序維護一個消息隊列,當有事件發生時,Windows會自動將這些事件轉換為“消息”,并投遞到消息隊列。

    在我們的程序中,可以通過一段“消息循環”代碼來從消息隊列中獲取消息:

  • while( GetMessage(&msg, NULL, 0, 0) ){
  • TranslateMessage(&msg); //翻譯消息
  • DispatchMessage (&msg); //分派消息
  • }
  • GetMessage 函數用來從消息隊列中獲取一條消息,并保存到 MSG 結構體變量中。作為簡明教程,我們不再詳細分析 getMessage 函數的各個參數,讀者根據上面的代碼“照貓畫虎”就可以,不會影響你后續的學習。

    注意:GetMessage 的返回值永遠為非零值,while 循環會一直進行下去。如果隊列中沒有消息,GetMessage 函數會等待,直到有消息進入。

    獲取到消息后,需要調用 TranslateMessage 函數對消息進行轉換(翻譯),然后再調用 DispatchMessage 函數將消息傳給窗口過程去處理(調用窗口過程)。

    4) 窗口過程

    所謂窗口過程,就是處理窗口事件的函數,也就是上面代碼中最后的?WndProc 函數。GetMessage 每獲取到一條消息,最終都會丟給窗口過程去處理。

    窗口過程有一個參數?message,會傳入發生的事件類型,常用的有:

    • WM_CREATE:窗口被創建。
    • WM_PAINT:窗口需要更新或重繪。
    • WM_WM_DESTROY:窗口被銷毀(關閉)。


    WM_CREATE 和 WM_DESTROY 很容易理解,WM_PAINT 將在下節中詳細講解,它非常重要,不理解 WM_PAINT 可以說就沒有學會Windows編程。

    不同的消息往往需要進行不同的處理,所以一般通過 switch case 語句來匹配。

    注意:你可以對獲取到的消息進行處理,加入自己的業務邏輯;也可以不處理,讓Windows自己看著辦(默認處理方式)。窗口過程最后一條語句:

    return DefWindowProc(hwnd, message, wParam, lParam) ;

    它的作用就是讓Windows自己處理應用程序沒有處理的消息,必須要有該語句。

    窗口過程在窗口類中指明,然后就不用管了,不需要我們顯式調用。

    最后的總結

    上面講到的,是開發一個Windows應用程序的基本流程,也是Windows應用程序的代碼模板,你不需要記住每個細節,直接套用就可以。

    編寫Windows應用程序的步驟:

    • 注冊窗口類
    • 根據窗口類來創建窗口
    • 進入無休止的消息循環
    • 編寫窗口過程


    有了代碼模板,剩下的主要工作就是處理各種各樣的事件了,也就是在窗口過程中編寫代碼。

    總結

    以上是生活随笔為你收集整理的一个完整的Windows程序框架的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。