書接上回,我們先來看一個例子吧,我們畫了一個矩形和一個圓:
caseWM_PAINT:
HDChDC;
PAINTSTRUCTps;
hDC=BeginPaint(hwnd,&ps);
Rectangle(hDC,50,50,200,200);
Ellipse(hDC,100,100,300,300);
Ellipse(hDC,400,100,600,300);
Rectangle(hDC,350,50,500,200);
EndPaint(hwnd,&ps);
break;
你會感到奇怪,這兩個函數畫出的圖形怎麼會相互遮蓋呢?或許你猜出了原因了,這兩個函 數不是單純地畫“邊框”,其內部還被白色的背景填充着,讓它們可以相互遮擋而不是“透明”的。像前面講過的Rectangle、Ellipse、 RoundRect、Chord、Pie和本回要講的Polygon、PolyPolygon這些畫帶邊界框的填充圖形函數都是這樣的。
認識畫刷
在Windows中圖形是以當前設備描述表選中的畫刷來填充的。默認情況下,使用現有的白色畫刷,這意味着圖形內部將畫爲白色。Windows預定義了 六種現有畫刷:WHITE_BRUSH、LTGRAY_BRUSH、GRAY_BRUSH、DKGRAY_BRUSH、BLACK_BRUSH和 NULL_BRUSH (也叫HOLLOW_BRUSH),大家看名字就應該知道它們代表什麼顏色了吧。你可以將任何一種現有畫刷選入你的設備描述表中,就和你選擇一種畫筆一 樣。
Windows用HBRUSH定義畫刷句柄,可以像這樣定義一個畫刷句柄變量:
HBRUSH hBrush;
你可以通過調用GetStockObject來取得GRAY_BRUSH的句柄:
hBrush = (HBRUSH) GetStockObject (GRAY_BRUSH) ;//這裏需要強制類型轉換
你可以調用SelectObject將它選進設備描述表:
SelectObject (hdc, hBrush) ;
現在,如果你要用上面的提到的任意一個函數畫圖,則圖形內部將爲灰色。
如果您想畫一個沒有邊界框的圖形,可以將NULL_PEN選進設備描述表:
SelectObject (hdc,(HBRUSH) GetStockObject (NULL_PEN)) ;
上一回我曾提到過NULL_PEN有啥用?我估計這可能就是它的一個用途吧。
如果您想畫出圖形的邊界框,但不填入內部,則將NULL_BRUSH選進設備內容:
SelectObject (hdc, (HBRUSH) GetStockobject (NULL_BRUSH) ;
大家看到此,應該想出畫不互相遮蓋的圖形了吧:
case WM_PAINT:HDC hDC;PAINTSTRUCT ps;hDC=BeginPaint(hwnd,&ps);SelectObject(hDC, (HBRUSH) GetStockObject (NULL_BRUSH) ;
Rectangle(hDC,50,50,200,200);
Ellipse(hDC,100,100,300,300);
Ellipse(hDC,400,100,600,300);
Rectangle(hDC,350,50,500,200);
EndPaint(hwnd,&ps);break;
再認識畫刷
我們除了可以使用以上的現有畫刷,還可以創建自己的畫刷,就如同上回我們創建自己的畫筆一樣。而且過程也是類似的:
首先創建邏輯畫刷,這裏Windows爲我們提供了幾個函數可供使用;
然後使用SelectObject把畫刷選進設備描述表;
繪圖函數繪圖;
最後在釋放設備描述表(或者在選擇了另一種畫刷到設備內容中)之後,就可以調用DeleteObject來刪除畫刷了。
接着我們就來看一下這幾個創建畫刷的函數吧。
下面是建立邏輯畫刷的第一個函數:
hBrush = CreateSolidBrush (crColor) ;
函數中crColor爲COLORREF類型,指定畫刷顏色。
你還可以使用由水平、垂直或者傾斜的線組成的“影線標記(hatch marks)”來創建畫刷,這種風格的畫刷對着色條形圖的內部和在繪圖儀上進行繪圖最有用。創建影線畫刷的函數爲:
hBrush = CreateHatchBrush (iHatchStyle, crColor) ;
iHatchStyle參數描述影線標記的外觀。下圖顯示了六種可用的影線標記風格。
CreateHatchBrush中的crColor參數是影線的色彩。
你還可以使用這個函數創建邏輯畫刷:
hBrush = CreateBrushIndirect (&logbrush) ;
變量logbrush是一個類型爲LOGBRUSH(“邏輯畫刷”)的結構,該結構的三個字段如表5-4所示,lbStyle字段的值確定了Windows如何解釋其它兩個字段的值:
lbStyle (UINT) |
lbColor (COLORREF) |
lbHatch (LONG) |
BS_SOLID |
畫刷的色彩 |
忽略 |
BS_HOLLOW |
忽略 |
忽略 |
BS_HATCHED |
影線的色彩 |
影線畫刷風格 |
BS_PATTERN |
忽略 |
位圖的句柄 |
BS_DIBPATTERNPT |
忽略 |
指向DIB的指標 |
上一回我們用SelectObject將邏輯畫筆選進設備描述表,用DeleteObject刪除畫筆,用GetObject來取得邏輯畫筆的信息。對於畫刷,同樣能使用這三個函數。
一旦你取得到了畫刷句柄,就可以使用SelectObject將該畫刷選進設備描述表:
SelectObject (hdc, hBrush) ;
然後,你可以使用DeleteObject函數刪除所建立的畫刷:
DeleteObject (hBrush) ;
但是,不要刪除目前選進設備描述表內的畫刷。
如果您需要取得畫刷的信息,可以調用GetObject:
GetObject (hBrush, sizeof (LOGBRUSH), (LPVOID) &logbrush) ;
其中,logbrush是一個類型爲LOGBRUSH的結構。
Polygon函數和多邊形填充
我們好像還有兩個函數沒有講,趁我還沒有忘記,趕緊把它講完吧。
Polygon函數也是一個畫帶邊界框的填充圖形函數,它的調用與Polyline函數相似:
Polygon (hdc, apt, iCount) ;
其中,apt參數是POINT結構的一個數組,iCount是點的數目。如果該數組中的最後一個點與第一個點不同,則Windows將會再加一條線,將最後一個點與第一個點連起來(在Polyline函數中,Windows不會這麼做)。
PolyPolygon函數如下所示:
PolyPolygon (hdc, apt, aiCounts, iPolyCount) ;
該函數繪製多個多邊形。最後一個參數給出了所畫的多邊形的個數。對於每個多邊形,aiCounts數組給出了多邊形的端點數。apt數組具有全部多邊形的所有點。除返回值以外,PolyPolygon在功能上與下面的代碼相同:
for (i = 0, iAccum = 0 ; i < iPolyCount ; i++)
{
Polygon (hdc, apt + iAccum, aiCounts[i]) ;
iAccum += aiCounts[i] ;
}
對於Polygon和PolyPolygon函數,Windows使用定義在設備描述表中的當前畫刷來填充這個帶邊界的區域。至於填充內部的方式,則取決於多邊形填充方式,你可以用SetPolyFillMode函數來設定:
SetPolyFillMode (hdc, iMode) ;
默認情況下,多邊形填入方式是ALTERNATE,但是您可以將它設定爲WINDING。
對於ALTERNATE方式,您可以設想從一個無窮大的封閉區域內部的點畫線,只有假想的線穿過了奇數條邊界線時,才填充封閉區域,當然若爲偶數,則不填充該區域。這就是星的角被填充而中心沒被填充的原因。
對於WINDING方式:方法一樣,如爲奇數,填充該區域;如爲偶數則要根據邊框線的方向來判斷:如果穿過的邊框線在不同方向的邊框線數目相等,則不填充,如不等,則填充。還是來分析個例子吧,比如要繪製下圖,線上的箭頭指出了畫線的方向。
用這兩種方式填充的效果如下圖(左側是ALTERNATE方式,右側是WINDING方式):
兩種方式都會填充三個封閉的L形區域,號碼從1到3。號碼爲4和5的兩個小內部區域,在ALTERNATE方式下不會被填充。但是,在WINDING方式下,號碼爲5的區域會被填充,因爲從區域內必須穿過兩條相同方向的線才能到達圖形外部。號碼爲4的區域不會被填充,因爲必須穿過兩條方向相反的線。
經過這兩節繪圖課後,大家應該對Windows中常用的繪圖函數有所瞭解了,發揮你的想象力,去畫一些漂亮的圖形吧!