Share via


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

注意

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

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

問題

MFC (Microsoft Foundation Class) の機能によって、ほとんどの印刷や印刷プレビューを実現できます。 多くの場合、わずかなコードを追加するだけで、ビューを印刷したりプレビューできるようになります。 印刷を最適化することもできますが、それには多くの労力を必要とし、場合によっては印刷プレビュー モードにユーザー インターフェイスを追加する必要もあります。

効率的な印刷

MFC アプリケーションの標準的な印刷方法では、すべてのグラフィカル デバイス インターフェイス (GDI: Graphical Device Interface) 出力呼び出しは、Windows によって、メモリ上のメタファイルに対して行われます。 EndPage が呼び出されると、Windows はプリンターが 1 ページの印刷に必要とする物理的なバンドのそれぞれに対して 1 回ずつメタファイルを出力します。 このレンダリング中、GDI は周期的にアボート プロシージャに対して印刷を継続するかどうかを問い合わせます。 一般にアボート プロシージャでは、ユーザーが印刷ダイアログを使って印刷ジョブを中止できるように、メッセージを処理します。

残念ながら、この処理によって印刷プロセスが遅くなっています。 標準的な方法よりも高速に印刷を行いたい場合は、手作業によるバンド処理を実装する必要があります。

印刷バンド処理

手作業でバンド処理を行うには、1 ページについて複数回 (バンドあたり 1 回) OnPrint 関数が呼び出されるように、印刷ループを実装し直します。 印刷ループは viewprnt.cpp ファイルの OnFilePrint 関数で実装されています。 CView の派生クラスでこの関数をオーバーライドして、print コマンドを処理するメッセージ マップのエントリから、独自の印刷関数が呼び出されるようにします。 OnFilePrint ルーチンをコピーして、バンド処理を行うように印刷ループを変更してください。 また、独自の印刷関数にバンド処理用の四角形を渡し、印刷されるページの範囲を基準にして最適な描画を行うことができます。

また、バンドを描画している間は、QueryAbort 関数を定期的に呼び出す必要があります。 この関数を呼び出さないと、アボート プロシージャが呼び出されないので、ユーザーは印刷ジョブをキャンセルできません。

印刷プレビュー。ユーザー インターフェイスを備えた電子用紙

印刷プレビューの本質は、画面をプリンターに変身させることにあります。 既定では、メイン ウィンドウのクライアント領域に、1 ページか 2 ページがまるごと表示されます。 ユーザーは、ズーム インしてその内容を詳しく調べることもできます。 機能を追加して、プレビュー モードでドキュメントを編集できるようにすることも可能です。

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

このメモにのみ印刷プレビューの変更の 1 つの側面でお得な情報します。プレビュー モードに UI を追加します。 他の変更方法については、ここでは扱いません。

プレビュー モードにユーザー インターフェイスを追加するには

  1. CPreviewView からクラスを派生します。

  2. 必要なユーザー インターフェイスに対して、コマンド ハンドラーを追加します。

  3. 画面の表示に対して変更を加えるには、OnDraw 関数をオーバーライドして CPreviewView::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。

  • 印刷プレビューで印刷が実行されるビューへのポインター。

  • プレビューのビュー クラスのランタイム クラス。 これは DoPrintPreview で動的に作成されます。

  • CPrintPreviewState ポインター。 CPrintPreviewState 構造体 (他にも状態を保存する場合は、その派生構造体) は、フレーム上に作成しないでください。 DoPrintPreview 関数はモードレスなので、この構造体は EndPrintPreview 関数が呼び出されるまで残っている必要があります。

    注意

    印刷で分割されたビューやビュー クラスのサポートが必要な場合には、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 ページ印刷されます。この場合、印刷プレビューは何を "ページ" として考えればよいのでしょうか。

最初に述べたように、印刷プレビューはプリンターのように動作します。 そのため、ユーザーは選択したプリンターによる出力内容を参照できます。 各ページに印刷するイメージは、このビューによって決定されます。

"Page 1" または "Pages 1-2" のように、ページごとに 1 つの番号を示すことができる場合は、CPrintInfo 構造体のページ記述文字列を使って、そのページ番号を表示できます。 この文字列は CPreviewView::OnDisplayPageNumber 関数の既定の実装で使われています。 表示を変更するには、この仮想関数をオーバーライドし、文字列を "Sheet1, Sections A, B" などに変更します。

参照

その他の技術情報

番号順テクニカル ノート

カテゴリ別テクニカル ノート