スクリプトによる Web ページ印刷のサポート

Andrew "Captain" Cerebrum
Senior Developer
Mead & Company Limited

November 20, 1998
日本語版最終更新日 2003 年 6 月 19 日

目次
はじめに
印刷と Internet Explorer 5: 新しい機能
Internet Explorer 4.x における方法: WebBrowser コントロール
印刷関連のコマンド
例 その1
フレームの中
非表示コンテンツの印刷

はじめに

この記事では、Internet Explorer 4.0 以降を使って表示される HTML ページで印刷サポートを実装する方法について説明します。Internet Explorer 5 の新しい印刷機能を紹介し、以前の 4.x ブラウザとの「後方互換性」を提供するためにページに組み込むことができる Jscript(R) ファイルを提供します。また、この print.js ファイルを使用するいくつかのサンプルを示し、コードを簡単に説明し(技術指向でない読者はこの部分をスキップしてかまいません)、ActiveX コントロールをベースにしたページ印刷の設定をさらにカスタマイズする方法をいくつか紹介します。

Internet Explorer 4.0 では、Web アプリケーション開発のための新しい、きわめてエキサイティングな機能がいくつも追加されました。しかし残念なことに、非常に重要な機能が1つ抜け落ちていました。印刷機能です。Internet Explorer 4.x には、ページの印刷やページ設定の変更を行うための Dynamic HTML(DHTML) DOM メソッドはありません。Internet Explorer 5 のリリースに伴い、新しい印刷機能が追加されましたので、この記事では、まず Internet Explorer 5 のネイティブな印刷サポートの使い方を紹介し、Internet Explorer 4.x における 100% に近いエミュレーションの可能性を追究してみることにします。

印刷と Internet Explorer 5: 新機能

まず Internet Explorer 5 の新しい印刷に関する関数を簡単に説明します。

window.print()

このメソッドは、ユーザーが[ファイル] - [印刷]メニューを選択したときと同じ動作をします。通常の HTML ページでは、ユーザーインターフェイス(UI)なしに印刷を開始することはできません。このメソッドは Netscape Navigator 4.x との互換性があるので、パラメータは取りません。

window.onbeforeprint

このイベントはキャンセルが不可能で、バブリングも行いません。これは文書が完全に読み込まれ、onload イベントが返された後にのみ発生します。印刷は onbeforeprint ハンドラが実行を終えるまでは行われません。

window.onafterprint

このイベントはキャンセルが不可能で、バブリングも行いません。イベントハンドラが実行されるまで、UI の制御はユーザーに返されません。このイベントは、すべての描画操作が完了した後に呼び出されます(言い換えると、ソフトウェアの仕事が終了し、印刷ハードウェアが仕事を始めたとき)。

コードを使用しないイベントハンドラの設定方法

onbeforeprint および onafterprint イベントハンドラは、既存の onload および onunload イベントとよく似た方法で定義します。これらは次の属性を使って設定することができます。

<BODY> の場合:


<body
onbeforeprint="beforeprint()"
onafterprint="afterprint()">

<FRAMESET> の場合:


<frameset onbeforeprint="beforeprint()"
onafterprint="afterprint()">

また、実行時に割り当てることもできます:


window.document.onbeforeprint=beforeprint;
window.document.onafterprint=afterprint;
window.onbeforeprint=beforeprint;
window.onafterprint=afterprint;

コードサンプル


//これは、印刷前にタイトルが変更されたページが
//印刷後には元のタイトルにリセットされることを示すサンプルです。
var originalTitle;

<script for=window event=onbeforeprint>
  originalTitle = document.title;
  document.title = document.title + " - by Captain"
</script>

<script for=window event=onafterprint>
  document.title = originalTitle;
</script>

要約すると、スクリプトからの印刷が可能になり、印刷の直前に選択を行うことができ、印刷の開始後にも何らかの処理を行えるようになっています。これはInternet Explorer 5 以降のユーザーにとっては願ってもない進歩だといえます。しかし、Internet Explorer 4.x と Internet Explorer 5 の両方を対象に、印刷タスクを一般化して実現するにはどうすればいいのでしょうか? これ以降では、ネイティブな印刷サポートと、それが存在しない場合にその機能をエミュレートするスクリプトを示していきます。

Internet Explorer 4.x における方法: WebBrowser コントロール

