最佳化控制項繪圖
當控制項表示會引入一由容器提供的裝置內容時,它通常會選取 GDI 物件 (例如畫筆、筆刷和字型) 到裝置內容中,會繪製作業,還原先前 GDI 的物件。 如果容器有要引入的多個控制項相同的裝置內容,因此它需要的每個控制項選取 GDI 物件則可以儲存如果控制項不會個別還原先前選取的物件。 在所有控制項繪製之後,容器可以自動還原原始物件。
若要偵測容器是否支援這個方法之後,控制項會呼叫 COleControl::IsOptimizedDraw 成員函式。 如果這個函式會傳回 TRUE,控制項可以略過正常步驟還原先前選取的物件。
假設有以下的控制項 ( OnDraw ) 未最佳化的函式:
void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
CPen pen(PS_SOLID, 0, TranslateColor(GetForeColor()));
CBrush brush(TranslateColor(GetBackColor()));
CPen* pPenSave = pdc->SelectObject(&pen);
CBrush* pBrushSave = pdc->SelectObject(&brush);
pdc->Rectangle(rcBounds);
pdc->SelectObject(pPenSave);
pdc->SelectObject(pBrushSave);
}
畫筆和筆刷在本例中為區域變數,表示其解構函式會呼叫,以便在超出範圍時 (在 OnDraw 函式結束時)。 解構函式會嘗試刪除對應的 GDI 物件。 它們,如果您打算讓它們被選取到裝置內容中傳回的值,則為 OnDraw,但不應該刪除。
若要防止 CPen 和 CBrush 物件被終結,當 OnDraw 完成時,請將其儲存在成員變數而非區域變數。 在控制項的類別宣告,請加入兩個新的成員變數的宣告:
class CMyAxOptCtrl : public COleControl
{
...
CPen m_pen;
CBrush m_brush;
};
然後就可以呼叫 OnDraw方法,如下所示:
void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
CPen pen(PS_SOLID, 0, TranslateColor(GetForeColor()));
CBrush brush(TranslateColor(GetBackColor()));
CPen* pPenSave = pdc->SelectObject(&pen);
CBrush* pBrushSave = pdc->SelectObject(&brush);
pdc->Rectangle(rcBounds);
pdc->SelectObject(pPenSave);
pdc->SelectObject(pBrushSave);
}
OnDraw ,在呼叫時,這個方法可以避免這個畫筆和筆刷的建立。 速度來改善以維護不同的執行個體資料為代價。
如果控制項或背景色彩屬性變更時,這個筆刷或需要重新建立。 若要這麼做,請覆寫 OnForeColorChanged 和 OnBackColorChanged 成員函式:
void CMyAxOptCtrl::OnForeColorChanged()
{
m_pen.DeleteObject();
}
void CMyAxOptCtrl::OnBackColorChanged()
{
m_brush.DeleteObject();
}
最後,排除不必要的呼叫 SelectObject ,請修改 OnDraw 如下:
void CMyAxOptCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
if (m_pen.m_hObject == NULL)
m_pen.CreatePen(PS_SOLID, 0, TranslateColor(GetForeColor()));
if (m_brush.m_hObject == NULL)
m_brush.CreateSolidBrush(TranslateColor(GetBackColor()));
CPen* pPenSave = pdc->SelectObject(&m_pen);
CBrush* pBrushSave = pdc->SelectObject(&m_brush);
pdc->Rectangle(rcBounds);
if (! IsOptimizedDraw())
{
pdc->SelectObject(pPenSave);
pdc->SelectObject(pBrushSave);
}
}