はじめに
これまでの連載では見積デモのGUIの機能について着目し、説明を行ってきました。この連載は今回で最終回となりますが、最後は印刷の機能について見ていきたいと思います。見積デモの見積書タブには、最終的に作成された見積書を印刷するための『見積書発行』ボタンが用意されています。このボタンには以下の機能が組み込まれています。
- 入力チェックを行う
- 印刷する
今回は、この印刷を実行するまでの処理について見ていきます。
印刷機能とは
Curlにおける印刷機能とは、画面と同様の方法で生成した帳票などのグラフィックを、ローカルのプリンタを利用して印刷することができる機能のことです。多くのWebアプリケーションでは、HTMLで帳票のような複雑なグラフィックを作成することができないため、ローカルで印刷を行う際はサーバ側で一度PDFなどに出力し、そのPDFをダウンロードさせて印刷を行う、といった方法をとることが一般的です。
それに対してCurlは、クライアント側で印刷するグラフィックを生成し、プリンタに直接印刷を行わせることができます。これによりダウンロードする時間を省けるため、迅速な印刷が可能になります。また、ただ印刷を行うだけでなく、印刷する用紙のマージンやヘッダー・フッターなどを指定するほか、印刷の向きや印刷するプリンタ名なども指定することができます。
Curlで印刷を行うときにはprint-graphicというプロシージャを呼び出します。これだけで印刷を実行できるのですが、簡単すぎて逆に分かりづらいと思いますのでサンプルソースを見てみましょう。
{curl 6.0 applet} {curl-file-attributes character-encoding = "shift-jis"} ||印刷したいグラフィックを生成します。 {let print-image:Frame = {Frame width = 100pt, height = 100pt, background = "yellow", "印刷に成功しました" } } {CommandButton label = "印刷", {on Action do ||印刷したいグラフィックを指定して、 ||印刷を実行します。 {print-graphic print-image} } }
このサンプルを実行すると、以下のようなボタンが表示されます。

このボタンを押下するとプリンタのダイアログが表示されて、さらに『OK』ボタンを押下すると以下のようなグラフィックが印刷されます。

印刷の基本はこれだけです。この時にprint-graphicのプロパティを設定することでプリンタ名を指定したり、印刷の向きやヘッダー・フッターなどを指定したりすることができます。
ところで、印刷といえばセットで「プレビュー」機能も用意されているものです。プレビューは、印刷するグラフィックを何らかの方法で表示してあげればよいので、先程のサンプルコードに以下の記述を追加するだけで実現できます。
{curl 6.0 applet} {curl-file-attributes character-encoding = "shift-jis"} ||印刷したいグラフィックを生成します。 {let print-image:Frame = {Frame width = 100pt, height = 100pt, background = "yellow", "印刷に成功しました" } } {CommandButton label = "印刷", {on Action do ||印刷のプレビューを表示します。 {popup-message title = "印刷プレビュー", print-image } ||印刷したいグラフィックを指定して、 ||印刷を実行します。 {print-graphic print-image} } }
これを実行すると、プリンタのダイアログが表示される前に以下のようなプレビューのダイアログが表示されます。

入力チェックとは
今回の説明をする上で、もう1つ『入力チェック』という特徴的な機能があります。これは、テキストフィールドなどに入力された内容が、開発者の意図した値であるかどうかを判定する機能のことです。多項目チェックやマスタチェックなど業務に直接かかわる処理は手動で実装する必要がありますが、単項目の『入力の有無』『文字数』『入力形式』のチェックなどはCurlの標準APIで提供されています。
入力チェックにはvalidate-withを使用します。こちらについても、まずはサンプルコードを見てみましょう。
{curl 6.0 applet} {curl-file-attributes character-encoding = "shift-jis"} {let numeric-val:TextField = {TextField width = 3cm, {validate-with {NumericValidator}} } } {HBox "数値入力:", numeric-val}
validate-withプロシージャは入力チェックを設定したいTextFieldなどに設定します。これを実行した結果が以下の図です。この入力領域は数値入力のみのTextFieldですが、数字以外の文字を入力すると入力欄の背景色が赤に変わります。


