その問題とさまざまな可能性〜Printerオブジェクトだけが印刷ではない
酒井法雄 SAKAI,Norio
| 印刷もラクじゃない |
|---|
Visual Basicはバージョンが上がるごとに,さまざまな機能が追加されてきた.一般的にいえば,そのおかげでソフトウェアの開発効率は確かに上がってきた.しかし,唯ひとつ進化していない分野がある.それが印刷だ.
もちろん,まったく進化していないわけではなく,バージョン4.0からは大幅な機能アップがはかられた.これには,ふたつの要素がある.
ひとつめはPrinterオブジェクトである.従来のPrinterオブジェクトに加え,インストールされているプリンタがPrintersコレクションとして取得できるようになったことが一番である.つまり,プリンタ設定がコードでできるようになったということだ.また,PaintPictureメソッドを使ってビットマップの印刷が可能になったこともある.
ふたつめは,Crystal Reportsのバンドルである.これは英語版Visual Basic 3.0からのものだが,要はデータベースの入っているデータを効率よく印刷しようというものだ.これは,いわゆる業務アプリケーションを作るときには,強力な助っ人となる.
と月並みなことを書いてしまった.しかし,正直に告白すると,私は印刷が大嫌いだ.できれば,印刷部分のプログラムは作りたくないと思っている(そして当然ながら,私が印刷特集の巻頭を書くなんてまっぴらだと思っている)(編注:…).なぜならば,そもそもがPrinterオブジェクトも,Crystal Reportsも,マトモに動いてくれないからである.いわゆる標準機能だけで印刷をしようとすると,これらのバグや妙な仕様などに悩まされることになる.だからやりたくないのだ.というのが建て前だ.
だからこそ,役に立つ記事を書くべきだという意見はもっともだ.しかし,本当に現実的な一般的解決法が浮かばないほど,実にその根は深いのである.それは,単にVisual BasicのPrinterオブジェクトがバグだらけだからAPIを使うべしとか,オマケでついてくるCrystal Reportsはダメで製品版を買うべきといった議論より先にある.
印刷での問題はWindows自体が抱えている印刷についての制限と,印刷に求められる日本人の潔癖主義とも言えるまでのクオリティの高さ,いや細かさという相反する要素があるのだ.
まず述べておきたいのは「印刷に関してはできるだけ妥協しよう」ということなのである.
| 印刷に関わる諸問題 |
|---|
まずは,印刷というテーマに関わる諸問題について,その傾向を述べておくことにしよう.
プリンタドライバの品質
ここでは,ややモノローグ的になるが,私のVisual Basicにおける印刷についての経験を述べておこう.
ここまで印刷を嫌がっているというのは,単に印刷での位置決めなどのデバッグが面倒だとか,そういった単純な話ではない.実は印刷については人一倍苦労した経験があるのだ.
それは,Visual Basic 2.0全盛の頃,あるVisual Basic開発者向けセミナーが終わったときだった.一人の紳士が私に話しかけてきた.こういったセミナー終了後には,質問攻めに合うことはしょっちゅうなので,別段驚くようなことではない.しかし,彼は私に仕事を依頼したいという.それは,自社ブランドでVBXを発売したいが,どんなものがよいかという相談だった.当時はクライアント/サーバーの話もほとんどなかったので,Visual Basicに不足している機能といえば印刷だろうということになった.それも,当時はできなかったビットマップの印刷やプレビューができるようにしようというものだ.しかもプリンタ設定までできるようにしようというのである.こうしてでき上がったのが,PrintPreview/VBXである.
自画自賛になってしまうが,これは当時としては画期的な商品だった.国産オリジナルVBXとしてもアイデアも卓抜していた.データベースに対応するようなものでもないが,基本的な機能はしっかりしていた.サンプル版として配布したモジュールには,VBのフォームに必要事項を入力すると申込用紙がプレビュー,印刷できるサンプルプログラムが入っており,FAXを使ってそのままオーダーする可能性も示唆していた.そして,この製品はそれなりに評価され,それなりに売れた.
この製品は,もちろんCを使って書かれており,Visual Basicのブラックボックス部分を使うことがあるとはいえ,ほぼWindowsネイティブな動作をするものだ.したがって,Visual Basicに関わりのない部分については,ほぼ完璧な動作をした…ハズだった.
ところが,そうはいかなかった.なぜかといえば,プリンタドライバの品質が悪く,意図通り動作しないことがままあったのである.当時のWindows 3.1に附属のプリンタドライバはすべてバグっていたといっても過言ではない.メーカーによってはときどきバージョンアップしてくれたが,完璧というには程遠かった.
このような問題が起きたときに必要になるのがリファレンスである.たとえば画面に何か描画するとリソースが減るといった問題が起きたときには,ビデオドライバが疑わしい.このようなときには,VGAにして調査してみる.VGAで問題がなければ,そのビデオドライバの問題であることがわかる(もっとも,当時のVGAのドライバにも問題はあった).ところが,プリンタではそうはいかないのだ.
そこで,複数のプリンタで調査することとなるのだが,いずれのプリンタドライバでも使っているMicrosoft提供のモジュールがバグっていることもある.これではお手上げである.正確にドライバの問題かどうかを判断するためには,いわゆるGDIプリンタを使ってテストするしかない.しかし,そのGDIプリンタのファームウェアがバグっていない保証もないのだ.
このように,Windowsでの印刷はすべてプリンタドライバに依存している.いかにバグのないプログラムを作っても,プリンタドライバがバグっていては,どうしようもないのだ.そして,メーカーにバグを指摘しても,そうスグには直るものではないのは,ご存じの通りである.
もちろん,当時と今とではWindows自体の普及率が違うから,プリンタドライバの品質も向上していることは確かだ.しかし,いまだにWindows NT用のプリンタドライバが用意されていないとか,機能が低いとか,品質が悪いといったことはあるようだ.
連帳とカスタムサイズ
プリンタドライバが必須となっているWindowsでの印刷では,すべてがページ単位で印刷されることが前提となっている.したがって,連帳へのジャーナル印刷や,カスタムサイズへの印刷では問題が起きる.
まず,ログをそのまま随時1行ずつ印刷していくというような芸当はできない.また,送り状や領収書,請求書,納品書などがコピーされるタイプのカスタムサイズの連帳も問題だ.
もちろん,プリンタドライバによっては,カスタムサイズに対応したものや,ユーザー定義サイズを指定できるものもある.しかし,ユーザー定義サイズは実際に印刷していくとズレてきたりすることもるあるので,何度もトライしたり,ときどき位置を合わせ直したりする必要があるパターンもありがちだ.
連帳にも,1行をユーザー定義サイズとすればジャーナル印刷ができそうなものだが,実際には改ページされてしまうという問題もある.
また,ユーザー定義サイズの大きさに制限があり,意図したサイズを指定できないケースや,正しく動かないケースもある.
エスケープシーケンスを出力できない
これもプリンタドライバを介して印刷するというWindowsの仕組みゆえの問題だが,エスケープシーケンスを出力することができない.これは問題というより,当然の仕様である.エスケープシーケンスなど使わなくても,GDIに描画した内容がそのまま印刷できることがメリットなのである.
もちろん,場合によってはエスケープシーケンスで制御したいコトはある.特に,以前にMS-DOSなどで作成したシステムがあれば,そのときのコードをそのまま使いたいというのが人情だろう.
しかし,それはプリンタドライバの役割である.Windowsプログラマとしては,GDIにきれいに描画することを考えるべきなのだ.
印刷に要求される細かさとツールの機能
日本人は印刷が好き,そして罫線が好きである.今や表計算ソフトの定番となったExcelの前身であるMultiPlanに罫線の機能がついたのは,日本語版からだったということからも,日本人の罫線好きが窺い知れるだろう.それはそれで便利なこともあるからよいのだが,過剰に罫線を使いたがる嫌いがあるのも確かだ.
印刷時にこうした罫線をあちこちに入れようとすると,ツールがうまく対応できないというケースが多い.これは,日本人向きにできていないからといえばそれまでだが困った問題である.
私などは,それなら罫線はやめましょうと提案してしまうところだが,世の中のプログラマ諸氏は罫線で起きる問題を解決することが自分の仕事だと思っている方も多いようだ.
ここでは罫線を例に述べたが,実際にはこれは罫線に限らない.細かい位置指定や文字サイズの問題などもある.たとえば,プロポーショナルフォントを使えば,文字幅が違ってくるのは当然なのだが,それについて文句が出るということもある.また,特定の場合のみフォントあるいはフォントサイズを変えなくてはならないといったケースもある.このようなときには,元となるデータ自体の英数文字コードを統一しておくといった,印刷以前の問題で解決できることもある.
出力が遅い
ページ単位でプリンタドライバが描画するという特性から,Windowsでの印刷は生のエスケープシーケンスを使った印刷より遅くなりがちだ.大量の印刷をしようとしたときには,これは大きな問題となるケースもある.
もっとも,最近ではプリンタが安価で高速になってきているから,このような問題は少なくなってきているように思う.
複数プリンタの制御
以前はVisual Basicでは実現できなかったが,Visual Basic 4.0以降では先に述べたようにPrintersコレクションを使って,コードを使ってプリンタの切換や,設定の変更ができるようになっている.これだけは唯一Visual Basicが解決してくれたものだ.
| 印刷を実現する多彩な方法 |
|---|
Visual Basicというよりは,Windowsでの印刷について一般的な話をしてきた.どれもあきらめよという消極的な内容になってきたが,現実はそれほど悲観的なものでもない.次に,現状で考えられるさまざまな印刷の手法を紹介しよう.その中には,先ほどの悲観的な結論めいたことをひっくり反すような手法もある.
Printerオブジェクト
Visual Basic標準の印刷方法だ.PictureBoxなどの描画メソッドとほぼ同様の方法で,仮想のPrinterオブジェクトに描画して印刷するというものだ.また,Printersコレクションでのプリンタ切換や設定の変更ができる.
Printerオブジェクトでの問題は,次のようなものだ.
| 細かい位置決めをいちいちコードを使って書かなくてはならない |
| プレビューできない |
| 印刷可能範囲はScaleWidht, ScaleHeight内でなければならない |
| アトリビュートを指定するとうまく動作しないことがある |
バグについては,APIを駆使してなんとか回避できるが,はっきりいってこんな信頼性が低くて使いにくいものは,使いたくない.ことPrinterオブジェクトについては,Visual Basic 5.0になってもバグはあまり修正されていないように思う.割り切った使い方にのみ使おうと思った方がよいだろう.
なお,Printerの設定を変更したときには,GDIデバイスを初期化するために,Priner.EndDocを忘れないように実行してほしい.
コモンダイアログ
Visual Basic附属のコモンダイアログActiveXコントロールを使えば,印刷設定のダイアログを出すことができる.しかし,印刷枚数などの設定がきちんと反映されないバグがある.
ActiveXコントロール
Spread/OCXやチャート系のActiveXコントロールでは,そのコントロール内に保持しているシートあるいはチャートのデータをそのまま印刷することができる.面倒なことをいわなければ,これは非常に簡単で効率のよい印刷方法である.
Crystal Reports
Visual Basicについてくるものはオマケである.使おうと思ったら,製品版を買うべし.あるいは,同様の他の製品を買うべし.オマケのまま使って泣くのは開発者である.もっとも,これも割り切った使い方なら十分に使えるものである.真崎氏の稿も参照されたい.
その他の印刷用ツール
Crystal Reportsが一番優れた印刷ツールというわけではない.他にも各社から優れた印刷ツールが発売されている.目的に応じてそれらを使うのもよいだろう.これらについては,別表などを参照されたい.
Office製品を印刷ツールとして使う
恐るべきことに,どこのWindowsマシンを使っても,なぜかMicrosoft Officeが入っていることが多い.これらは,ご存じのようにワープロやら表計算ソフトやらデータベースやらのツールであり,もちろん印刷機能ももっている.そもそもが,それぞれのアプリケーションだけでもかなりのクオリティの印刷業務が可能である.これを使わない手はないだろう.
もちろん,こういったWord,Excel,AccessといったツールにはVisual Basic for Applications EditionというVisual Basicライクな言語が搭載されているうえ,OLEオートメーションを使ってVisual Basicから制御することができる.これについては,別稿で述べることにしよう.
シリアルポートの使用
裏ワザに近いが,シリアルポートを持つプリンタであれば,当然ながらシリアルポートを使っての印刷が可能だ.MSCommあるいはPDQCommといったRS-232C制御ActiveXコントロールを使えば,自在にエスケープシーケンスを使った制御が可能である.もちろん,連帳への対応やジャーナル印刷も可能だ.
以前のWindowsであれば,LPT1:やPrnデバイスをOutputモードでオープンして印刷するという必殺技もあったが,最近のものではうまくいかないようだ.
図1:オーバーレイプリンタの仕組み
|
オーバーレイプリンタ
実は私がもっともお勧めしたいのが,このオーバーレイプリンタである.少々価格が高いとか,あまり一般的でないという問題はあるが,これは非常に便利なものだ.
簡単にいうと,次のようなものだ.
| 専用のツールなどでテンプレートとなる印刷イメージファイルを作成 |
| ファイルをプリンタにアップロードする |
| テンプレートに流し込む文字列を含むテキストファイルを作成 |
| Visual BasicからActiveXコントロールやDLLを使って印刷ルーチンに,テンプレートとテキストファイルを指定して呼び出す |
製品によって細かい部分は違うが,大筋ではこのような仕組みである(図1参照).ダイナミックに変わるビットマップなどには対応していないケースも多いようだが,テキストのみを印刷するのにはこの上なく便利である.また,高速でもある.もちろんデータベースだろうが何だろうがテキストを流し込むだけだからどうにでもなる.
| それでも印刷しなくては |
|---|
実のところ,このオーバーレイプリンタを使ってから,ばかばかしくてPrinterオブジェクトや面倒なツールを使う気にならなくなったのである.
それならばというので,ふつうのプリンタでもこれができるような仕組みをドライバ込みで作ってしまおうと真面目に考えたことがある.ずっと忘れていたが,この記事を書いているうちに思い出してしまった.うーん,今からでも作ろうかな.
このように,印刷といってもPrinterオブジェクトとCrystal Reportsしかないわけではない.実のところ,私の会社でも社内業務の印刷にはAccessやWordが活躍している.何でもVisual Basicでやってしまおうと考えないことが,一番重要なことなのかもしれない.