視窗與訊息 (window and message)
DESCRIPTION
視窗與訊息 (Window and Message). 井民全製作. 建立自己的視窗. CreateWindow 函式就可以建立視窗 背景知識 子視窗 ( 控制項視窗 , 子視窗控制項 ) 選單按鈕 , 核取方塊 , 清單方塊 , 捲動列 , 文字輸入 都是 視窗 的一種. child window. Message 概念. Message: 視窗間使用 message 作通訊 程式建立的每個視窗都有一相關的 視窗訊息處理程式 Window class 標示了 視窗訊息的處理程式 - PowerPoint PPT PresentationTRANSCRIPT
視窗與訊息視窗與訊息(Window and Message)(Window and Message)
井民全製作
建立自己的視窗建立自己的視窗CreateWindow CreateWindow 函式就可以建立視窗函式就可以建立視窗背景知識背景知識– 子視窗 子視窗 (( 控制項視窗控制項視窗 ,, 子視窗控制項子視窗控制項 ))
選單按鈕選單按鈕 , , 核取方塊核取方塊 , , 清單方塊清單方塊 , , 捲動列捲動列 , , 文字文字輸入輸入
都是都是視窗視窗的一種的一種
child window
Message Message 概念概念Message: Message: 視窗間使用 視窗間使用 message message 作通訊作通訊
– 程式建立的每個視窗都有一相關的程式建立的每個視窗都有一相關的視窗訊息處理程式視窗訊息處理程式
– Window class Window class 標示了標示了視窗訊息的處理程式視窗訊息的處理程式 多個視窗可同屬一個 多個視窗可同屬一個 window classwindow class 並且使用同一個處理程式並且使用同一個處理程式
改變視窗大小
OS
message
你的應用程式
WndProc( ) function
MessageMessageLoader
載入應用程式
配置專屬Message Queue
執行 MessageLoop 讀取事件
MSG msg; …while(GetMessage(&msg,NULL,0,0){ TranslateMessage(&msg); DispatchMessage(&msg);}
message loop
Create window Create window 三個主要程序三個主要程序#include <windows.h>LRESULT CALLBACK WndProc( HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE …){
}
1. 註冊 Window Class RegisterClass(&wndclass)
1. 註冊 Window Class RegisterClass(&wndclass)
2. 建立視窗 hwnd=CreateWindow(…)
2. 建立視窗 hwnd=CreateWindow(…)
3. Message loop3. Message loop
MSG msg; …while(GetMessage(&msg,NULL,0,0){ TranslateMessage(&msg); DispatchMessage(&msg);}
4. 訊息處理函式LRESULT CALLBACK WndProc(HWND hwnd, …)
4. 訊息處理函式LRESULT CALLBACK WndProc(HWND hwnd, …)
1. 註冊 Window Class
WNDCLASS wndclass; wcx.cbSize = sizeof(wcx); // size of structure wcx.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes wcx.lpfnWndProc = MainWndProc; // points to window procedure wcx.cbClsExtra = 0; // no extra class memory wcx.cbWndExtra = 0; // no extra window memory wcx.hInstance = hinstance; // handle to instance wcx.hIcon = LoadIcon(NULL,IDI_APPLICATION); // predefined app. icon wcx.hCursor = LoadCursor(NULL,IDC_ARROW); // predefined arrow wcx.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH); wcx.lpszMenuName = NULL; // name of menu resource wcx.lpszClassName = "MainWClass";
WNDCLASS wndclass; wcx.cbSize = sizeof(wcx); // size of structure wcx.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes wcx.lpfnWndProc = MainWndProc; // points to window procedure wcx.cbClsExtra = 0; // no extra class memory wcx.cbWndExtra = 0; // no extra window memory wcx.hInstance = hinstance; // handle to instance wcx.hIcon = LoadIcon(NULL,IDI_APPLICATION); // predefined app. icon wcx.hCursor = LoadCursor(NULL,IDC_ARROW); // predefined arrow wcx.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH); wcx.lpszMenuName = NULL; // name of menu resource wcx.lpszClassName = "MainWClass";
RegisterClass(&wndclass)指定你的 windows class name
將你的 class name 註冊
如果寬度或高度改變 , 則重畫整個視窗
2.2. 建立視窗
hwnd = CreateWindow ("MainWClass", // window class name TEXT ("The Hello Program"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ;
hwnd = CreateWindow ("MainWClass", // window class name TEXT ("The Hello Program"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ;
指定你前面設定好的 windows class name指定你前面設定好的 windows class name
這個變數由 WinMain 參數得到
這個變數由 WinMain 參數得到
把視窗顯示出來把視窗顯示出來
*WS_XXX Window style 選項* CW_ XXX Create Window 選項
訊息處理函式 – WinProc( )LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (message) { case WM_CREATE: PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ; return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; DrawText (hdc, TEXT ("Hello, Windows 2000!"), -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) ; // 呼叫預設的 window procedure } // 做預設的處理 , 以保證每一個 message 都被處 // 理
當 window 剛被建立時 , 撥放音效檔當 window 剛被建立時 , 撥放音效檔
當 window 被要求重新繪製時 , 要做的工作當 window 被要求重新繪製時 , 要做的工作
當 window 被刪除時 , 要做的工作當 window 被刪除時 , 要做的工作
Uppercase IdentifiersUppercase Identifiers
CS_HREDRAW DT_VCENTER SND_FILENAME
CS_VREDRAW IDC_ARROW WM_CREATE
CW_USEDEFAULT IDI_APPLICATION WM_DESTROY
DT_CENTER MB_ICONERROR WM_PAINT
DT_SINGLELINE SND_ASYNC WS_OVERLAPPEDWINDOW
Prefix Constant
CS Class style option
CW Create window option
DT Draw text option
IDI ID number for an icon
IDC ID number for a cursor
MB Message box options
SND Sound option
WM Window message
WS Window style
WM_PAINT 屬於 Window message
New Data TypeNew Data Type
UINT UINT unsigned int unsigned int
PSTR PSTR char * char *
LRESULT LRESULT LONG LONG
16-bit Windows16-bit Windows 32-bit Windows32-bit Windows
WPARAMWPARAM WORDWORD UINT UINT
LPARAMLPARAM LONGLONG LONGLONG
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow);
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
_stdcall
__stdcall: fun(1,2,3,4)1. 最右邊的參數先推入堆疊2. 函式返回前 , 自行移除堆疊中的參數*Win32 API 使用 __stdcall
先 push 進堆疊先 push 進堆疊
節省程式碼的原因
Getting a Handle on HandlesGetting a Handle on Handles
Handle Handle 在視窗程式中使用的非常頻繁在視窗程式中使用的非常頻繁– 一個整數一個整數– 他代表一個物件他代表一個物件– Windows Windows 使用代號來操作物件使用代號來操作物件
Identifier Meaning
HINSTANCE Handle to an "instance"—the program itself
HWND Handle to a window
HDC Handle to a device context 我們已經看過的 handle如果你需要輸出資料到裝置你會需要 DC
Hungarian Notation (Hungarian Notation ( 匈牙利表示匈牙利表示法法 ))
紀念 紀念 Microsoft Microsoft 程式設計師 程式設計師 Charles SimonyiCharles Simonyi
變數名稱以一個或多個變數名稱以一個或多個小寫字母小寫字母開始開始– 這些字母表示資料型態這些字母表示資料型態
szszCmdLine CmdLine 以以 0 0 結尾的字串結尾的字串hhInstance Instance 與 與 hhPrevInstance PrevInstance h h 表示 表示 HandleHandleiiCmdShow CmdShow i i 表示 表示 intint
structure structure 變數變數– 以 以 structure name structure name 為小寫當 為小寫當 prefix prefix 或 變數的名稱或 變數的名稱
msg msg MSG structure MSG structurecndclass cndclass WNDCLASSES structure WNDCLASSES structureps ps PAINTSTRUCT structure PAINTSTRUCT structurerect rect RECT structure RECT structure
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvsgen/html/hunganotat.asp匈牙利表示法進一步參考資料匈牙利表示法進一步參考資料 ::
附錄附錄 : : 完整的程式碼 完整的程式碼 #include <windows.h>// 視窗訊息處理函式的 prototypeLRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; // Windows 程式第一個進入點 WinMain(...) int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT ("HelloWin") ; HWND hwnd ; MSG msg ; // ===============Step 1: 建立並且註冊 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 = szAppName ; // << -- 指定目前的 class name
#include <windows.h>// 視窗訊息處理函式的 prototypeLRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; // Windows 程式第一個進入點 WinMain(...) int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT ("HelloWin") ; HWND hwnd ; MSG msg ; // ===============Step 1: 建立並且註冊 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 = szAppName ; // << -- 指定目前的 class name
// ============== Step 2: 建立視窗並且傳回 window handle ========== hwnd = CreateWindow (szAppName, // 指定 window class name TEXT ("The Hello Program"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters // =============== Step 3: 把視窗顯示出來 ======================== ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ;
// =============== Step 4: Message - Loop 的部分 =================== while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ;}
// ============== Step 2: 建立視窗並且傳回 window handle ========== hwnd = CreateWindow (szAppName, // 指定 window class name TEXT ("The Hello Program"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters // =============== Step 3: 把視窗顯示出來 ======================== ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ;
// =============== Step 4: Message - Loop 的部分 =================== 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_CREATE: // << -- 當視窗被建立時 , 事件處理程式碼 PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ; return 0 ; case WM_PAINT: // << -- 當視窗被要求重新繪製時 , 事件處理程式碼 hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; DrawText (hdc, TEXT ("Hello, Windows!"), -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) ;}
// 視窗訊息處理函式LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (message) { case WM_CREATE: // << -- 當視窗被建立時 , 事件處理程式碼 PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ; return 0 ; case WM_PAINT: // << -- 當視窗被要求重新繪製時 , 事件處理程式碼 hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; DrawText (hdc, TEXT ("Hello, Windows!"), -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) ;}
End of HelloWin.c
在你專案目錄中的重要檔案在你專案目錄中的重要檔案
FileFile DescriptionDescription
Debug Debug 目錄目錄 執行檔與暫存檔HelloWinHelloWin.vcproj.vcproj Visual C++ .Net 專案檔HelloWin.slnHelloWin.sln 包含 .vcproj 進入點的 solution file
HelloWin.c (HelloWin.c ( 或 或 cpp)cpp) Source file
.rc.rc Resource Script file
HellWin.ncbHellWin.ncb InteliSense Database file 可刪除可刪除
可刪除可刪除
編譯你的程式編譯你的程式找不到 PlaySoundA
你必須 import library winmm.lib
Project HelloWin Properties …
Step 1: Input
Step 2: Addition Dependence winmm.lib
winmm.lib
試著建立一個 試著建立一個 simple windows applicationsimple windows application
附錄附錄 : : (MFC (MFC 相關相關 )) 如何處理 如何處理 Button Button 的訊的訊息息
你可以藉由 Control Events tab 設定在主視窗中的 childwindow( 按鈕 )的 event 處理 !
但是 , 若我想要接收更多的事件時 , 要如何做 ?( 因為 Control Events tab 中沒有相關的設定 )
所有視窗的 所有視窗的 messagemessage
ms-help://MS.MSDNQTR.2004JAN.1033/vclib/html/_mfc_wm__message_handlers.3a_.l_.2d_.m.htm
L-M 的項目
你要 override 的部分你要 override 的部分
滑鼠按左鍵滑鼠按左鍵
滑鼠移動滑鼠移動
處理滑鼠按左鍵處理滑鼠按左鍵你必須要繼承 你必須要繼承 CButton, CButton, 並根據上一頁說並根據上一頁說明明 ,, 需要 需要 override override
afx_msg void OnLButtonDown( UINT nFlags, CPoint point );
你新按鈕類別的長相應該是長這樣你新按鈕類別的長相應該是長這樣
testDlg.h
建立新按鈕建立新按鈕新增一個按鈕新增一個按鈕 , , 在 在 Dialog Dialog 中中
testDlg.h
testDlg.cpp
結果結果
自訂處理按鈕事件