テクニカル ノート 30: 印刷と印刷プレビューのカスタマイズ

Note

次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。 結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。 最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。

このメモでは、印刷と印刷のプレビューをカスタマイズするプロセスについて説明し、CView で使用されるコールバック ルーチンの目的と、CPreviewView のコールバック ルーチンおyびメンバー関数について説明します。

問題

MFC は、ほとんどの印刷および印刷プレビューのニーズに完全なソリューションを提供します。 ほとんどの場合、ビューを印刷してプレビューするために追加しなければならないコードは多くありません。 ただし、開発者の作業に多大な労力を要する印刷を最適化する方法があります。一部のアプリケーションでは、印刷プレビュー モードに特定のユーザー インターフェイス要素を追加する必要があります。

効率的な印刷

MFC アプリケーションが標準メソッドを使用して出力する場合、Windows では、すべてのグラフィカル デバイス インターフェイス (GDI) 出力呼び出しをメモリ内メタファイルに送る必要があります。 EndPage が呼び出された場合Windows ではプリンターが 1 ページを印刷するために必要な物理バンドごとにメタファイルを 1 回再生します。 このレンダリング中、GDI は頻繁に中止プロシージャに対してクエリを実行し、続行する必要があるかどうかを判断します。 通常、中止プロシージャを使用すると、ユーザーが印刷ダイアログを使用して印刷ジョブを中止できるメッセージを処理できます。

残念ながら、これにより印刷プロセスが遅くなる可能性があります。 標準的な手法を使用する場合よりも、アプリケーションでの印刷の方が高速でなければならない場合は、手動のバンドを実装する必要があります。

手動でバンドを設定するには、ページごとに OnPrint が複数回 (バンドごとに 1 回) 呼び出される印刷ループを実装する必要があります。 印刷ループは、viewprnt.cpp の OnFilePrint 関数に実装されます。 CView 派生クラスでは、この関数をオーバーロードして、印刷コマンドを処理するためのメッセージ マップ エントリが印刷関数を呼び出すようにします。 OnFilePrint ルーチンをコピーし、印刷ループを変更してバンドを実装します。 印刷するページのセクションに基づいて描画を最適化できるよう、印刷関数にバンドの四角形を渡す必要がある場合があります。

次に、バンドの描画中に QueryAbort を頻繁 に呼び出す必要があります。 それ以外の場合、中止プロシージャは呼び出されません。ユーザーは印刷ジョブを取り消す必要があります。

印刷プレビューでは、本質的に、表示をプリンターのエミュレーションに変換します。 既定では、メイン ウィンドウのクライアント領域は、ウィンドウ内に 1 ページまたは 2 ページを完全に表示するために使用されます。 ユーザーは、ページの領域を拡大して詳細を表示できます。 追加のサポートにより、ユーザーはプレビュー モードでドキュメントを編集できる場合があります。

印刷プレビューのカスタマイズ

このメモでは、印刷プレビューの変更の 1 つの側面のみを扱います: プレビュー モードへの UI の追加 その他の変更も可能ですが、ここの説明の範囲には含まれません。

プレビュー モードに UI を追加するには

  1. CPreviewView からビュー クラスを派生させます。

  2. 必要な UI 側面のコマンド ハンドラーを追加します。

  3. 表示に視覚的な側面を追加する場合は、CPreviewView::OnDraw を呼び出した後に OnDraw をオーバーライドし、描画を実行します。

OnFilePrintPreview

これは、印刷プレビューのコマンド ハンドラーです。 既定の実装は次の通りです:

void CView::OnFilePrintPreview()
{
    // In derived classes, implement special window handling here
    // Be sure to Unhook Frame Window close if hooked.

    // must not create this on the frame. Must outlive this function
    CPrintPreviewState* pState = new CPrintPreviewState;

    if (!DoPrintPreview(AFX_IDD_PREVIEW_TOOLBAR, this,
        RUNTIME_CLASS(CPreviewView), pState))
    {
        // In derived classes, reverse special window handling
        // here for Preview failure case

        TRACE0("Error: DoPrintPreview failed");
        AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
        delete pState;  // preview failed to initialize, delete State now
    }
}

