MFC ActiveX コントロール : ActiveX コントロールの描画
このアーティクルでは、ActiveX コントロールの描画プロセスについて説明します。また、描画コードを変更してプロセスを最適化する方法についても説明します。 (「 コントロールが 以前に選択した GDI オブジェクトを個別に復元しないことで描画を最適化する方法に関する手法に対するコントロール描画の最適化。すべてのコントロールが描画されると、コンテナーは元のオブジェクトを自動的に復元できます)。
重要
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) ではなく、渡されるデバイス コンテキストは、コントロールを含むコントロール コンテナのものです。
Note
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);
}
Note
コントロールを描画するときに、pdc パラメーターとして OnDraw
関数に渡されるデバイス コンテキストの状態について仮定してはいけません。 デバイス コンテキストは、コンテナー アプリケーションから提供されることもあり、必ずしも既定の状態に初期化されるとは限りません。 特に、描画コードが依存しているペン、ブラシ、色、フォント、およびその他のリソースを明示的に選択します。
ペイントコードの最適化
コントロールが正常に描画された後、次の手順は OnDraw
関数を最適化することです。
ActiveX コントロール描画の既定の実装では、コントロール領域全体が描画されます。 これは単純なコントロールには十分ですが、コントロール全体ではなく、更新が必要な部分だけが再描画された場合は、多くの場合、コントロールの再描画が高速になります。
OnDraw
関数は、再描画が必要なコントロールの四角形の領域である rcInvalid を渡すことによって、簡単な最適化方法を提供します。 描画プロセスを高速化するために、通常はコントロール領域全体より小さいこの領域を使用します。
メタファイルを使用したコントロールの描画
ほとんどの場合、OnDraw
関数の pdc パラメーターは、画面デバイス コンテキスト (DC) を指しています。 ただし、コントロールのイメージを印刷するとき、または印刷プレビュー セッション中に、レンダリングのために受信した DC は、"メタファイル DC" と呼ばれる特殊な型になります。 送信された要求をすぐに処理する画面 DC とは異なり、メタファイル DC は後で再生する要求を格納します。 一部のコンテナー アプリケーションでは、デザイン モードでメタファイル DC を使用してコントロール イメージを表示することもできます。
メタファイル描画要求は、コンテナーによって、2 つのインターフェイス関数 IViewObject::Draw
(この関数はメタファイル以外の描画にも呼び出すことができます) と IDataObject::GetData
を使用して作成できます。 メタファイル DC をパラメーターの 1 つとして渡すと、MFC フレームワークによって、COleControl:: OnDrawMetafile が呼び出されます。 これは仮想メンバー関数であるため、特別な処理を実行するには、コントロール クラスのこの関数をオーバーライドします。 既定の動作では COleControl::OnDraw
を呼び出します。
コントロールを画面とメタファイルの両方のデバイス コンテキストで描画可能にするには、画面とメタファイル DC の両方でサポートされているメンバー関数だけを使用する必要があります。 座標系はピクセル単位では測定されない場合があることに注意してください。
OnDrawMetafile
の既定の実装はコントロールの OnDraw
関数を呼び出すので、OnDrawMetafile
をオーバーライドしない限り、メタファイルとスクリーン デバイスの両方のコンテキストに適したメンバー関数だけを使用します。 メタファイルと画面デバイス コンテキストの両方で使用できるメンバー関数の CDC
サブセットを次に示します。 これらの関数の詳細は、MFC リファレンスのクラス CDC を参照してください。
Arc | 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 パラメータの四角形に収まるように調整する必要があります。 rcBounds はコントロールのウィンドウ サイズを表すため、誤ってコントロールの外側を描いてしまうことを防ぎます。
コントロールのメタファイル レンダリングを実装した後、テスト コンテナーを使用してメタファイルをテストします。 Test Container にアクセスする方法について詳しくは、「 テスト コンテナーでのプロパティとイベントのテスト 」をご覧ください。
テスト コンテナーを使用してコントロールのメタファイルをテストするには
テスト コンテナーの [編集] メニューで、[Insert New Control (新しいコントロールを挿入)] をクリックします。
[Insert New Control (新しいコントロールを挿入)] ボックスで、コントロールを選択し、[OK]をクリックします。
コントロールがテスト コンテナーに表示されます。
[コントロール] メニューの [Draw Metafile (メタファイルの描画)] をクリックします。
別のウィンドウが表示され、メタファイルが表示されます。 このウィンドウのサイズを変更して、スケーリングがコントロールのメタファイルに与える影響を確認できます。 このウィンドウはいつでも閉じることができます。