次の方法で共有


マルチページ ドキュメント

この記事では、Windows 印刷プロトコルについて説明し、複数のページを含むドキュメントを印刷する方法について説明します。 この記事では、次のトピックについて説明します。

印刷プロトコル

複数ページのドキュメントを印刷するために、フレームワークとビューは次のように対話します。 最初に、フレームワークによって [印刷] ダイアログ ボックスが表示され、プリンターのデバイス コンテキストが作成されて、CDC オブジェクトの StartDoc メンバー関数が呼び出されます。 次に、ドキュメントのページごとに、フレームワークによって CDC オブジェクトの StartPage メンバー関数が呼び出され、ページを印刷するようにビュー オブジェクトが指示され、EndPage メンバー関数が呼び出されます。 特定のページを開始する前にプリンター モードを変更する必要がある場合、ビューによって ResetDC が呼び出されます。これにより、新しいプリンター モード情報を含む DEVMODE 構造体が更新されます。 ドキュメント全体が印刷されると、フレームワークによって EndDoc メンバー関数が呼び出されます。

ビュー クラス関数のオーバーライド

CView クラスには、印刷時にフレームワークによって呼び出されるいくつかのメンバー関数が定義されています。 ビュー クラス内でこれらの関数をオーバーライドすることによって、フレームワークの印刷ロジックとビュー クラスの印刷ロジック間の接続を提供します。 これらのメンバー関数の一覧を次の表に示します。

CView のオーバーライド可能な印刷用関数

名前 オーバーライドの理由
OnPreparePrinting [印刷] ダイアログ ボックスに値 (特にドキュメントの長さ) を挿入するため
OnBeginPrinting フォントまたはその他の GDI リソースを割り当てるため
OnPrepareDC 特定のページのデバイス コンテキストの属性を調整するため、または印刷時の改ページ位置の自動修正を行うため
OnPrint 特定のページを印刷するため
OnEndPrinting GDI リソースの割り当てを解除するため

印刷関連の処理は他の関数でも実行できますが、これらの関数は印刷プロセスを駆動するものです。

次の図は、印刷プロセスに関連する手順を示しています。また、CView の各印刷メンバー関数がどこで呼び出されるかを示しています。 この記事の残りの部分では、これらの手順の大部分について詳しく説明します。 印刷プロセスの追加の部分については、記事「GDI リソースの割り当て」で説明しています。

Printing loop process.
印刷ループ

改ページ位置の自動修正

フレームワークにより、印刷ジョブに関する情報の多くが CPrintInfo 構造体に格納されます。 CPrintInfo 内の値のいくつかは、改ページ位置の自動修正に関連しています。これらの値には、次の表に示すようにアクセスできます。

CPrintInfo に格納されているページ番号情報

メンバー変数または

関数名
参照ページ番号
GetMinPage/SetMinPage ドキュメントの最初のページ
GetMaxPage/SetMaxPage ドキュメントの最後のページ
GetFromPage 印刷される最初のページ
GetToPage 印刷される最後のページ
m_nCurPage 現在印刷中のページ

ページ番号は 1 から始まります。つまり、最初のページの番号は 0 ではなく 1 になります。 これらや CPrintInfo の他のメンバーの詳細については、"MFC のリファレンス" を参照してください。

印刷プロセスの開始時に、フレームワークによって、ビューの OnPreparePrinting メンバー関数が呼び出され、CPrintInfo 構造体へのポインターが渡されます。 アプリケーション ウィザードでは、CView の別のメンバー関数である DoPreparePrinting を呼び出す OnPreparePrinting の実装が提供されます。 DoPreparePrinting は、[印刷] ダイアログ ボックスを表示し、プリンター デバイス コンテキストを作成する関数です。

