參考 MFC ActiveX Controls: Painting an ActiveX Control
本文介紹ActiveX控件繪制過程以及如何更改繪制代碼以優化過程。(有關如何通過不使控件單獨恢復以前選擇的GDI對象來優化繪圖的技術,請參閱優化控制圖。在繪制完所有控件后,容器可以自動恢復原始對象。)
本文中的示例來自MFC ActiveX控件向導使用默認設置創建的控件。
繪制控件的整個過程以及ActiveX控件向導創建的代碼以支持繪制
ActiveX控件的繪制過程
最初顯示或重繪ActiveX控件時,它們遵循與使用MFC開發的其他應用程序類似的繪制過程,但有一個重要區別:ActiveX控件可以處於活動狀態或非活動狀態。
ActiveX控件容器中的子窗口表示活動控件。與其他窗口一樣,它在接收WM_PAINT消息時負責繪制自身。控件的基類COleControl在其OnPaint函數中處理此消息。此默認實現調用OnDraw控件的功能。
非活動控件的繪制方式不同。當控件處於非活動狀態時,其窗口要么不可見,要么不存在,因此無法接收繪制消息。相反,控件容器直接調用控件的OnDraw功能。這與活動控件的繪制過程不同,因為OnPaint永遠不會調用成員函數。
如前面段落中所討論的,ActiveX控件的更新方式取決於控件的狀態。但是,因為框架OnDraw在兩種情況下都調用成員函數,所以在此成員函數中添加大部分繪制代碼。
該OnDraw成員函數處理控制繪畫。當控件處於非活動狀態時,控件容器調用OnDraw,傳遞控件容器的設備上下文和控件占用的矩形區域的坐標。
框架傳遞給OnDraw成員函數的矩形包含控件占用的區域。如果控件處於活動狀態,則左上角為(0,0),並且傳遞的設備上下文用於包含控件的子窗口。如果控件處於非活動狀態,則左上角坐標不一定是(0,0),並且傳遞的設備上下文是針對包含控件的控件容器。
注意 重要的是,您的修改OnDraw不依賴於矩形的左上角等於(0,0),而是僅在傳遞給矩形的內部繪制OnDraw。如果繪制超出矩形區域,則可能會出現意外結果。
控件實現文件(.CPP)中的MFC ActiveX控件向導提供的默認實現(如下所示)使用白色筆刷繪制矩形,並使用當前背景顏色填充橢圓。
void CMyAxUICtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
if (!pdc)
return;
// TODO: Replace the following code with your own drawing code.
pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
pdc->Ellipse(rcBounds);
}
注意 在繪制控件時,不應該假設將作為pdc參數傳遞給OnDraw函數的設備上下文的狀態。有時,設備上下文由容器應用程序提供,不一定會初始化為默認狀態。特別是,明確選擇繪圖代碼所依賴的筆,畫筆,顏色,字體和其他資源。
如何優化繪制過程
優化你的繪制代碼
控件成功繪制后,下一步是優化OnDraw功能。
ActiveX控件繪制的默認實現繪制整個控件區域。這對於簡單的控件來說已經足夠了,但是在許多情況下,如果僅重新繪制需要更新的部分而不是整個控件,則重新繪制控件會更快。
該OnDraw函數通過傳遞rcInvalid提供了一種簡單的優化方法,rcInvalid是需要重繪的控件的矩形區域。使用此區域(通常小於整個控制區域)可加快繪制過程。
如何使用元文件繪制控件
在大多數情況下,函數的pdc參數OnDraw指向屏幕設備上下文(DC)。然而,當打印控件的圖像時或在打印預覽會話期間,接收用於渲染的DC是稱為“元文件DC”的特殊類型。與立即處理發送給它的請求的屏幕DC不同,元文件DC存儲稍后要回放的請求。在設計模式下,某些容器應用程序還可以選擇使用圖元文件DC來呈現控制圖像。
元數據繪圖請求可以由容器通過兩個接口函數進行:( IViewObject::Draw此函數也可以調用非元文件繪圖)和IDataObject::GetData。當元文件DC作為參數之一傳遞時,MFC框架調用COleControl :: OnDrawMetafile。因為這是一個虛擬成員函數,所以在控件類中重寫此函數可以進行任何特殊處理。默認行為調用COleControl::OnDraw。
要確保可以在屏幕和元文件設備上下文中繪制控件,必須僅使用屏幕和圖元文件DC中都支持的成員函數。請注意,坐標系可能無法以像素為單位進行測量。
因為默認實現OnDrawMetafile調用控件的OnDraw函數,所以只使用適合元文件和屏幕設備上下文的成員函數,除非你重寫OnDrawMetafile。下面列出了CDC可以在元文件和屏幕設備上下文中使用的成員函數的子集。有關這些函數的更多信息,請參閱MFC參考中的類CDC。
| Arc | BibBlt | Chord |
|---|---|---|
| Ellipse | Escape | ExcludeClipRect |
| ExtTextOut | FloodFill | IntersectClipRect |
| LineTo | MoveTo | OffsetClipRgn |
| OffsetViewportOrg | OffsetWindowOrg | PatBlt |
| Pie | Polygon | Polyline |
| PolyPolygon | RealizePalette | RestoreDC |
| RoundRect | SaveDC | ScaleViewportExt |
| ScaleWindowExt | SelectClipRgn | SelectObject |
| SelectPalette | SetBkColor | SetBkMode |
| SetMapMode | SetMapperFlags | SetPixel |
| SetPolyFillMode | SetROP2 | SetStretchBltMode |
| SetTextColor | SetTextJustification | SetViewportExt |
| SetViewportOrg | SetWindowExt | SetWindowORg |
| StretchBlt | TextOut |
除了CDC成員函數之外,還有一些在圖元文件DC中兼容的其他函數。這些包括CPalette :: AnimatePalette,CFont :: CreateFontIndirect,以及三個成員函數CBrush:CreateBrushIndirect,CreateDIBPatternBrush和CreatePatternBrush。
未記錄在圖元文件中的函數有:DrawFocusRect,DrawIcon,DrawText,ExcludeUpdateRgn,FillRect,FrameRect,GrayString,InvertRect,ScrollDC和TabbedTextOut。由於元文件DC實際上並未與設備關聯,因此不能將SetDIBits,GetDIBits和CreateDIBitmap與圖元文件DC一起使用。您可以使用SetDIBitsToDevice和StretchDIBits將元文件DC作為目標。CreateCompatibleDC,CreateCompatibleBitmap和CreateDiscardableBitmap 對於元文件DC沒有意義。
使用圖元文件DC時要考慮的另一點是,坐標系可能無法以像素為單位進行測量。出於這個原因,所有的繪圖代碼應該進行調整,以適應傳遞到矩形OnDraw的rcBounds參數。這可以防止在控件外部意外繪制,因為rcBounds表示控件窗口的大小。
為控件實現元文件呈現后,使用Test Container測試元文件。有關如何訪問測試容器的信息,請參閱使用測試容器測試屬性和事件。
使用Test Container測試控件的元文件
在“測試容器”的“ 編輯”菜單上,單擊“ 插入新控件”。
在“ 插入新控件”框中,選擇該控件,然后單擊“ 確定”。
該控件將出現在Test容器中。
在“ 控制”菜單上,單擊“ 繪制圖元文件”。
將出現一個單獨的窗口,其中顯示元文件。您可以更改此窗口的大小以查看縮放如何影響控件的圖元文件。您可以隨時關閉此窗口。
