RealBasic University

このコラムはStone Table Softwareのオーナーであり、またREALbasic Developerの編集者でもあるMarc Zeedar氏により書かれたものを、著者の許可を得て翻訳したものです。この翻訳はHREM Researchにより提供されています。この日本語版へのご意見はRBU-Jまでご連絡下さい。

URL: http://www.applelinks.com/rbu/065/
INDEXに戻る

FontPrinter:パート 4

前回から印刷システムのプログラムに取り組み始め、それはほぼ終了しました。一番初めに完成したいものは、印刷プレビュー機能です。これは作成するのに少し単調で退屈なように思えます。しかしこの良い点は、このウィンドウを一度作成してしまえば、後はハードディスクからプログラムをドラッグしてコピーするだけで簡単にそれを再利用できることです(完成したウィンドウをエキスポートするためには、それをREALbasicからFinderウィンドウにドラッグしてください)。

印刷プレビュー・ウィンドウの構築

PrintPreviewウィンドウが再利用できる理由は、それが極めて自己完結型のプログラムだからです。それは、機能させるためにたった2つのグローバル属性が必要なだけです。そのグローバル属性は画像であるpと、ユーザがキャンセルかOKを押したかを知らせる論理型であるgPrintOkayです。あなたの作成した他のプログラムにこれらのグローバル属性を加えることによって、他のプロジェクトでこれと同じPrintPreviewウィンドウを簡単に扱うことができます。たとえあなたがそれをデバッグやプログラムの印刷ルーチンのテストのためだけに使い、プログラムの最終的なバージョンではその機能を使わないとしても、これは常に手元に置いておくべき役に立つリソースです。私はいつもそれを使っています。

詳細

現バージョンの印刷プレビュー機能は、1ページの印刷に限られています――しかし複数ページの印刷へ対応を拡張することはそれほど難しいことではありません。主に必要になる変更点は、グローバル属性のpをダイナミック配列に変換し、印刷する文書のすべてのページにそれを保存することです。それから、ユーザにそれらの画像全体を移動(矢印キー、pushButton機能、あるいは両方を用いて)できるようにさせるために、印刷プレビュー内に拡張機能を追加する必要があります。

いつものように、インターフェースの作成から始めましょう。印刷プレビュー・ウィンドウは少しの要素しかないので、それほど難しくありません。まずcanvasに、次のような属性を与えましょう。

印刷画像を描画する場所であるpreviewでは、"lock"属性がチェックされているので(lockLeftlockTop等)、previewprintWindowに合わせて拡大縮小します。

次に、縦・横両方向の2つのscrollBarを追加します。それらの設定は次のようになります。


最後に、cancelButtonprintButtonと呼ばれる2つのpushButtonが必要です。そして後者のボタンをデフォルトに設定します。完成したウィンドウは次のようになっているでしょう。

さて次に、コードを加えていきます!

印刷プレビューウィンドウのコーディング

まずウィンドウが最初に必要とするイベントのコーディングから始めましょう。実際に必要なのは、設定を初期化する場所であるOpenイベントと、ウィンドウのサイズが変更されたときに必要となるResizeイベントの2つだけです。

ここにOpenイベントのコードを掲載します。

   dim xDif, yDif, w, h as integer 

xDif = me.width - preview.width
yDif = me.height - preview.height

w = p.width + xDif
h = p.height + yDif

if w < screen(0).width - 30 and h < screen(0).height - 50 then
// スクリーンにフィットする最小値
me.width = w
me.height = h
else
// スクリーンに対して大きすぎるときのサイズ変更
me.height = screen(0).height - 50
me.width = (me.height / h) * w
end if

gPrintOkay = false

基本的にここで行っているのは、現在のスクリーンにフィットするようにプレビュー・ウィンドウのサイズを調整することです。それは大きければ大きいほど望ましいですが、大きすぎるのも良くありません(メニューバーとウィンドウのタイトルバーのための余白を残しておきます)。

始めの2つの変数xDifyDifは、ウィンドウの端から描画領域(印刷画像を描画するキャンバスのpreview)の始まりの間までのスペースを保存しておくために使用されます。それから、画像サイズにウィンドウ・インターフェースの必要な領域を加えたwhを設定します。(これを実行時に計算する大きな利点は、要素を動かしたときや新しいものを加えた場合でも、依然として機能するということでしょう。)

変数whは、必要なウィンドウの最大サイズを伝えます(この値よりも大きい値は、プレビュー領域が描画する画像よりも大きくなってしまい無意味です)。よって次に、 whをメイン・スクリーンscreen(0)のサイズからメニューバー等の値を差し引いたものと比べます。画像がフィットすれば、設定は完了です:後はウィンドウのサイズをwhに設定するだけです。

