次の方法で共有


コントロールの描画の最適化

コントロールは、コンテナー提供のデバイス コンテキストに自身を描画するように指示された場合、通常、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 から戻ったときにデバイス コンテキストに選択されたままにしておく予定である場合は、削除するべきではありません。

OnDraw の完了時に CPen および CBrush オブジェクトが破棄されないようにするには、これらをローカル変数ではなくメンバー変数に格納します。 コントロールのクラス宣言で、2 つの新しいメンバー変数の宣言を追加します。

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 が呼び出されるたびにペンとブラシが作成されることが回避されます。 速度が向上する代わりに、追加のインスタンス データを維持するコストが発生します。

ForeColor または BackColor プロパティが変更された場合は、ペンまたはブラシを再度作成する必要があります。 そうするには、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);
   }
}

関連項目

MFC ActiveX コントロール: 最適化
COleControl クラス
MFC ActiveX コントロール
MFC ActiveX コントロール ウィザード
MFC ActiveX コントロール: ActiveX コントロールの描画