この記事では、ActiveX コントロールの描画プロセスと、プロセスを最適化するためにペイント コードを変更する方法について説明します。 (以前に選択した GDI オブジェクト をコントロールが 個別に復元しないようにして描画を最適化する方法については、「コントロール描画の最適化」を参照してください。すべてのコントロールが描画されると、コンテナーは元のオブジェクトを自動的に復元できます)。
Von Bedeutung
ActiveX は、新しい開発には使用すべきではないレガシ テクノロジです。 ActiveX に代わる最新のテクノロジの詳細については、「 ActiveX コントロール」を参照してください。
この記事の例は、MFC ActiveX コントロール ウィザードによって既定の設定で作成されたコントロールの例です。 MFC ActiveX コントロール ウィザードを使用してスケルトン コントロール アプリケーションを作成する方法の詳細については、 MFC ActiveX コントロール ウィザードの記事を参照してください。
次のトピックについて説明します。
ActiveX コントロールの描画プロセス
ActiveX コントロールは、最初に表示または再描画されるときに、MFC を使用して開発された他のアプリケーションと同様の描画プロセスに従います。1 つの重要な違いは、ActiveX コントロールがアクティブまたは非アクティブな状態である可能性があります。
アクティブ なコントロールは、子ウィンドウによって ActiveX コントロール コンテナーで表されます。 他のウィンドウと同様に、WM_PAINTメッセージを受信したときにそれ自体を描画する役割を担います。 コントロールの基底クラス COleControl は、 OnPaint
関数でこのメッセージを処理します。 この既定の実装では、コントロールの OnDraw
関数が呼び出されます。
非アクティブなコントロールの描画方法が異なります。 コントロールが非アクティブな場合、そのウィンドウは非表示か存在しないため、描画メッセージを受信できません。 代わりに、コントロール コンテナーはコントロールの OnDraw
関数を直接呼び出します。 これは、 OnPaint
メンバー関数が呼び出されないという点で、アクティブなコントロールの描画プロセスとは異なります。
前の段落で説明したように、ActiveX コントロールの更新方法は、コントロールの状態によって異なります。 ただし、どちらの場合もフレームワークによって OnDraw
メンバー関数が呼び出されるため、このメンバー関数に描画コードの大部分を追加します。
OnDraw
メンバー関数は、コントロールの描画を処理します。 コントロールが非アクティブな場合、コントロール コンテナーは OnDraw
を呼び出し、コントロール コンテナーのデバイス コンテキストと、コントロールが占有する四角形領域の座標を渡します。
フレームワークによって OnDraw
メンバー関数に渡される四角形には、コントロールによって占有される領域が含まれています。 コントロールがアクティブな場合、左上隅は (0, 0) で、渡されるデバイス コンテキストはコントロールを含む子ウィンドウ用です。 コントロールが非アクティブな場合、左上の座標は必ずしも (0, 0) ではなく、渡されるデバイス コンテキストはコントロールを含むコントロール コンテナー用です。
注
OnDraw
に対する変更は、四角形の左上の点が (0, 0) に等しいことに依存せず、OnDraw
に渡された四角形の内側にのみ描画することが重要です。 四角形の領域を超えて描画すると、予期しない結果が発生する可能性があります。
コントロール実装ファイル内の MFC ActiveX コントロール ウィザードによって提供される既定の実装 (.CPP)、次に示すように、白いブラシで四角形を塗りつぶし、楕円を現在の背景色で塗りつぶします。
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 を渡すことによって、最適化の簡単な方法を提供します。 この領域 (通常はコントロール領域全体よりも小さい) を使用して、描画プロセスを高速化します。
メタファイルを使用したコントロールの描画
ほとんどの場合、関数への OnDraw
パラメーターは、画面デバイス コンテキスト (DC) を指します。 ただし、コントロールのイメージを印刷するとき、または印刷プレビュー セッション中に、レンダリング用に受信した DC は、"メタファイル DC" と呼ばれる特殊な種類です。 送信された要求をすぐに処理する画面 DC とは異なり、メタファイル DC は後で再生される要求を格納します。 一部のコンテナー アプリケーションでは、デザイン モードのときにメタファイル DC を使用してコントロール イメージをレンダリングすることもできます。
メタファイル描画要求は、 IViewObject::Draw
(この関数はメタファイル以外の描画にも呼び出すことができます) と IDataObject::GetData
の 2 つのインターフェイス関数を使用してコンテナーによって行うことができます。 メタファイル DC がパラメーターの 1 つとして渡されると、MFC フレームワークは COleControl::OnDrawMetafile を呼び出します。 これは仮想メンバー関数であるため、特別な処理を行うには、コントロール クラスでこの関数をオーバーライドします。 既定の動作では、 COleControl::OnDraw
が呼び出されます。
画面とメタファイルの両方のデバイス コンテキストでコントロールを描画できるようにするには、画面とメタファイル DC の両方でサポートされているメンバー関数のみを使用する必要があります。 座標系はピクセル単位で測定されない場合があることに注意してください。
OnDrawMetafile
の既定の実装ではコントロールのOnDraw
関数が呼び出されるため、OnDrawMetafile
をオーバーライドしない限り、メタファイルと画面のデバイス コンテキストの両方に適したメンバー関数のみを使用します。 メタファイルと画面デバイス コンテキストの両方で使用できる CDC
メンバー関数のサブセットを次に示します。 これらの関数の詳細については、MFC リファレンスの クラス CDC を 参照してください。
アーク | BibBlt | コード |
---|---|---|
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
の 3 つのメンバー関数 ( CreateBrushIndirect、 CreateDIBPatternBrush、 CreatePatternBrush) が含まれます。
メタファイルに記録されない関数は、DrawFocusRect、DrawIcon、DrawText、ExcludeUpdateRgn、FillRect、FrameRect、GrayString、InvertRect、ScrollDC、TabbedTextOut です。 メタファイル DC は実際にはデバイスに関連付けられていないため、メタファイル DC で SetDIBits、GetDIBits、CreateDIBitmap を使用することはできません。 SetDIBitsToDevice と StretchDIBits は、メタファイル DC を宛先として使用できます。 CreateCompatibleDC、 CreateCompatibleBitmap、 CreateDiscardableBitmap は、メタファイル DC では意味がありません。
メタファイル DC を使用する際に考慮すべきもう 1 つのポイントは、座標系をピクセル単位で測定できないことです。 このため、OnDraw
パラメーターでに渡される四角形に収まるように、すべての描画コードを調整する必要があります。
rcBounds はコントロールのウィンドウのサイズを表しているため、これにより、コントロールの外部で誤って描画されるのを防ぐことができます。
コントロールのメタファイル レンダリングを実装したら、テスト コンテナーを使用してメタファイルをテストします。 Test Container にアクセスする方法について詳しくは、「 テスト コンテナーでのプロパティとイベントのテスト 」をご覧ください。
テスト コンテナーを使用してコントロールのメタファイルをテストするには
テスト コンテナーの [編集] メニューで、[ 新しいコントロールの挿入] をクリックします。
[ 新しいコントロールの挿入 ] ボックスで、コントロールを選択し、[OK] をクリック します。
コントロールがテスト コンテナーに表示されます。
[ コントロール ] メニューの [ メタファイルの描画] をクリックします。
メタファイルが表示される別のウィンドウが表示されます。 このウィンドウのサイズを変更して、スケーリングがコントロールのメタファイルに与える影響を確認できます。 このウィンドウはいつでも閉じることができます。