もし画像がフィットしなければ(画像がメイン・スクリーンよりも大きい)、ウィンドウをできるだけ大きな値に設定します。ほとんどの印刷ページは縦方向なので、なるべくウィンドウを高くするようにして(スクリーンの高さ−50ピクセル)、それに比例して幅を設定します(高さと同じ割合かそれよりも小さく)。

初期設定の最後は、gPrintOkayfalseに設定されることを確認します(印刷のキャンセルをデフォルトにします)。

次に、Resizeイベントのコードを追加しなければなりません:

   horzScrollBar.maximum = p.width - preview.width 
vertScrollBar.maximum = p.height - preview.height
horzScrollBar.value = 0
vertScrollBar.value = 0

ここではscrollBarの調整を行っているだけです。ウィンドウの幅と高さ(すなわちプレビュー領域)は、(もし必要あれば)スクロールに必要な量に影響を与えるので、ウィンドウのサイズが変更される場合はいつでもこれを実行する必要があります。

実際には、ユーザがウィンドウのサイズを調整する方法はありませんので、これは初期設定中(Openイベント)でウィンドウのサイズを調整するときにだけ実行されます。したがって、われわれはこれをOpenルーチンに入力することもできましたが、このようにするのがより論理的で、適切な方法です。

このルーチンでは、画像サイズとプレビュー領域サイズとの差分に、それぞれのスクロールバーのmaximum属性を設定します。したがってもしその差に違いがあれば、それがプレビューするためにスクロールしなければならない量となります。

最後の2行は、スクロールバーの"ボタン"をスタート・ポイントにセットするだけです。(あなたの好みで、.maximum / 2とすることにより、ボタンを中央に設定することもできます。)

ここでスクロールバーに必要なコードを加えましょう。とても簡単です。それぞれのscrollbarのValueChangedイベントに、次を入力してください。

 preview.refresh 

これだけです。これはスクロールバーが動かされる度にpreviewへ再描画するよう伝えています。

それでは、previewはどのように描画するのでしょうか?これもまた大変簡単です。プレビューのPaintイベントに行き、次の1行を入力してください。

 g.drawPicture p, -horzScrollBar.value, -vertScrollBar.value 

これはスクロールバーの値によって定められた場所に、画像pを描画しています。それにマイナスを付加しているのに注意してください。もし正ならば、始めの描画ポイントはキャンバスの外側になってしまいます。

分かりやすく言うと、水平スクロールバーの位置が100ならば、それは-100になり、水平方向に-100の位置からpが描画されることを意味します。またそれはpの始めの100ピクセル分を見ることができないことも意味します。それは実際、pのより右側部分を表示するためにpが左側へスクロールされたことを示しています。水平スクロールバーの値がより大きくなれば、それだけ画像が左側へシフトされます。(上下方向が変わるだけで、おなじ理屈が垂直スクロールバーでも成り立ちます。)

最後に、ユーザがボタンをクリックしたときに起こる機能を定義する必要があります。どちらもコードはごく僅かです。CancelButtonのActionイベントは次のようになります。

   gPrintOkay = false 
self.close

PrintButtonのActionイベントはそれと反対になります。

   gPrintOkay = true 
self.close

どちらの場合も、クリックされた時は論理型のgPrintOkayグローバル属性に保存され、ウィンドウは閉じられます。

これで印刷プレビュー・ウィンドウは完成しました。この印刷プレビュー・ウィンドウを他のプログラムで使いたい場合は、ただプロジェクト・ウィンドウからFinderウィンドウへドラッグするだけです。それで他のプロジェクトにもドラッグすることのできるウィンドウ・ファイルが作成されます。

プログラムをテストすることが可能です。それはコンパイルされるでしょう。しかしなぜプログラムが機能しないのか疑問に思っているならば――印刷ボタンをクリックしても何も起こらないじゃないかと――それに対してはとても明白です。これまで印刷メソッドを定義してきましたが、まだそれを呼び出していません!

filePrintメニュー・ハンドラーとprintButtonのActionイベントの両方に行って、次を入力してください。

 printIt 

これは印刷ルーチンを呼び出します。これでプログラムは動くようになるでしょう。

しかしdrawItには何も入力されていないなので、プレビューウィンドウには何も表示されません。今のところは、drawItに次を入力してください。

 g.drawString "This is a test", 100, 100 

これで何か見えるようになるでしょう――どのように見えるか確認するため、他の描画コマンドを加えたりして、自由にいじくり回してください。印刷はスクリーンにただ描画するものだと覚えておいてください。drawlineコマンドを試したり、描画カラーを変えたり、四角や円を描いたりしてみましょう。ここではただ印刷プレビューがどのように見えるか実験しているだけですが、あなたがそこに描画したものはすべて印刷されるでしょう。

