TN040: MFC/OLE 埋め込み先サイズ変更とズーム
Note
次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。 結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。 最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。
このメモでは、インプレース編集に関連する問題と、サーバーで正しいズームとインプレース サイズ変更を実行する方法について説明します。 インプレース アクティブ化を使用すると、コンテナーとサーバーが互いに連携し、具体的には、OLE 仕様をほぼ同様に解釈することによって WYSIWYG の概念がさらに一歩前進します。
インプレース アクティブ化をサポートするコンテナーとサーバー間の密接な相互作用のために、管理する必要のあるエンド ユーザーからの期待が多くあります。
プレゼンテーション表示 (
COleServerItem::OnDraw
のオーバーライドで描画されるメタファイル) は、編集用に描画されたときとまったく同じに見える必要があります (編集ツールが表示されないことを除きます)。コンテナーがズームしたら、サーバー ウィンドウもズームする必要があります。
コンテナーとサーバーの両方で、同じメトリクスを使用して編集するオブジェクトを表示する必要があります。 これは、表示デバイスでレンダリングするときに、1 インチあたりの論理ピクセル数 (1 インチあたりの物理ピクセル数ではない) に基づくマッピング モードを使用することを意味します。
Note
インプレース アクティブ化は、埋め込み (未リンク) 項目にのみ適用されるため、ズームは、埋め込みオブジェクトにのみ適用されます。 COleServerDoc
と COleServerItem
の両方に、ズームに使用される API が表示されます。 この二分性の理由は、リンク項目と埋め込み項目の両方に対して有効な関数だけが COleServerItem
内に存在し (これにより共通の実装を持つことができる)、埋め込みオブジェクトに対してのみ有効な関数が COleServerDoc
クラスに配置される (サーバーの観点から見ると、埋め込まれたドキュメントになる) ことです。
サーバーはコンテナーのズーム係数を認識し、必要に応じて編集インターフェイスを変更する必要があるという点で、ほとんどの負担はサーバー実装者にかかります。 ところで、コンテナーで使用されるズーム率をサーバーがどのように決定するのでしょうか。
MFC によるズームのサポート
現在のズーム率は、COleServerDoc::GetZoomFactor
を呼び出すことによって決定できます。 ドキュメントがインプレース アクティブでない場合にこれを呼び出すと、必ず、100% のズーム率 (つまり、1 対 1 の比率) になります。 インプレース アクティブ中にこれを呼び出すと、100% 以外の値が返されます。
正しいズームの例については、MFC OLE サンプル HIERSVR を参照してください。 HIERSVR のズームは、テキストを表示するという事実と、一般的に、テキストは線形的にスケーリングされないという事実によって複雑になります (ヒント、印刷規則、デザイン幅、および高さのすべてが問題を複雑にします)。 それでも、HIERSVR は、ズームを正しく実装するための妥当な参照先であり、そのことは MFC チュートリアル SCRIBBLE (ステップ 7) で確認できます。
COleServerDoc::GetZoomFactor
は、コンテナーから、または COleServerItem
クラスと COleServerDoc
クラスの実装から入手可能なさまざまなメトリクスに基づいて、ズーム率を決定します。 つまり、現在のズーム率は、次の式によって決定されます。
Position Rectangle (PR) / Container Extent (CE)
POSITION RECTANGLE はコンテナーによって決定されます。 これは、COleClientItem::OnGetItemPosition
が呼び出されるインプレース アクティブ化の間にサーバーに返され、コンテナーがサーバーの COleServerDoc::OnSetItemRects
を呼び出した (COleClientItem::SetItemRects
の呼び出しを通して) ときに更新されます。
CONTAINER EXTENT の計算は少し複雑です。 コンテナーが COleServerItem::OnSetExtent
を呼び出していた (COleClientItem::SetExtent
の呼び出しを通して) 場合は、CONTAINER EXTENT が論理インチあたりのピクセル数に基づいてピクセルに変換された値になります。 コンテナーが SetExtent を呼び出していない場合 (通常のケース) は、CONTAINER EXTENT が COleServerItem::OnGetExtent
から返されたサイズになります。 そのため、コンテナーが SetExtent を呼び出していない場合、フレームワークは、コンテナーが呼び出すとしたら、100% の自然なエクステント (COleServerItem::GetExtent
から返される値) で呼び出すだろうと想定します。 言い方を変えれば、フレームワークは、コンテナーが 100% (それ以上でもそれ以下でもない) の項目を表示していると想定します。
COleServerItem::OnSetExtent
と COleServerItem::OnGetExtent
は名前が似ていますが、項目の同じ属性を操作するわけではないことに注意する必要があります。 OnSetExtent
は、コンテナーに表示可能なオブジェクトの量 (ズーム率に関係なく) をサーバーに通知するために呼び出され、OnGetExtent
は、オブジェクトの理想的なサイズを決定するためにコンテナーによって呼び出されます。
関係する API のそれぞれを調査することによって、さらに明確に把握することができます。
COleServerItem::OnGetExtent
この関数は、項目の HIMETRIC 単位の "自然なサイズ" を返すはずです。 "自然なサイズ" を決定する最善の方法は、印刷時に表示されるサイズとして定義することです。 ここで返されるサイズは、特定の項目の内容に対して一定です (特定の項目に対して一定であるメタファイルによく似ています)。 このサイズは、ズームを項目に適用しても、変化しません。 また、コンテナーが OnSetExtent
を呼び出すことによって項目の間隔を変更しても、通常は変化しません。 変化する例として、コンテナーから送信された最後のエクステントに基づいてテキストをラップする "余白" 機能を備えていない単純なテキスト エディターの場合が挙げられます。 サーバーで変更する場合は、システム レジストリで OLEMISC_RECOMPOSEONRESIZE ビットを設定しなければならない可能性があります (このオプションの詳細については、OLE SDK のドキュメントを参照してください)。
COleServerItem::OnSetExtent
この関数は、コンテナーがオブジェクトの "拡大/縮小" を表示したときに呼び出されます。 ほとんどのコンテナーは、この関数をまったく呼び出しません。 既定の実装は、コンテナーから受け取った最後の値を 'm_sizeExtent' に格納します。この値は、前述の CONTAINER EXTENT 値を計算するときに COleServerDoc::GetZoomFactor
で使用されます。
COleServerDoc::OnSetItemRects
この関数は、ドキュメントがインプレース アクティブのときにのみ呼び出されます。 コンテナーが項目の位置または項目に適用されたクリッピングを更新したときに呼び出されます。 前述したように、POSITION RECTANGLE は、ズーム率を計算するための分子を提供します。 サーバーは、COleServerDoc::RequestPositionChange
を呼び出すことによって、項目の位置を変更するように要求できます。 コンテナーは、OnSetItemRects
を呼び出す (COleServerItem::SetItemRects
の呼び出しを通して) ことによって、この要求に応答する場合と応答しない場合があります。
COleServerDoc::OnDraw
COleServerItem::OnDraw
のオーバーライドによって作成されたメタファイルから、現在のズーム率に関係なく、まったく同じメタファイルが生成されることに気付く必要があります。 コンテナーは、必要に応じてメタファイルをスケーリングします。 これは、ビューの OnDraw
とサーバー項目の OnDraw
の重要な違いです。 ビューはズームを処理します。項目はズーム可能なメタファイルを作成するだけで、適切なズームの実行はコンテナーに委ねます。
サーバーが正しく動作することを保証する最善の方法は、ドキュメントがインプレース アクティブの場合に COleServerDoc::GetZoomFactor
の実装を使用することです。
MFC によるインプレース サイズ変更のサポート
MFC は、OLE 2 仕様書に記載されているように、インプレース サイズ変更インターフェイスを完全に実装します。 ユーザー インターフェイスは、COleResizeBar
クラス、カスタム メッセージ WM_SIZECHILD、および COleIPFrameWnd
でのこのメッセージの特殊な処理によってサポートされます。
このメッセージの処理は、フレームワークによって提供される処理とは異なる方法で実装できます。 前述したように、フレームワークはインプレース サイズ変更の結果をコンテナーに委ねます。サーバーはズーム率の変化に対応します。 コンテナーがその COleClientItem::OnChangeItemPosition
(COleServerDoc::RequestPositionChange
の呼び出しの結果として呼び出される) の処理中に CONTAINER EXTENT と POSITION RECTANGLE の両方を設定することによって対応する場合は、インプレース サイズ変更の結果として、編集ウィンドウに項目の "拡大/縮小" が表示されます。 コンテナーが COleClientItem::OnChangeItemPosition
の処理中に POSITION RECTANGLE のみを設定することによって対応する場合は、ズーム率が変化し、項目が "拡大または縮小" して表示されます。
サーバーは、このネゴシエーション中の動作を (ある程度) 制御できます。 たとえば、スプレッドシートでは、ユーザーがインプレースで項目を編集中にウィンドウのサイズを変更したときに、表示するセルの数を増やしたり減らしたりできます。 ワード プロセッサでは、ウィンドウと同じになるように "ページ余白" を変更し、テキストを新しい余白に折り返すことができます。 サーバーは、サイズ変更が完了したときに、自然なエクステント (COleServerItem::OnGetExtent
から返されるサイズ) を変更することによって、この処理を実装します。 これにより、POSITION RECTANGLE と CONTAINER EXTENT の両方が同じ量だけ変化し、結果として、同じズーム率が得られますが、表示領域が増えたり減ったりします。 加えて、OnDraw
によって生成されたメタファイルで、ドキュメントの拡大/縮小を確認できます。 この場合は、ユーザーが表示領域ではなく項目のサイズを変更したときに、ドキュメント自体が変化します。
COleIPFrameWnd
クラス内の WM_SIZECHILD メッセージをオーバーライドすることによって、COleResizeBar
から提供されるユーザー インターフェイスを活用しながら、カスタム サイズ変更を実装できます。 WM_SIZECHILD の詳細については、テクニカル ノート 24 を参照してください。