カスタムブラウジングアプリケーションを作成している開発者は WebBrowser コントロールのことをよく知っています。これは、Active Documenst (MSHTMLドキュメントなど)をホストし、文書間のナビゲーションを処理する下位のエンジンです。個々のページと、ネストされているフレームは、対応する WebBrowser オブジェクトを持っています。

安全については?

WebBrowser コントロールは、潜在的に安全ではないオートメーションプロパティを一式持っていますが、HTMLページ上に WebBrowser コントロールを配置すべき明白な理由はないし、いずれにせよ Internet Explorer 4.0 チームはそのような気晴らしの全く無駄なことに対して最善を尽くしているので(PRB: Permission Denied Accessing Web Browser Control in HTML Non-MSDN Online link を参照下さい)、直ちに問題にならないでしょう。しかし、誰か頭のいい人間が(Steve Gore かもしれません。ただし、これを最初に行った人が誰なのかはわかっていません)、WebBrowser の Exe cWB Non-MSDN Online linkメソッドを使ってページの印刷を開始するというアイデアを思いついたのです。

手段がある場合には……Where There's a Method ...

実際、ExecWBは、カスタムの WebBrowser ホスティングを行っている開発者のみを対象として、部分的にしか文書化されていません。しかし、HTML ページには、スタンドアロンで、ナビゲーションされていない WebBrowser オブジェクトを配置することが可能だということが分かっています。この場合、オブジェクトはすべての ExecWB 呼び出しを親文書に転送します。

印刷関連のコマンド

WebBrowser は、印刷関連のコマンドとして、OLECMDID_PRINT(6,1) と OLECMDID_PAGESETUP(8) をサポートしていることがわかっています。

基本事項

トリックは、DHTML を使って一時的な WebBrowser オブジェクトを作成し、その ExecWB(6, 1) を呼び出してページを印刷することにあります。次に例を示します。