今週のチュートリアルの完全なREALbasicプロジェクト(リソースを含む)を手に入れたい場合は、ここからダウンロードしてください。

次週

フォントの描画ルーチンを追加することで、FontPrinterを完成させます。

Letters

今回は、数回前のコラムで公開されたREALbasic Universityの内容に関するレターに対して、いくつかの反応が届いています。

始めに、George Bateさんからです。

Marcさんへ

あなたが以前紹介したGravely氏の手紙で、彼はオブジェクト指向プログラムの構造を理解するために一年半取り組んでいると言っていました。その考え方は、あなたも仰るように理解しがたいものでした。Gravely氏はまるで"スパゲッティ・コード" から一気にオブジェクト指向プログラムに飛躍したように見えます。それは歴史的観点から言えば、およそ1965年から1990年への飛躍になります。それはとうてい無理なことです。たとえ70、80年代の構造化プログラミングを15年もの間学習してきたとしても、私自身はMacAppのようなクラス・ライブラリーのプログラミングをマスターするのに無意味ともいえる数年間を費やしました。とうとう私はそれをあきらめ、手続き指向型のTools Plusに落ち着きました。RealBasicが出たときは、私はとうとうMacアプリケーションのオブジェクト指向プログラムも使えるようになってきたと思いました。

Gravely氏は、私のようなプログラム手法に興味があるただの愛好家とは正反対で、常に結果を求める実務家肌の人です。彼が言うように、手に入る本やチュートリアルが彼にとって無意味である場合、彼はあとどれくらいの努力が必要かを自身に問いかける必要があるでしょう。私は生徒との経験から、プログラム構造の概念に対して元々理解する能力のないと思える人もいることを知っています。Gravely氏はちょうどこのような精神的な障害のある可能性があり、もしそうならば、彼は時間を無駄に費やしていることになるでしょう。

ある私の同僚は、他の生徒からプログラムをコピーしてきた生徒にも少なくともいくらかは成績をあげる必要があるとよく主張していたものでした。これは「誰か他の人にやってもらう」ことは、実際問題として、プログラムを書くためのひとつの道理にかなった方法であるという理由に基づいています。ある人々は病み付きのプログラマーで、いったん問題に突き当たると解決するまでそこから離れられません。おそらくGravely氏もこの可能性を考慮する必要があるでしょう。あるとき突然、彼が納得できるという期待が持てないときは、明らかに彼自身考え直す必要があります。

George Bate

Georgeさん、興味深いお返事です。私が「年を取った犬に新しい芸は仕込めない。」という諺に賛成するかははっきりと分かりません。Gravely氏がプログラミングのある手法に慣れ親しんできたからといって、それとOOPを学ぶことができないということには関係ないからです。つまづいたところに取り組んでいると、思っている以上に時間はどんどん過ぎてしまうので、この場合は実用的な目的から言って、彼はあまりプログラムについて悩みすぎない方が良いかもしれません。しかし私は誰でも学ぶ能力があるものだと信じています。

OOPは重要なテーマだと思うので、ごく近い将来にこれに関するコラムの連載を始めましょう:私は伝統的なプログラミング手法を学んできた人々にも理解できるような方法で、OOPを解説したいと思います。

次に、Scottさんからの手紙です。

Marcさん

私はRBの初心者で、またマガジンの特別購読者です。私はいま第1号を楽しく読まさせていただいていて、必要に応じてコメントを送ろうかと思っています。

私はBen Gravelyさんのレターを読み終えましたが、彼の意見には賛成することができませんでした。私は天文学、アマチュア無線や写真撮影に興味があります。その言うわけなので、私はゲームや、その他最近のプログラミング・サークルで見るようなトピックにはあまり興味がありません。興味があるのは、アルゴリズムの展開についての一連のショートコラムです。それはとても簡単なので、他のコラムでより複雑なもののフォローアップがされると良いかもしれません。また、私はそこからダウンロードできて学習することができる、短いコード集のダウンロード・サイトがあればよいと思います。

私は短い期間で終了するようなプログラムへ移行するというあなたの意見には強く賛成します。初心者にとっては、ひとつのプロジェクトに6ヵ月を費やすのは長すぎるので、もっと短いプログラムにするといいでしょう。私はRBで作成しているたくさんのプラグインやシェアウェア、フリーウェアの開発者がいることを知りました。ちょっとした学習プログラムの助けになるように、そのプログラムのいくつかを参照してみるのはどうでしょう。