この時点では、アプリケーションはドキュメントのページ数を認識していません。 ドキュメントの最初と最後のページの番号には、既定値の 1 と 0xFFFF が使用されます。 ドキュメントに含まれているページの数がわかっている場合は、CPrintInfo 構造体を DoPreparePrinting に送信する前に、OnPreparePrinting をオーバーライドし、それに対して [SetMaxPage]--brokenlink--(reference/cprintinfo-class.md#setmaxpage) を呼び出します。 これにより、ドキュメントの長さを指定できます。

次に、DoPreparePrinting により、[印刷] ダイアログ ボックスが表示されます。 制御が戻ると、ユーザーが指定した値が CPrintInfo 構造体に含まれています。 ユーザーは、選択した範囲のページだけを印刷する場合、[印刷] ダイアログ ボックス内で開始と終了ページ番号を指定できます。 フレームワークは、CPrintInfoGetFromPageGetToPage 関数を使用して、これらの値を取得します。 ユーザーがページ範囲を指定しない場合、フレームワークにより、GetMinPageGetMaxPage が呼び出され、返された値を使用してドキュメント全体が印刷されます。

印刷するドキュメントのページごとに、フレームワークにより、ビュー クラス内にある 2 つのメンバー関数 OnPrepareDCOnPrint が呼び出され、各関数に 2 つのパラメーター (CDC オブジェクトへのポインターと CPrintInfo 構造体へのポインター) が渡されます。 フレームワークにより、OnPrepareDCOnPrint が呼び出されるたびに、CPrintInfo 構造体の m_nCurPage メンバーに異なる値が渡されます。 このようにして、フレームワークにより、ビューは印刷するページを指示されます。

OnPrepareDC メンバー関数は、画面の表示にも使用されます。 これにより、描画が実行される前に、デバイス コンテキストの調整が行われます。 OnPrepareDC は印刷でも同様の役割を果たしますが、2 つの違いがあります。1 つ目は、CDC オブジェクトは画面デバイス コンテキストではなくプリンター デバイス コンテキストを表します。2 つ目は、CPrintInfo オブジェクトが 2 番目のパラメーターとして渡されます。 (このパラメーターは画面表示に対して呼び出された場合OnPrepareDCは NULL。印刷するページに基づいてデバイス コンテキストを調整するには、オーバーライドOnPrepareDCします。 たとえば、ビューポートの原点とクリッピング領域を移動して、確実にドキュメントの適切な部分が印刷されるようにすることができます。

OnPrint メンバー関数は、ページの実際の印刷を実行します。 記事「既定の印刷プロセス」では、フレームワークにより、プリンター デバイス コンテキストを指定した OnDraw を呼び出して、印刷を実行する方法を示しています。 より正確には、フレームワークにより、CPrintInfo 構造とデバイス コンテキストを指定した OnPrint が呼び出され、OnPrint により、デバイス コンテキストが OnDraw に渡されます。 レンダリングを実行するが、印刷中にのみ実行し、画面表示の場合はしないようにするには、OnPrint をオーバーライドします。 たとえば、ヘッダーまたはフッターを印刷する場合です (詳細については、記事「ヘッダーとフッター」を参照してください)。 その場合に、画面表示と印刷の両方に共通のレンダリングを実行するには、OnPrint のオーバーライドから OnDraw を呼び出します。

OnDraw で画面表示と印刷の両方に対してレンダリングが実行されるという事実は、実際のアプリケーションが WYSIWYG "What You See Is What You Get" であることを意味します。ただし、WYSIWYG アプリケーションを記述していないと想定しています。 たとえば、印刷では太字のフォントを使用するが、画面上では太字のテキストを示すコントロール コードを表示するテキスト エディターを考えてみます。 このような状況では、画面表示には厳密に OnDraw を使用します。 OnPrint をオーバーライドする場合は、OnDraw の呼び出しを別の描画関数の呼び出しに置き換えます。 その関数では、画面に表示されていない属性を使用して、紙には印刷されるようにドキュメントを描画します。

プリンター ページとドキュメント ページ

ページ番号を参照するときは、プリンターのページの概念とドキュメントのページの概念を区別することが必要な場合があります。 プリンターの観点から見ると、1 ページは 1 枚の紙です。 しかし、1 枚の紙は必ずしもドキュメントの 1 ページと同じではありません。 たとえば、紙を折りたたむニュースレターを印刷する場合、1枚の紙にドキュメントの最初と最後のページの両方が横に並んで含まれていることがあります。 同様に、スプレッドシートを印刷する場合、ドキュメントはまったくページで構成されていません。 代わりに、1 枚の紙に 1 から 20 までの行、6 から 10 までの列が含まれていたりします。

CPrintInfo 構造体内のすべてのページ番号は、プリンター ページを参照します。 フレームワークにより、1 枚の紙がプリンターを通過するごとに 1 回 OnPrepareDCOnPrint が呼び出されます。 OnPreparePrinting 関数をオーバーライドして、ドキュメントの長さを指定する場合は、プリンター ページを使用する必要があります。 1 対 1 で対応している場合 (つまり、1 プリンター ページが 1 ドキュメント ページと等しい場合)、これは簡単です。 一方、ドキュメント ページとプリンター ページが直接対応していない場合は、それらの間で変換を行う必要があります。 たとえば、スプレッドシートを印刷する場合を考えます。 OnPreparePrinting をオーバーライドする場合は、スプレッドシート全体を印刷するために必要な枚数を計算し、CPrintInfoSetMaxPage メンバー関数を呼び出すときにその値を使用する必要があります。 同様に、OnPrepareDC をオーバーライドする場合は、m_nCurPage をその特定の紙に印刷される行と列の範囲に変換し、それに応じてビューポートの原点を調整する必要があります。

印刷時の改ページ位置の自動修正

場合によっては、ビュー クラスではドキュメントが実際に印刷されるまでその長さが事前にわからないことがあります。 たとえば、実際のアプリケーションが WYSIWYG でない場合、画面上のドキュメントの長さは印刷時のその長さと対応しません。

これにより、ビュー クラスの OnPreparePrinting をオーバーライドした場合に問題が発生します。ドキュメントの長さがわからないので、CPrintInfo 構造体の SetMaxPage 関数に値を渡すことができません。 ユーザーが [印刷] ダイアログ ボックスを使用して停止するページ番号を指定しなかった場合、印刷ループをいつ停止するかがフレームワークにはわかりません。 印刷ループをいつ停止するかを判断する唯一の方法は、ドキュメントを印刷して、それがいつ終了するかを確認することです。 ビュー クラスでは、印刷中にドキュメントの末尾を確認し、末尾に達したときにフレームワークに通知する必要があります。

フレームワークは、いつ停止するかを伝えるビュー クラスの OnPrepareDC 関数に依存しています。 OnPrepareDC の各呼び出しの後、フレームワークにより、CPrintInfo 構造体の m_bContinuePrinting という名前のメンバーが確認されます。 その既定値は TRUE です。それが維持される限り、フレームワークは印刷ループを継続します。 FALSE に設定された場合、フレームワークにより停止されます。 印刷時の改ページ位置の自動修正を実行するには、OnPrepareDC をオーバーライドしてドキュメントの末尾に到達したかどうかを確認し、そうなったときに m_bContinuePrintingFALSE に設定します。

OnPrepareDC の既定の実装では、現在のページが 1 より大きくなると、m_bContinuePrintingFALSE に設定されます。 これは、ドキュメントの長さが指定されていない場合、フレームワークがドキュメントの長さを 1 ページと見なすという意味です。 その 1 つの結果として、OnPrepareDC の基底クラス バージョンを呼び出す場合は注意が必要です。 基底クラス バージョンを呼び出した後に、m_bContinuePrintingTRUE になると想定しないでください。

さらに詳しい情報

関連項目

印刷
CView クラス
CDC クラス