RealBasic University

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

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

FontPrinter:パート 5

前回のレッスンでは、印刷プレビュー機能を追加しました。しかし現在の段階では、FontPrinterはフォント・リストの印刷という目的としていた機能を果たしていません。今回は、描画ルーチンを仕上げることによってプログラムを完成させましょう。

印刷画像を書き出す

FontPrinterの核となる部分は、実際の描画を実行するdrawItルーチンです。これはいくらか複雑なルーチンなので、注意深く目を通していくことにしましょう。

まず始めに、われわれが何をしたいのか考えましょう。われわれの目的は、"入力できる"すべてのフォントを表示することです。よって、それには通常のキーボード入力で表示される文字(修飾キーなし)と、シフトキーを押した場合、オプションキーを押した場合、そしてシフトオプションキーの両方を押した場合についての文字を表示する必要があります。それは同じキーを4通りの異なった方法で入力することなので、それにふさわしい表示方法は、それぞれの文字に対応した4つの列を設けることでしょう。

さて、ユーザは記号フォント(文字ではなく絵フォント)を印刷すると考えられるので、まず通常のフォントを使って"普通"(修飾キーなし)の文字を表示することから始めなければなりません。私はHelveticaを選びましたが、どんなフォントを使っても構いません(理想としては、どのMacにもインストールされているフォントがよいでしょう)。私の思いついた方法は、まず小さな通常の文字を括弧でくくり、それからその右側に、ユーザの指定したフォントを大きな文字で表示します。

ここで私は他の問題に突き当たりました。一ページに収まるようにすべての文字を表示させようとすると、その行間にはダブルスペースをとることができません。お互いの文字がとても近寄って、大きな文字はお互いに重なり合ってしまいます。私はとっさに、大きな文字は交互にずらして表示するというシンプルな方法を思い浮かびました。大きな文字をその真上に表示しないので、お互いの文字の間には隙間があります。しかしまだすべての文字を一ページに収めて表示するには、行間全体がまだきつい感じがします。

ユニコードの問題

さてMac OS 9の時代に書き上げたこのプログラムのオリジナルバージョンでは、私はテキスト変換については悩む必要がありませんでした。私が特定のアスキー番号を指定すれば、そのフォントが表示されました(すなわちchr(65)はHelveticaフォントでは大文字の"A"を、Zapf Dingbatsフォントでは六角星型になります)。しかしMac OS Xはもっと洗練されています。フォント表示に関して実際に賢くなっていて、Zapf Dingbatsで大文字の"A"を指定すると、Zapf Dingbatsではなくて大文字のAを持っているデフォルトのフォントで大文字のAを出力してしまいます。それはMac OS XがZapf Dingbatsは大文字のAがないということをすでに知っていて、さらにASCII(65)は大文字のAに当たることから、Mac OS Xは私の欲しいフォントは大文字のAなのだと決め込んでしまうことに原因があります。Mac OS Xのやり方は、ユニコードを使用して希望する実際の文字を特定します。

詳細

ユニコードにまだ慣れていない場合は、TidBITSよくできた手引を書いています (パート2はここから利用できます)。

手短に言うと、ユニコードとはユーザが入力(どんな言語でも)しそうなあらゆる文字について、ある固有番号へ対応付けをしている新しい国際的なマルチ・プラットフォーム規格です。これは、ASCII(65)があるフォント、あるいはあるプラットフォームで対応しているものが、他のフォントやプラットフォームではまったく違うものになってしまうという現行のシステムよりもはるかに優れています。ユニコードでは、あなたの表示したい特定の文字を指定すると、それがあなたの手にするものとなります。

あいにくにも、ユニコードの現況は、アップルがシリアルからUSBに切り替えたときに当たる数年前の状況に似ています。要するに、現在はすべてのプログラム(Mac OS Xでさえも)がユニコードに対応しているというわけでなく、その対応状況はプログラムごとによっても異なっています。そしてMac OS Xでさえも、ユニコードへのサポートが完全になされていない部分があります。そして明らかなことですが、多くの人々がまだユニコードをサポートしていないMac OS 9を使用しています。