document.body.insertAdjacentHTML("beforeEnd",
    "<object id=\"idWBPrint\" width=0 height=0 \

classid=\"clsid:8856F961-340A-11D0-A96B-00C04FD705A2\">
    </object>");
  idWBPrint.ExecWB(6, 1);
  idWBPrint.outerHTML = "";

現実の世界では、ユーザーが印刷ダイアログのキャンセルボタンを選択した場合に ExecWB(6, 1) が実行に失敗するので、上記のコードにエラー処理を追加することになります。

例 その1

注: これらのサンプルを実行するためには、Internet Explorer 4.x か Internet Explorer 5 を使用している必要があります。

最初のサンプルを実際に試してみるか、この後の詳しい説明を読んでください。JScript の印刷メソッドは printFrame(frameToPrint) です。また、print.js ファイルにはコードの説明があるので、これを読んでもかまいません。このコード (英語) は Internet Explorer 5 の新しいネイティブな印刷サポートを使用しており、Internet Explorer 4.x の print() メソッドと onbeforeprint/onafterprint イベントのためのエミュレーションも提供しています。このサンプルを使用するには、自分のページに print.js ファイルをインクルードしてください。


<script defer
src="print.js"></script>

これで、1つの HTML ページ ソースで Internet Explorer 4.x と Internet Explorer 5 の両方に対応することができます。


<head>
<title>Simple Printing</title>
<script defer language=JScript
src="print.js"></script>
</head>

<body onbeforeprint="beforeprint()"
onafterprint="afterprint()"
  bgcolor="infobackground">
<p><input disabled name="idPrint" type="button"
  value="Print this page"
onclick="print()"> </p>
</body>

<script defer>
function window.onload() {
  idPrint.disabled = false;
}

var originalTitle;
function beforeprint() {
  idPrint.disabled = true;
  originalTitle = document.title;
  document.title = originalTitle + " - by Captain";
}

function afterprint() {
  document.title = originalTitle;
  idPrint.disabled = false;
}
</script>

Internet Explorer 4.x のサポートは、<BODY> のインラインで割り当てられたイベントハンドラに対してしか用意されていないことに注意してください。完璧ではありませんが、Internet Explorer 4.x と Internet Explorer 5 の両方に同じコードで対応するという意味では十分だと思います。上のサンプルコードで、文書のタイトルを印刷時に更新している点に注意してください。

フレームの中

他にも、特定のフレームを、おそらくは他のフレームから印刷したいことがあります。また、フレームの内側からウィンドウの内容を印刷しなければならないこともあるでしょう。幸いなことに、WebBrowser はデフォルトでフォーカスを持っているフレームを印刷します。したがって、われわれはフォーカスを必要なフレーム(またはウィンドウそのもの)に設定するだけで済みます。これが必要なのは Internet Explorer 4.x のみです。Internet Explorer 5 では、特定のフレームの frame.print() を呼び出すだけです。

注意 その1(Internet Explorer 4.0)

残念なことに、Internet Explorer 4.0 には、特定のフレームにフォーカスを設定する方法はありません。frame.focus() に何の効果もないためです。これは Internet Explorer 4.01 では修正されていますが、Internet Explorer 4.0 のユーザーはフォーカスを持っているフレーム/ウィンドウしか印刷できません。

注意 その2(Internet Explorer 4.01)

frame.focus() の後に idWBPrint.ExecWB を使用すると、WebBrowser はフォーカスの変更をただちに行わず、ウィンドウ全体を印刷します。これを回避するには、setTimeout() 呼び出しを使って、idWBPrint.ExecWB コマンドを先に延ばします(技術的には、次のメッセージループまで)。われわれが用意したフレーム印刷のサンプルを試してみてください。

注意 その3(Internet Explorer 4.x)

フレームの中から printFrame を呼び出したときにも、望ましくない問題が生じることがあります。ユーザーがキャンセルを行うと、印刷ダイアログはトップウィンドウまでの個々のフレームネストレベルで「バブル」します。この動作は困りますが、対処策は存在します。このような機能が本当に必要なのであれば、Scripting Factory ActiveX control を使用してください。

非表示コンテンツの印刷

もう1つの興味深い機能は、非表示 HTML 文書の印刷です。たとえば、Webコンテンツ制作者が HTML で生成されたデータベースレポートを印刷したいと考えているとします。次のサンプルを見て、細部に関心がある方はコードの説明 (英語) を読んでください。メインメソッドの printHidden(url) は、共有インクルードファイル printHid.js に含まれています。


<head>
<title>Hidden Document Printing</title>
</head>

<body bgcolor="infobackground">

<p>This is a main page</p>
<script defer language=JScript
src="print.js"></script>
<script defer src="printHid.js"></script>

<p><input disabled name="idPrint" type="button"
  value="Print this page" onclick="print()">
<input disabled name="idPrintFrame" type="button"
  value="Print the frame below"
onclick="printFrame(idFrame)"> </p>
<IFRAME style="visibility: visible" name="idFrame"
  width="50%" height="30%" src="frame.htm">
</IFRAME>

<p><input disabled name="idPrintHidden" type="button"
  value="Print hidden page"
onclick="printURL()"></p>

<script defer>
function window.onload() {
  idPrintHidden.disabled = false;
  idPrint.disabled = false;
  idPrintFrame.disabled = false;
}

function printURL() {
  idPrintHidden.disabled = true;
  // set to handle completition
  window.onprintcomplete = function() {
    idPrintHidden.disabled = false;
  }
  // print the content
  printHidden("report.htm");
}
</script>

</body>
</html>

"Captain" の告白

Internet Explorer DOM には印刷設定のカスタマイズのサポートがないため、多くの人から「この印刷設定のカスタマイズはどうやって実現したのか」という質問が寄せられました。種明かしをすると、そのあまりの単純さに笑い出す人もいるかもしれません。われわれは非表示の「ページ設定ダイアログ」を呼び出し、ユーザーであるかのように設定の取得/変更を行います。それだけなのです(ただし、コードが安全になるように注意して作ってありますが)。ダイアログコントロール ID はローカライズされた Internet Explorer バージョンの間で共通しており、Internet Explorer 4.x と Internet Explorer 5 の間でも同じなので、このコードはこれらすべてのバージョンで正常に動作します。将来のバージョンの Internet Explorer で何かが変更された場合には、それに合わせて ScriptX をアップデートする予定です。現在のところ、スクリプトからページ設定をカスタマイズする方法は、われわれが知っている限りこれが唯一のものです。

ScriptX Non-MS link は無償で提供されている MeadCo Scripting Factory の一部です。MeadCo Scripting Factory は、Internet Explorer 4.0 以降の HTML、ASP、WSH、またはカスタムを含む任意のスクリプティングホストで使えるように開発されており、同社の進化を続けるWebアプリケーションツールキットの一部でもあります。1988年に創立され、Cambridge UK に本拠を置くMeadCoは、全世界の企業/組織のクライアントのためのオンライン情報システムの構築、保守業務を行っています。