第三章跟蹤你的窗口和使用GDI
簡介
如果你看過了頭兩篇連載,這次我們將學(xué)習(xí)WINDOWS GDI(圖形設(shè)備接口)和其它一些相關(guān)的東西,象響應(yīng)用戶輸入和處理Windows產(chǎn)生的一些消息。至于顯示圖形,我們將接觸三個課題:文本顯示,繪制象素,顯示位圖。我們先來研究一下幾個Windows消息的細節(jié)。重復(fù)的話:你需要C語言的基礎(chǔ)知識,好看過上兩章。由于本章將使你能做一個具體的圖形DEMO,有一個源代碼例程附在本章后面。是用Visual C++寫的和編譯的。在連載一里,我們創(chuàng)建和注冊了一個窗口類,其中有一行定義了窗口的風(fēng)格(功能),是這個樣子:
sampleClass.style =
CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
// standard settings
其中三個屬性是很一般的,但這個——CS_OWNDC,需要解釋一下。設(shè)備上下文是一個結(jié)構(gòu),是一個表現(xiàn)一組圖形對象和屬性的結(jié)構(gòu),還有一些輸出設(shè)備的設(shè)置和屬性。使用設(shè)備上下文允許你直接操縱圖形,不用考慮低級細節(jié)。Windows GDI是一個圖形翻譯系統(tǒng),是介于應(yīng)用程序和圖形硬件之間的一層。GDI可以輸出到任意的兼容設(shè)備,不過常使用的設(shè)備是視頻監(jiān)視器、圖形硬拷貝設(shè)備(如打印機或繪圖儀),或者是內(nèi)存中的圖元文本。GDI函數(shù)能夠繪制直線、曲線、封閉的圖形和文本。所有訪問GDI的Windows函數(shù)都需要一個設(shè)備上下文句柄作為參數(shù)。這是非常容易做到的。你若想得到一個窗口的設(shè)備上下文句柄,你可以用這個函數(shù):
HDC GetDC(
HWND hWnd // handle to a window
);
很簡單,所有你做的是,把要操作的窗口的句柄傳遞給它,然后返回一個設(shè)備上下文句柄。如果你傳遞的是NULL,將返回整個屏幕的設(shè)備上下文(DC,以后都用DC表示)句柄。如果函數(shù)調(diào)用失敗,將返回NULL。
處理顯示圖形的DC類型,稱作顯示DC,處理打印的,稱作打印DC;處理位圖數(shù)據(jù)的,稱作內(nèi)存DC,還有其它一些設(shè)備DC。感覺有點復(fù)雜吧,不要緊,這是Windows,它的主要功能就是迷惑群眾。一旦我們接觸一些代碼,就不會覺得難了。
當(dāng)你結(jié)束使用DC時,一定要釋放它,也就是釋放它占用的內(nèi)存空間。要把這種思想貫穿到以后的編程中去,占用了內(nèi)存,不用時要釋放,切記!釋放DC是一個很簡單的函數(shù):
int ReleaseDC(
HWND hWnd, // handle to window
HDC hDC // handle to device context
);
若成功釋放,返回值是1,否則是0。參數(shù)有注釋,我還是說一下:
※ HWND hWnd:你所要控制的那個窗口的句柄。如果你開始傳遞的是NULL,現(xiàn)在還要傳遞NULL。
※ HDC hDC:DC的句柄。
在用DC和GDI進行圖形顯示前,我們先看看創(chuàng)建窗口實例時要遇到的幾條重要的消息。我將要提到的四條消息是:WM_MOVE、WM_SIZE、WM_ACTIVATE、WM_PAINT。
追蹤窗口狀態(tài)
頭兩個是很簡單的。當(dāng)窗口被用戶移動時將發(fā)送WM_MOVE消息,窗口新位置的坐標(biāo)儲存在lparam中。(還記得嗎,消息在lparam和wparam中被進一步描述,它們是消息控制函數(shù)的參數(shù))lparam的低端字中存儲窗口客戶區(qū)左上角的坐標(biāo)x,高端字中存儲坐標(biāo)y。當(dāng)窗口的大小被改變時,將發(fā)送WM_SIZE消息。同WM_MOVE消息差不多,lparam的低端字中存儲客戶區(qū)的寬度,高端字存儲高度。同WM_MOVE不同的是,wparam參數(shù)也控制了一些重要的東西。它可以是下列中任意一個值:
※ SIZE_MAXHIDE:其它的窗口被大化了。
※ SIZE_MAXIMIZED:本窗口被大化了。
※ SIZE_MAXSHOW:其它的窗口被還原了。
※ SIZE_MINIMIZED:本窗口被小化了。
※ SIZE_RESTORED:窗口被改變了尺寸,但既沒大化,也沒有小化。
當(dāng)我編寫窗口實例時,我通常喜歡把窗口的當(dāng)前位置和大小保留在幾個全局變量里。假設(shè)我們命名這些全局變量為xPos,yPos,xSize和ySize,你好這樣控制WM_SIZE和WM_MOVE這兩個消息:
if (msg == WM_SIZE)
{
xSize = LOWORD(lparam);
ySize = HIWORD(lparam);
}
if (msg == WM_MOVE)
{
xPos = LOWORD(lparam);
yPos = HIWORD(lparam);
}
現(xiàn)在輪到WM_ACTIVATE消息了。它告訴你一個新窗口被激活。這是很有用的,因為如果出現(xiàn)優(yōu)先的申請,你就不可能處理程序里的所有邏輯。有時,例如寫一個全屏的DIRECTX程序,忽略WM_ACTIVATE消息將導(dǎo)致你的程序出現(xiàn)致命的錯誤,可能它做了一些你不希望它做的事情。在任何情況下,守候WM_ACTIVATE消息從而采取行動,是一個好主意。
窗口被激活和被解除激活都會發(fā)出WM_ACTIVATE消息,我們可以通過檢測wparam的低端字來得知是被激活還是被取消。這將有三種可能的值:
※ WA_CLICKACTIVE:窗口被鼠標(biāo)激活。
※ WA_ACTIVE:窗口被其它東西激活。(鍵盤、函數(shù)調(diào)用、等等)
※ WA_INACTIVE:窗口被解除激活。
為了處理這個消息,我保留了另一個全局變量bFocus,當(dāng)接收到WM_ACTIVATE消息,它的值將改變。示例如下:
if (msg == WM_ACTIVATE)
{
if (LOWORD(wparam) == WA_INACTIVE)
focus = FALSE;
else
focus = TRUE;
// tell Windows we handled it
return(0);
}
簡介
如果你看過了頭兩篇連載,這次我們將學(xué)習(xí)WINDOWS GDI(圖形設(shè)備接口)和其它一些相關(guān)的東西,象響應(yīng)用戶輸入和處理Windows產(chǎn)生的一些消息。至于顯示圖形,我們將接觸三個課題:文本顯示,繪制象素,顯示位圖。我們先來研究一下幾個Windows消息的細節(jié)。重復(fù)的話:你需要C語言的基礎(chǔ)知識,好看過上兩章。由于本章將使你能做一個具體的圖形DEMO,有一個源代碼例程附在本章后面。是用Visual C++寫的和編譯的。在連載一里,我們創(chuàng)建和注冊了一個窗口類,其中有一行定義了窗口的風(fēng)格(功能),是這個樣子:
sampleClass.style =
CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
// standard settings
其中三個屬性是很一般的,但這個——CS_OWNDC,需要解釋一下。設(shè)備上下文是一個結(jié)構(gòu),是一個表現(xiàn)一組圖形對象和屬性的結(jié)構(gòu),還有一些輸出設(shè)備的設(shè)置和屬性。使用設(shè)備上下文允許你直接操縱圖形,不用考慮低級細節(jié)。Windows GDI是一個圖形翻譯系統(tǒng),是介于應(yīng)用程序和圖形硬件之間的一層。GDI可以輸出到任意的兼容設(shè)備,不過常使用的設(shè)備是視頻監(jiān)視器、圖形硬拷貝設(shè)備(如打印機或繪圖儀),或者是內(nèi)存中的圖元文本。GDI函數(shù)能夠繪制直線、曲線、封閉的圖形和文本。所有訪問GDI的Windows函數(shù)都需要一個設(shè)備上下文句柄作為參數(shù)。這是非常容易做到的。你若想得到一個窗口的設(shè)備上下文句柄,你可以用這個函數(shù):
HDC GetDC(
HWND hWnd // handle to a window
);
很簡單,所有你做的是,把要操作的窗口的句柄傳遞給它,然后返回一個設(shè)備上下文句柄。如果你傳遞的是NULL,將返回整個屏幕的設(shè)備上下文(DC,以后都用DC表示)句柄。如果函數(shù)調(diào)用失敗,將返回NULL。
處理顯示圖形的DC類型,稱作顯示DC,處理打印的,稱作打印DC;處理位圖數(shù)據(jù)的,稱作內(nèi)存DC,還有其它一些設(shè)備DC。感覺有點復(fù)雜吧,不要緊,這是Windows,它的主要功能就是迷惑群眾。一旦我們接觸一些代碼,就不會覺得難了。
當(dāng)你結(jié)束使用DC時,一定要釋放它,也就是釋放它占用的內(nèi)存空間。要把這種思想貫穿到以后的編程中去,占用了內(nèi)存,不用時要釋放,切記!釋放DC是一個很簡單的函數(shù):
int ReleaseDC(
HWND hWnd, // handle to window
HDC hDC // handle to device context
);
若成功釋放,返回值是1,否則是0。參數(shù)有注釋,我還是說一下:
※ HWND hWnd:你所要控制的那個窗口的句柄。如果你開始傳遞的是NULL,現(xiàn)在還要傳遞NULL。
※ HDC hDC:DC的句柄。
在用DC和GDI進行圖形顯示前,我們先看看創(chuàng)建窗口實例時要遇到的幾條重要的消息。我將要提到的四條消息是:WM_MOVE、WM_SIZE、WM_ACTIVATE、WM_PAINT。
追蹤窗口狀態(tài)
頭兩個是很簡單的。當(dāng)窗口被用戶移動時將發(fā)送WM_MOVE消息,窗口新位置的坐標(biāo)儲存在lparam中。(還記得嗎,消息在lparam和wparam中被進一步描述,它們是消息控制函數(shù)的參數(shù))lparam的低端字中存儲窗口客戶區(qū)左上角的坐標(biāo)x,高端字中存儲坐標(biāo)y。當(dāng)窗口的大小被改變時,將發(fā)送WM_SIZE消息。同WM_MOVE消息差不多,lparam的低端字中存儲客戶區(qū)的寬度,高端字存儲高度。同WM_MOVE不同的是,wparam參數(shù)也控制了一些重要的東西。它可以是下列中任意一個值:
※ SIZE_MAXHIDE:其它的窗口被大化了。
※ SIZE_MAXIMIZED:本窗口被大化了。
※ SIZE_MAXSHOW:其它的窗口被還原了。
※ SIZE_MINIMIZED:本窗口被小化了。
※ SIZE_RESTORED:窗口被改變了尺寸,但既沒大化,也沒有小化。
當(dāng)我編寫窗口實例時,我通常喜歡把窗口的當(dāng)前位置和大小保留在幾個全局變量里。假設(shè)我們命名這些全局變量為xPos,yPos,xSize和ySize,你好這樣控制WM_SIZE和WM_MOVE這兩個消息:
if (msg == WM_SIZE)
{
xSize = LOWORD(lparam);
ySize = HIWORD(lparam);
}
if (msg == WM_MOVE)
{
xPos = LOWORD(lparam);
yPos = HIWORD(lparam);
}
現(xiàn)在輪到WM_ACTIVATE消息了。它告訴你一個新窗口被激活。這是很有用的,因為如果出現(xiàn)優(yōu)先的申請,你就不可能處理程序里的所有邏輯。有時,例如寫一個全屏的DIRECTX程序,忽略WM_ACTIVATE消息將導(dǎo)致你的程序出現(xiàn)致命的錯誤,可能它做了一些你不希望它做的事情。在任何情況下,守候WM_ACTIVATE消息從而采取行動,是一個好主意。
窗口被激活和被解除激活都會發(fā)出WM_ACTIVATE消息,我們可以通過檢測wparam的低端字來得知是被激活還是被取消。這將有三種可能的值:
※ WA_CLICKACTIVE:窗口被鼠標(biāo)激活。
※ WA_ACTIVE:窗口被其它東西激活。(鍵盤、函數(shù)調(diào)用、等等)
※ WA_INACTIVE:窗口被解除激活。
為了處理這個消息,我保留了另一個全局變量bFocus,當(dāng)接收到WM_ACTIVATE消息,它的值將改變。示例如下:
if (msg == WM_ACTIVATE)
{
if (LOWORD(wparam) == WA_INACTIVE)
focus = FALSE;
else
focus = TRUE;
// tell Windows we handled it
return(0);
}

