次の方法で共有


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

コントロールは、コンテナーが提供するデバイス コンテキストに描画するように指示されると、通常、デバイス コンテキストに 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 オブジェクトと OnDraw オブジェクトが破棄されないようにするには、ローカル変数ではなくメンバー変数に格納します。 コントロールのクラス宣言で、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 コントロールの描画