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

更新 : 2007 年 11 月

aabc3hc6.alert_note(ja-jp,VS.90).gifメモ :

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

ここでは MFC (Microsoft Foundation Class) のコントロール バー クラスである CControlBar、CStatusBar、CToolBar、CDialogBar、CDockBar について説明します。

問題

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. 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 関数が呼び出されるまで残っている必要があります。

    aabc3hc6.alert_note(ja-jp,VS.90).gifメモ :

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

EndPrintPreview

印刷プレビュー モードを終了するために呼び出されます。印刷プレビューで最後に表示したドキュメントのページに移動するときは、EndPrintPreview 関数を使います。pInfo->m_nCurPage メンバは、直前に表示されたページ (2 ページ表示の場合は左側のページ) を指すので、カーソルの位置と合わせて、ユーザーがページのどの位置にいるかがわかります。アプリケーションのビューの構造はフレームワークにはわからないので、選択された位置に移動するためのコードを作成する必要があります。

印刷プレビューに関するほとんどの操作は、CView::EndPrintPreview 関数の呼び出しの前に行う必要があります。この関数を呼び出すと、DoPrintPreview 関数の結果は失われ、pViewpDCpInfo も削除されます。

// 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" などに変更します。

参照

その他の技術情報

番号順テクニカル ノート

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