このまま入力を終了しようとするとエラーメッセージが表示され、入力エラーの項目にフォーカスが自動で戻ります。また、validate-withプロシージャの設定を変更することにより入力エラーのときの挙動やメッセージの内容、表示方法などを変更することができます。
なお、入力チェックは次のような種類があります。
- NumericValidator : 入力された値が数値であるかどうかチェックします。
- RegExpValidator : 入力された値が指定した正規表現にマッチするかチェックします。
- StringValidator : 入力された文字列が指定した文字数内かどうかチェックします。
見積デモの実装解説
では、基礎を踏まえた上で見積デモのサンプルを見てみましょう。今回も前回と同様、ソースコードが理解しやすいように、印刷の機能を抽出して作成したサンプルを添付ファイルとして用意しました。実際のソースコードについてはそちらをご確認ください。
サンプルを実行すると、以下のような画面が表示されます。
画面の左上にある各入力項目は、見積先の詳細情報を入力するためのものです。見積書作成のためには必須であるため、これらの項目には入力チェック機能を実装しています。
||見積先電話入力 {let company-phone-field:TextField = {TextField width = 150pt, ||validate-withを用いて必須入力と ||形式チェックを追加 {validate-with {RegExpValidator.from-ValidationPattern ValidationPattern.ja-phone-number }, required? = true }, ||入力完了時に電話を見積書へ反映する {on ValueFinished at tf:TextField do {if tf.validation-result == null then {phone.add tf.value,replace? = true} } } } }
各入力領域は入力チェック機能が実装されましたが、『見積書発行』ボタンを押した時に値が不正のままだと、見積書も不正のまま印刷されてしまいます。そこで、『見積書発行』ボタンを押したときにも入力チェックが実行されるようにボタン側に処理を実装します。
{CommandButton label = "見積書発行", {on Action do ||validate-dialogを用いて ||入力項目の一括チェックを行います。 {if {validate-dialog input-base-info} then ||印刷を実行します。 {print-graphic estimate-print} } } }
『見積書発行』ボタンに記述しているvalidate-dialogというのは指定したグラフィックの中に含まれる入力チェックを一括で実行し、不正な点があればエラーメッセージを表示するというものです。validate-dialogプロシージャはエラーの有無をboolで返しますので、この返却された値を見ながら、エラーが発生したかどうかを判定することが可能となっております。ここでは、validate-dialogがtrue、つまりエラーが存在しない場合のみ、印刷を実行します。
続いて、ヘッダー部分の印刷の制御を行います。今回、ヘッダーには見積先の名称や住所、電話番号などが入力されますが、入力内容に応じて帳票上の文字を変更する必要があります。そこで、以下のように実装しました。
{let name:Frame = {Frame text-underline? = true}} {let name2:Frame = {Frame}} {let address:Frame = {Frame}} {let phone:Frame = {Frame}} (省略) ||見積先名称入力 {let company-name-field:TextField = {TextField width = 150pt, ||validate-withを用いて必須入力チェックを追加 {validate-with {StringValidator}, required? = true }, ||入力完了時に名称を見積書へ反映する {on ValueFinished at tf:TextField do {if tf.validation-result == null then {name.add tf.value&" 御中",replace? = true} {name2.add tf.value&" 株式会社",replace? = true} } } } } (省略) {estimate-print.add {Frame width = {make-elastic}, halign = "left", name||見積先名称を表示 } }
まず表示用の領域としてFrame型の変数nameを用意します。変数nameで表示する文字列は見積先名称が入力されるたびに更新されます。この変数nameを印刷用グラフィック(変数estimate-print)に含めることで、動的に変更を行います。この処理を通じて、アプリケーションの操作に合わせて印刷用グラフィックを変更することにより、ヘッダー部分を常に最新の状態で印刷することができます。
最後に明細印刷の機能についてです。明細行の印刷は明細の内容とデータ件数によって実装方法が変わりますが、ここでは第2回のときに作成した明細のデータを印刷するという前提で処理を実装しています。
let total:int = 0 ||明細のレコードのイテレーションを行って ||印刷する明細のグラフィックを作成します。 {for r:Record key index:int in {RecordView list} do {estimate-meisai.add {row-prototype index + 1, r["Code"], r["Name"], r["Count"], "台", r["Price"], r["Subtotal"] } } ||合計金額を計算します。 set total = total + (r["Subtotal"] asa int) } ||合計金額を出力します。 {estimate-meisai.add {row-prototype {cell-prototype colspan = 6,halign = "right","計"},total} }
印刷を行うときも、基本はデータの集合であるRecordSetのイテレーションです。レコード1件ずつデータを抽出してレイアウトを整形し、印刷を行います。ここでは行インデックスを取得するためにRecordSetを一度RecordViewでラップしました。RecordViewはRecordSetと同様に操作することができるデータの集合ですが、RecordViewを用いると行のインデックスを取得することができるようになります。
このような機能を組み合わせて、印刷機能が実装されています。実際の動作については、添付ファイルの方にてご確認ください。
おわりに
以上全3回を通じて見積デモの機能をご紹介してきましたが、見積デモの構造を理解いただけましたでしょうか? 見た目は複雑そうな機能も、1つ1つ機能を紐解いていくと、実はシンプルな実装によって実現されています。見積デモはこの他にも日付の入力や見積情報の出力などさまざまな機能がありますが、これらもCurlのAPIを用いて単純に実装されているのがほとんどです。
この他にも、Curl Apps Galleryには100を越えるアプリケーションが公開されています。それらはソースコードも合わせて公開されており、中には実際の開発に役立つアイデアもいっぱい詰まっています。Curlにご興味を持っていただけた方、またCurlの開発を行うことになった方はぜひCurl Apps Galleryを覗いてみてください。