DoPrintPreview は、アプリケーションのメインウィンドウを非表示にします。 ステータス バーなどのコントロール バーは、pState->dwStates メンバーで指定することで保持できます (これはビット マスクであり、個々のコントロール バーのビットは AFX_CONTROLBAR_MASK( AFX_IDW_MYBAR) によって定義されます)。 ウィンドウ pState->nIDMainPane は、自動的に非表示にされ、再び表示されるウィンドウです。 DoPrintPreview では、標準プレビュー UI のボタン バーが作成されます。 他のウィンドウを非表示または表示するなどの特別なウィンドウ処理が必要な場合は、DoPrintPreview が呼び出される前に行う必要があります。

既定では、印刷プレビューが完了すると、コントロール バーが元の状態に戻り、メイン ペインが表示されます。 特別な処理が必要な場合は、 EndPrintPreviewのオーバーライドで行う必要があります。 DoPrintPreview に失敗した場合は、特別な処理も提供します。

DoPrintPreview は、次の方法で呼び出されます:

  • プレビュー ツール バーのダイアログ テンプレートのリソース ID。

  • 印刷プレビューの印刷を実行するビューへのポインター。

  • Preview View クラスの実行時クラス。 これは、DoPrintPreview で動的に作成されます。

  • CPrintPreviewState ポインター。 CPrintPreviewState 構造体 (または、アプリケーションでさらに状態を維持する必要がある場合は派生構造体) をフレームに作成しないでください。 DoPrintPreview はモードレスであり、EndPrintPreview が呼び出されるまでこの構造体は存続する必要があります。

    Note

    印刷のサポートに別のビューまたはビュー クラスが必要な場合は、そのオブジェクトへのポインターを 2 番目のパラメーターとして渡す必要があります。

EndPrintPreview

これは、印刷プレビュー モードを終了するために呼び出されます。 多くの場合、印刷プレビューで最後に表示されたドキュメントのページに移動することが望ましい場合があります。 EndPrintPreview は、アプリケーションでこれを行う機会です。 pInfo->m_nCurPage メンバーは、最後に表示されたページ (2 つのページが表示されている場合は左端) であり、ポインターは、ユーザーが関心を持っていたページの場所に関するヒントです。 アプリケーションのビューの構造はフレームワークでは不明なので、選択したポイントに移動するコードを指定する必要があります。

CView::EndPrintPreview を呼び出す前に、ほとんどのアクションを実行する必要があります。 この呼び出しは DoPrintPreview の効果を反転し、pView、pDC、pInfo を削除します。

// Any further cleanup should be done here.
CView::EndPrintPreview(pDC, pInfo, point, pView);

CWinApp::OnFilePrintSetup

これは、[印刷セットアップ] メニュー項目にマップする必要があります。 ほとんどの場合、実装をオーバーライドする必要はありません。

ページの命名

ページ番号と順序という問題もあります。 単純なワード プロセッサ型のアプリケーションの場合、この問題は難しくありません。 ほとんどの印刷プレビュー システムでは、印刷された各ページがドキュメント内の 1 ページに対応すると想定されています。

一般化されたソリューションを提供するには、いくつかの点を考慮する必要があります。 CAD システムを考えてみてください。 ユーザーは、複数の E サイズ シートをカバーする描画を持っています。 E サイズ (または小さいスケールの) プロッターでは、ページ番号は単純な場合と同じになります。 しかし、レーザープリンターでは、1 シートあたり A サイズ 16 ページを印刷すると、印刷プレビューでは "ページ" と見なされます。

最初の段落に説明されるように、印刷プレビューはプリンターのように機能します。 そのため、ユーザーは、選択されている特定のプリンターから何が表示されるのかを確認します。 各ページに印刷される画像は、ビューによって決まります。

CPrintInfo 構造体のページ説明文字列は、ページごとに 1 つの数でページ番号を表す ("ページ 1" または "ページ 1~2" のように) 手段を提供します。 この文字列は、CPreviewView::OnDisplayPageNumber の既定の実装で使用されます。 別の表示が必要な場合は、"Sheet1, セクション A, B" など、この仮想関数をオーバーライドして提供できます。

関連項目

番号順テクニカル ノート
カテゴリ別テクニカル ノート