一个完整的Windows程序框架
前面我們演示了帶界面的Windows程序,但那僅僅是一個彈窗,調用MessageBox函數就可以實現,不是一個真正意義上的窗口。我們通常所說的窗口包含最大化、最小化、關閉按鈕,也包含菜單、單選框、圖像等各種控件。
一個完整的Windows程序框架:
運行結果:
對于初學者,這段代碼“又臭又長”,難于理解,有點嚇人。但這是一個Windows程序的基本框架,只不過不像C語言的框架那么簡單,幾行代碼搞定。大家不要急于理解每行代碼的含義,大部分代碼直接拿來使用就可以。
1) 注冊窗口類
在Windows中,調用 CreateWindow() 函數可以創建一個窗口(請看上面的代碼)。窗口有很多屬性,比如大小、位置、標題、背景顏色、鼠標樣式、圖標等,在創建窗口時都需要指定。這些屬性比較多,超過10個,但是有一部分是通用的,不同的窗口,它們的值一般相同,Windows將這些通用的屬性抽取出來,用一個結構體表示,就是上面代碼中WNDCLASS(window class縮寫):
這個結構體,我們稱之為窗口類。如果你有面向對象的編程經驗,那么會很容易理解,沒有的話也沒關系,你可以認為,基于該結構體創建的窗口屬于同一個類別,有很多屬性是相同的。
注意最后的字段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() 函數,如下所示:
幾點說明:
A) CreateWindow 的第一個參數就是窗口類的名字,通過這個名字可以找到剛才注冊的窗口類,然后再根據它來創建窗口。
B) 顯示器上的坐標與數學中的不同,顯示器的左上角是坐標原點,從原點向右是x軸,向下是y軸,都是正坐標,沒有負數。如下圖所示:
C) 參數 hInstance 是通過主函數 WinMain 傳入的。
注意:通過 CreateWindows() 函數創建窗口后,僅僅是為窗口分配了內存空間,獲得了句柄,但窗口并沒有顯示出來,所以還需要調用?ShowWindow() 函數來顯示窗口。
而調用了 ShowWindow() 函數又僅僅是將窗口顯示出來,但不會進行客戶區的繪制,所以還需要調用 UpdateWindow() 函數,生成 VM_PAINT 消息,將客戶區中的各種控件繪制出來,下面會講解。
至此,一個窗口的創建工作就已經完成了。窗口的各種屬性,在窗口類和 CreateWindow() 函數的參數中都進行了說明。
3) 進行消息循環
在 UpdateWindow 函數被調用之后,新建的窗口在屏幕中就可以顯示了。此時,程序必須能夠接受用戶的鍵盤或鼠標事件,例如按下回車鍵、右擊鼠標等。
在《與windows編程有關的重要概念》一節中講到了Windows的消息機制。Windows 會為每個應用程序維護一個消息隊列,當有事件發生時,Windows會自動將這些事件轉換為“消息”,并投遞到消息隊列。
在我們的程序中,可以通過一段“消息循環”代碼來從消息隊列中獲取消息:
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自己看著辦(默認處理方式)。窗口過程最后一條語句:
它的作用就是讓Windows自己處理應用程序沒有處理的消息,必須要有該語句。
窗口過程在窗口類中指明,然后就不用管了,不需要我們顯式調用。最后的總結
上面講到的,是開發一個Windows應用程序的基本流程,也是Windows應用程序的代碼模板,你不需要記住每個細節,直接套用就可以。
編寫Windows應用程序的步驟:
- 注冊窗口類
- 根據窗口類來創建窗口
- 進入無休止的消息循環
- 編寫窗口過程
有了代碼模板,剩下的主要工作就是處理各種各樣的事件了,也就是在窗口過程中編寫代碼。
總結
以上是生活随笔為你收集整理的一个完整的Windows程序框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: poi 不自动计算 设置单元格公式_Ja
- 下一篇: matlab时域转复频域,信号与系统实验