したがってわれわれは現在、ユニコードとユニコードでない部分が入り混じった中間の世界に住んでいて、その移り変わりは混乱を伴い、厄介なことでもあります。結果的に、ユニコードの普及はFontPrinterを役に立たない陳腐なものにしてしまうでしょう:結局のところFontPrinterの醍醐味はさまざまなフォントでさまざまな文字を入力するのに必要なキーボード配列を表示することですが、Mac OS Xはわれわれが入力している文字を、入力時に指定した特別な文字ではなくて、入力したまま出力することでその機能を無効にしてしまいます。それは奇妙なもので、例えばMac OS XのTextEditで、Zapf Dingbatsの六角星型(Shift-A)を入力してみてください。入力できないでしょう!Mac OS Xがそれを入力させてはくれません。たとえあなたがフォントをZapf Dingbatsに変更しても、表示される文字は次のようなデフォルト(通常)のフォントになります。

だからFontPrinterに記載されたキーボードのショートカットは、Mac OS Xのユニコード対応のアプリケーションでは無意味となってしまいます。(これはあるCarbonアプリと、すべてのClassicではまだ使えます。)

ユニコードをどのように入力するかについては、このコラムの範疇を超えています。ただこれまでと同じように簡単なものでないということだけ言っておきましょう。後ほど改善されてくると思うので、今は我慢してください。個人的には、このフォントを自動的に変更するMac OS Xの機能はそれほど気になりません。私は古いやり方に慣れていて、考えがそこから抜け出すことができません。しかしながら、ユニコードは当然これから普及してくるものなので、結局私はそれを学ぶことになることでしょう。

われわれの問題点は、Mac OS Xのユニコード対応が、普段使われないフォントでは記号文字を表示させてくれないということです。ここでわれわれがしたいことは、以前のやり方へ戻ることです。要するに、現在のフォントで表示をさせ、Mac OS Xの自動フォント置き換え機能によって無効にされないようにすることです。

言い換えれば、ユーザがフォントとしてZapf Dingbatsを選択したときに何も処置しなければ、プログラムはASCII(65)に対応する六角星型の記号を表示しません。代わりに、それが置き換えられた文字として大文字のAを表示するでしょう。それは望むところではありません。

(鋭い読者はRBU Pyramidの製作中にこの問題に突き当たったことを覚えているかもしれません。われわれは当初、トランプの組の記号を描くために記号フォントを使用しました。しかし、われわれが通常の文字を表示させたいのだと勘違いしてMac OS Xがその記号を表示させてくれなかったので、後になってそのルーチンをインポートした画像を使用するように書き直さなければなりませんでした。)

幸いにも、REALbasicはこの問題を解決するためのツールを提供してくれます。REALbasicはユニコード(またその他のエンコーディング)に対応し、ある1つのものから別のものへ変換することができます。その基本的な原理は次のようになっています:まずあなたが何から(入力コード)変換したいのか、そしてそれを何へ(出力コード)変換したいのかをREALbasicに伝え、それからそれをテキストに変換するように伝えます。原理的にはとても簡単なものです。しかしながら、実際にはREALbasicのオブジェクト指向によるアプローチは、これを少しだけ分かりづらくしています。

オブジェクト指向プログラミングでは、オブジェクトが自身をどのように扱えばよいかを知っているということを覚えておいてください。それが全てのアイデアです。だから次のような手続き型のアプローチ

 newText = convertText(oldText, inputEncoding, outputEncoding) 

ではなく、次のように2つのステップを踏まなければなりません。

 converter = getTextConverter(inputEncoding, outputEncoding) 
newText = converter.convert(oldText)

一度これと同じようなものを目にすれば、これはそれほど難しくありません。しかしここで、inputEncodingとoutputEncodingオブジェクトを入手する必要があります。これは次のようなgetFontTextEncodingコマンドで入手することができます。

 inputEncoding = getFontTextEncoding("Zapf Dingbats") 
outputEncoding = getFontTextEncoding("Zapf Dingbats")

ここでは、REALbasicに入力と出力のフォントの両方ともZapf Dingbatsだと伝えています。すなわち、われわれは自動置き換え機能なしでZapf Dingbatsを使いたいのです。いったんテキスト(前の僅かなコード)を変換すれば、REALbasicはわれわれの記号がZapf Dingbatのものだと確認します。

このすべての結果として、次の2つのオブジェクトがあります。それはテキスト・エンコーディング・オブジェクト(特定のエンコーディング・タイプについての情報を含んでいます)とテキスト・コンバータ・オブジェクト(実際に変換を行います)です。それ程というわけではありませんが、組み込みのマニュアル(レファレンス)からこれを理解しようとするのは容易ではありません(GetFontTextEncoding関数を使って避けようとしている全てのコードタイプについて学習するとは言うまでもなく困難です)。