私の個人的な願望は、アマチュア無線のコンテスト・プログラムを書くことです。このプログラムは、新しい行が作成されるたびに行番号を埋め込んだり、自動的に時間と日付を入力したり、ある特定のフィールドの写しを表示したり、コンテストのルールで要求されるフォーマットで出力するようなプログラムです。この最後の一文は、少なくとも4つの優れた解説のための例題を示していると思います。

素晴らしいお仕事を続けてください。私はこれからも購読し続けようと思います。

お時間を割いていただき、ありがとうございます。

Scott Clausen

Scottさん、お手紙どうもありがとうございました。もちろん私はいつでもRBUで取り上げるべき具体的な提案を心待ちにしています。あなたのコンテスト・プログラムについても心に留めておこうと思います(もちろんそれを実際に作成するにはもっと詳細な情報が必要です)。

短いコード集について、あなたがそれについて言及されたのは興味深いことです。それは7月に行われたマックワールドのREALbasicのユーザ・ミーティングで話し合われていて、私はそれを行うのにはREALbasic Developerが最適なものだと思いました。それは実際に私がやってみたいことのひとつです。しかし残念ながら、今のところその雑誌の立ち上げに忙殺されています。

ところで、あなたのコメントにあるコーディングについて話を戻しましょう。プログラムの初心者には2つのタイプがあります。ひとつは明確な指示が与えられないとプログラムすることができない"レシピ"プログラマー。もうひとつは、障害を乗り越えるのにわずかの助けだけが必要で、あとは自分のアイデアで乗り切る構想型プログラマーです。

はじめのタイプは、その人の望んでいるものとぴったりのものがチュートリアルにあるうちは幸せです。後者のタイプは、ひとつのレッスンからコンセプトを学び取り、それをまったく違うプロジェクトにも応用する能力があります。後者のタイプの実例を紹介しましょう。

昨年、RBU Pyramidと呼ばれるカードゲームの作成についてを連載しました。私は単なるゲームを取り上げたことについて、いくつかの非難(ほんのちょっとだけですが;-)を受けました(それにあまりにも多くの時間を費やしたことは認めます)。私の考えは、そのゲームには他のコンセプトを教えてくれるたくさんの部分があるということでした。

例えば、そのゲームではスクリーン上に一組のトランプを作成します。それぞれのカードはcanvasオブジェクトで、プログラムが実行される度にコントロール配列としてプログラムにより作成されます。すべてのカードはお互いとてもよく似ているために大きな意味を持ち、プログラムの作成や維持がより簡単になりました。

さてここであなたがまったく違ったプログラムに取り組み始めるとしましょう。たぶんあなたは音楽に興味を持っていて、ピアノの鍵盤プログラムを作成したいと思ったとします。それはまったく同じ方法で作成することができるのです。1つ目のcanvasオブジェクトから始め、コントロール配列としてプログラム的(コードによって)にそれを複製して、ピアノの鍵盤を作ることができます。あなたは数値属性に基づいて音を鳴らすための1つ目のオブジェクトをプログラムするだけです。それでそれぞれの鍵盤が違う音を鳴らすことができるようになるでしょう。簡単です!

しかしあなたが音楽に興味がないとしましょう。しかしあなたは手紙で写真撮影について述べています。それでもし、あなたがオリジナルのiPhotoのようなプログラムを書きたいとしたらどうでしょう?一連のサムネイル画像をスクリーンに表示させたいですよね?それも同じ方法でできます:一連のcanvasオブジェクトを複製し、それぞれのオブジェクトは異なるインポートされた画像を参照するようにします。

これで様子が分かりましたでしょうか?あるプログラムで使う基本的なアイデアの多くは、他のプログラムにも役に立ちます。実際に現在、世界に出ている最も洗練されたソフトウェアの大部分は、"単なる"ゲームから端を発したテクノロジーをもとに作られています。

そのプログラムがあなたの作成したいものでないという理由だけで、あなたがたとえそれに興味が持てないとしても、私はチュートリアルを試しにやってみるようにあなたに言いたかっただけです。今の時点ではそれがどれほど重要か分からないとしても、そこから何かを学ぶことができるでしょう。

私は希望されたすべての種類のプログラムのチュートリアルを作成するためのリソース集を作ろうと思います。おそらくその結果として、すべてをカバーすることのできる教育的な用例集となるでしょう。しかしそれができるまでの当分の間、あなたのできる最善の方策は、ひとつのチュートリアルからできる限りのことを学習し、それを他のプロジェクトへ応用することでしょう。


RBU-Jの通知サービス!コラムが発表されるたびに日本語版REALbasic Universityのお知らせの emailがあなたに届きます。登録・削除は ここ から。

INDEXに戻る