またREALbasicのバージョンによって、これがどのように機能するかにも違いがあります。上記のコードはREALbasic 4.5で機能するもので、REALbasic 4では少し異なって作動し、それより以前のREALbasicのバージョンではユニコードのサポートが不完全です。確実で一番よい方法は、REALbasicの最新バージョンを使用して、あなたが期待したことが実際に起こったかどうかを確認するために、コードを隈なくテストすることです。

DrawItのコード

解説はこの辺にしてdrawItのコードに目を通して、あなたが理解しているかを確認してみましょう。

   dim i, j, x, y as integer 
dim c, s as string
dim tcon as textConverter
dim t as textEncoding

const defaultFont = "Helvetica"

t = getFontTextEncoding(fontPopup.text)
tcon = getTextConverter(t, t)

g.textFont = defaultFont
g.textSize = 18
g.bold = true
g.drawString "Font: " + fontPopup.text, 72, 26

x = 72 // left margin
for i = 1 to 4
y = 48 // top margin
select case i
case 1
s = "Normal"
case 2
s = "Shift"
case 3
s = "Option"
case 4
s = "Shift-Option"
end select

g.textFont = defaultFont
g.textSize = 14
g.bold = true
g.drawString s, x, y

for j = 1 to len(gTheString(i))
y = y + 14
c = mid(gTheString(i), j, 1)

g.textFont = defaultFont
g.textSize = 10
g.bold = false

g.drawString "(", x, y
g.drawString c, x + 16, y
g.drawString ")", x + 32, y

if j / 2 = j \ 2 then
g.foreColor = rgb(230, 230, 230) // gray
g.fillRect(x, y, 117, 14)
g.foreColor = rgb(0, 0, 0) // black
end if

g.textFont = fontPopup.text
g.textSize = 24
g.bold = false

if tcon <> nil then
c = tcon.convert(c)
end if
if j / 2 = j \ 2 then
g.drawString c, x + 48 + 36, y
else
g.drawString c, x + 48, y
end if
next // j
x = x + 117 // a fourth of the width
next // i  

いつものように、メソッドで使用する変数(属性)を定義することから始めます。気づくと思いますが、ここにはtcon as textConvertert as textEncodingという見なれないオブジェクトがあります。これらは、適切な記号で確実に出力するため、テキストを変換して、適切な記号を出力するために必要になります。

次に、ローカルな定数を定義していることに気がつくでしょう。これは入力文字を表示するために使用する"ノーマル"(記号でない)フォントの名前です。私はHelveticaを選びましたが、Arial、Monaco、System、その他何でもご自由に使用してください。

ちょうど始めのところで、getFontTextEncoding関数にわれわれが使用するフォントの名前(fontPopupのテキスト)を渡すことで、textEncodingオブジェクトtに適切にエンコードを設定しました。それから、textConverterオブジェクト、tconを作成します。これまでのところはまだ何もコンバートしていないことに注意してください。ここで行ったことは全て前準備です。

さてそれでは描画するための準備は整いました。まずページの上部に大きな文字で書くフォントの名前を描画することから始めます。われわれはユーザの選んだフォントではなく、デフォルトのフォントでそれを描画したので、それが読みやすいことは間違いないでしょう。

そこでループを設定します。表示するものは4列あるので、4回のループが必要です。ループの各ステップでは、列のラベル毎に違うテキストを割り当てます。そのラベルは各列の一番上に表示されます。

ところで2回ほど前のレッスンで、FontPrinterのリソース・フォークにあるTEXTリソースからのテキストをgTheString配列に割り当てるためのルーチンを作成しました。そのメソッドはinitと呼ばれています。もう一度確認してみたいならばそれはglobalsModuleの中にあります。gTheStringの各インデックスは、様々な修飾キー(Shift、Option等)と押すか、押さずにタイプして得られる異なる文字セットを含んでいます。だからiループの各ステップでは、gTheStringの異なるインデックスを使用します。

文字は一文字ごとに描画していくので、gTheStringの中の各文字ごとに進んでいく必要があります。それはもうひとつのjループで行います。各文字については、まず始めに括弧で囲まれた標準の文字(defaultFontを使用して)を描画します。各文字の後は、xの値だけ前にすすめることに注意してください。(xyは現在描画している座標のカーソル点です。xは水平方向でyは垂直方向の座標を示します。)

それからif j / 2 = j \ 2 thenという興味深いコードがあるでしょう。これは何を意味しているのでしょうか?もちろん、演算子/は割り算です。それでは演算子\はなんでしょうか。それは分数はなく、常に整数を返すことを意味する整数割算を行います。それぞれ2で割られた2つの演算を比較することで、jが奇数か偶数かを簡単に判別することができます。仮にjが5のような奇数であれば、2つの演算は等しくなりません(5/2は2.5で、5\2は2だからです)。したがってこのif文のあとのコードは、jが偶数の時にだけ実行されます!

ではそのコードは何をするのでしょうか?それは横方向の灰色の四角形を描画します。その四角形はテキストの一行分と同じ高さで、また列と同じ横幅を持ちます。ただそれだけです。この効果は、テキストの一行おきに水平方向に淡い灰色の四角形を置くことで、文字のマス目をより読みやすくするものです(この記事の最後にあるサンプル画像を見てください)。

次に、ユーザが選択したフォントで大きな文字を描画する準備を整えます。フォントとフォントのサイズを設定し、それからテキストを適切なエンコーディングへ変換してみます。私は「試してみる」と言いました。なぜならば、REALbasic 4.5ではそれは有効なオブジェクトなのに、REALbasic 4のtconは常にnil(getTextConvertコマンドはtconオブジェクトの生成に失敗しています)に等しいことが分かったからです。4と4.5の間では、明らかにどのようにテキストのエンコーディングに違いがあります。しかしREALbasic 4では、4.5で起こるようなフォントの置き換え問題はありませんので、ここでしなければならないことは、仮にtconが適切なオブジェクトであればテキストを変換するだけです。RB 4(あるいはtconオブジェクトが存在しないときには)では、プログラムは変換をしないでテキストをそのまま使用します。

最後は、大きなフォントで文字を実際に描画するコードです。偶数行では文字を右側へ36ポイントずらして段差違いにしていることに注意してください。仮にそれが一行分の高さよりも大きいとしても、その上下方向には十分なスペースがあるので、問題はありません。

最後の行では、xに114(1列分の幅)を加えます。iのループの開始点では、yは上部の余白分である48にリセットされるのが分かりますね。これはカーソルを1つ右側の列に移動し、次の列を描画するための準備としてページの上部に戻るためのものです。

隣の列に移動したあともループ内ではすべてのプロセスが繰り返されますが、毎回違った文字セットが使用されます(4つのgTheString要素のそれぞれです)。

終了です!これでFontPrinterが完成して、動作するでしょう。プレビュー・ウィンドウは次のようになるでしょう(Zapf Dingbats使用の場合):

プリントボタンを押せば、プリンターにこれと同じページが印刷されるでしょう。

いろいろと楽しんでみてください。これがあなたの役に立ったチュートリアルであることを望みます。これを自由に改良してみてください。印刷プレビューを複数ページに対応させたり、FontPrinterがすべてのインストールされたフォント・ページを印刷するような機能を付け加えたりすることもできるでしょう。あなたがどのようにこのプログラムを改良したのかお知らせください。

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

次週

REALbasic 4.5のミニ・レビューを行います。〔訳注:rbu-jではミニ・レビューは省略し、次回はレッスン71:DoRbScriptになります〕

Letters

今週のお手紙はFontPrinterをMac OS X 10.2で使用したときに問題になる可能性について、ちょっとした情報を提供してくれたPaulさんからです。

こんにちはMarcさん、簡単なeメールですが…

10.2は8ビットの画像を好みません。私はこの情報をRBのメーリングリストで発見しました。

私がFontPrinterのアプリケーションを試したときに、'this is a test'と表示されるはずのプレビュー・ウィンドウが表示されませんでした。printInitメソッドで画像を16ビットに変更することで、この問題は解消されます。

この問題をあなたに知らせておくべきだと思いました!またすばらしい内容のRBDの創刊号もありがとうございます!!

コラムについての提案ですか?いくつかの理解しやすい印刷チュートリアルとその例題集があれがよいと思います!

それでは。 Paulより

Paulさん、情報どうもありがとうございました!悲しいことに、まだ私はJaguarを手に入れていません。私はそれを先行予約で申し込んだのですが、まだ届いていません。私はどうしてJaguarが8ビット画像を好まないのか理由がよく分かりませんが、それを知っておくのはよいことです。私はメモリーの消費を少なくするという理由だけで8ビットを選びましたが、Mac OS Xではどちらにしてもその問題はありません。

変更する一行はprintItメソッドの中にあります。古い行では、

 p = newPicture(thePrinter.pageWidth, thePrinter.pageHeight, 8) 

そして新しい行は次のようになります。

 p = newPicture(thePrinter.pageWidth, thePrinter.pageHeight, 16) 

これでうまく動くようになるでしょう。


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

INDEXに戻る