Luaレッスン21「(3.2)テキスト・ボックスとリッチ・テキスト入力」和訳

出典:http://compasstech.com.au/TNS_Authoring/Scripting/script_tut21.html

レッスン21(「3.2)テキスト・ボックスとリッチ・テキスト入力」

TI-NspireのOS 3.2では、非常に強力で大変便利なツールがいくつか登場しました。中でも重要なのは、Luaスクリプト・エディターの組み込まれたことです。Luaスクリプト・エディターは、[Insert]メニューの一番下に現れます。これでようやく、Luaスクリプトが使いたい誰もがLuaスクリプトを利用できるようになりました。[Insert]メニューを使ってNspireウィンドウにスクリプトを挿入することもできるし、既存のスクリプトを編集することもできます。Script Editorは、TI-Nspireのエミュレーターでは利用できますが、ハンドヘルドでは利用できません。ですから、生徒は自分のハンドヘルドではスクリプトにアクセスできません。しかし自宅のStudentソフトウェアではもちろんスクリプトへアクセスできます。バージョン3.2の優れた機能のいくつかを学びながら、このエディターについて体験してゆきましょう。

便利な元祖2D EditorでLuaスクリプトの基本に返ってみましょう。最初のいくつかのレッスンはずいぶん昔のことに思えますし、内容を思い出すのに苦労するかもしれませんね。最初の5回のレッスンのメイン・テーマはテキストでした。テキストをページに表示すること、テキストをどこにどのように表示させるかを設定すること、キーボード入力を取り込めるようにすることで生徒が解答をドキュメントに入力できるようにすること、などを学びました。覚えていますか? 

われわれのLua環境には、バージョン3.2まで実際にRichText 2D Editorが含まれていましが、あまり機能的ではありませんでした。しかしようやく実力の発揮できる状況が整い、生徒は、テキストだけでなく、数式や化学式、さらには幾何学記号まで入力できるようになりました。

on.paint函数を使って画面に色を塗ったり、あるいは外観、レイアウトの細部までいちいち設定したりする代わりに(分数などの表現は大変でした)、今や、いわゆるテキスト・ボックスと同じ機能を持ったオブジェクトがページ上のどこにでも作成できるようになりました。テキストを入力して編集することや、文字のサイズなどを変えることができるようになったのです。それどころか、Notesページとまったく同じように、Math Box(またはChem Box)も作成でき、レイアウトや書式も処理してくれるのです。

 特に重要なのは、入力されたどのテキストについても、そのテキストをつかんでさまざまな処理が加えられることです。

 たとえば、テストの解答の成否を判断したり、入力された文字を数式に変換したりといった処理だけでなく、テキストの検索や、検索されたテキストの一部置換などもできます。

 

クイック・スタート

ほんの数行を記述するだけでページにテキスト・ボックスが設置できます。全然難しくありません(高度な内容はのちほど登場します)。現時点では不思議に思えるかもしれませんが、on.paint函数はまったく使う必要がありません。面白いですね! 

 これ以降に紹介するスクリプトはすべて、先頭にAPIレベルが記述されます。OS 3.2の機能(on.constructionなど)を使用するスクリプトは、platform.apilevel = "2.0"として定義されます。これまでに紹介してきたスクリプトAPIレベルが"1.0"でした。OS 3.2の新しい機能を含んだドキュメントはバージョン3.2より古いOSでは開きません。これには良く注意してください。作成したスクリプトがレベル2.0である場合、それよりも古いOSを使っている生徒は、ドキュメントを開くことすらできません。

 まずはウィンドウ変数を設定します。その変数が必要なときに簡単にアクセスできるようにするためです。長くて扱いづらい"platform.window"を"screen"に置き換えていることに注意してください。変数は、極力ローカル変数として定義してください。そのほうが、処理が速いうえに効率的です。

 さあ、マジックを御覧ください。今回は、"TBox"という名前のテキスト・ボックスを定義します。定義するのは1回だけで済みますので、必要なら函数の外側で定義することが可能です。

 残りのコマンドは、ページが開かれたとき、およびページのサイズが変化したときにon.resize函数が呼び出されるようにする手段として、on.resize函数の中に記述します。moveコマンドで、ボックスの左上の初期座標を設定します。resizeコマンドでボックスの寸法を設定します。これだけでテキスト・ボックスが完成します。追加の処理として、ボックスのサイズをページよりも若干小さくしています。その理由は、周囲に余白を設けて読みやすくするためです。

 最後の2行は、点滅するカーソルを設定する行と、ボックスにテキストを記述する行です。簡単ですね。

 platform.apilevel = "2.0"

local screen = platform.window

local w = screen:width()

local h = screen:height()

local TBox = D2Editor.newRichText()

function on.resize()

      w = screen:width()

      h = screen:height()

      TBox:move(0.05*w, 0.05*h) --ボックスの左上座標

      TBox:resize(0.9*w, 0.9*h) --ボックスの幅、高さ

      TBox:setFocus(true)

      TBox:setText("Welcome to Text Boxes!") --ボックスにあらかじめ入力されるテキスト

end

  

f:id:ti-nspire:20141209104416j:plain

  1. テキスト・ボックスを設定する

 もう少し完成度を上げてみましょう。これを避ける簡単な方法はありませんので、コードを示し、それを基に説明します。

 今回は、on.construction、および以前からあるon.resizeを使います。前者は、on.createの代わりとしてバージョン3.2で新たに追加されました。on.createは、実際に呼び出したときに信頼性の劣る傾向があるため、これまでほとんど使いませんでした。このような問題はon.constructionでは起きません。on.constructionは、先頭に記述します。ですから、on.constructionの中には、ページ・サイズの基準値は記述しないでください。この時点で計測すべきページは実際には存在しないからです。しかし、一度だけ実行する必要のある要素は設定できます。今回は、TextBox1という名前の新しいリッチ・テキスト・ボックスを作成してタイマーを起動するだけです。タイマーは、画面を連続してリフレッシュする手段として使います。

 そのあと、普通のon.resize函数を使って、ページ・レイアウトの処理、およびそのページのサイズが変化したときの管理を行います。常として、たとえページのサイズを変更しない場合でも、画面に何か描画される前にon.resizeは一回は呼び出されます。したがって、ページが変化した場合にリフレッシュする必要のある要素を記述する場所としてはon.resizeが適しています。

 ほかに、新たなお気に入りであるon.getFocusも見つけました。この機能は、読んで字のごとくです。つまり、このページに戻ったときに、指定の機能が実行されます。今回は、文字の入力が簡単に始められるようにテキスト・ボックスにフォーカスを戻しています。

 では早速取りかかりましょう。.

 右のコードをコピーし、新規ドキュメントを作成し、スクリプト・ページを挿入してから、Set Script(またはctrl-S)を実行して、何が起きるのか確認してください。下半分にテキスト・ボックスの配置されたページが表示されましたね。何か打ち込んでから、Notesページを新たに挿入してください。MathBoxに「input」と入力してenterを押してください。入力したテキストが表示されるはずです。

 言い換えれば、何が打ち込まれたかを認識できるライブ・テキスト・ボックスが作成されたということです。しかもon.paint函数はまったく使用していません。

 さまざまなコマンドの意味は、文字通りです。これまで20回のレッスンをこなしてきたわけですから、わかるはずです。D2Editor.newRichText()コマンドでテキスト・ボックスを作成し、TextBox1:move(W*0.05, H*0.5)で位置を決め、TextBox1:resize(W*0.9,H*0.4)でサイズを決めています。

 各種のコマンドおよび値をいろいろいじって、その影響を確認してください。on.timer函数のところで本当の魔法が起きていることがわかるでしょう。テキスト・ボックスに何が入力されれようと、その入力された値が取り込まれて変数名が割り当てられているのです。これはパワフルな箇所です。テキスト・ボックスを消去するescapeKey函数も追加しましたので、その動作を確認してください。これは非常に重要なコマンドです。

 

platform.apilevel = "2.0"

local screen = platform.window

local w = screen:width()

local h = screen:height()

local TextBox1

local fontSize

function on.construction()

     timer.start(0.4)

     TextBox1 = D2Editor.newRichText()

end

function on.resize()

     w = screen:width()

     h = screen:height()

     TextBox1:move(w*0.05, h*0.5) --ボックスの左上座標

     TextBox1:resize(w*0.9,h*0.4) --ボックスの幅、高さ

     fontSize = math.floor(w/32)

     fontSize = fontSize > 6 and fontSize or 7

     TextBox1:setFontSize(fontSize)

     TextBox1:setBorderColor(500) --ボックス境界線の色

     TextBox1:setBorder(1) --ボックスの線太さ

     TextBox1:setTextColor(200*200*200)

     TextBox1:setFocus(true)

end

function on.getFocus()

     TextBox1:setFocus()

end

function on.timer()

     cursor.show()

     Input = TextBox1:getExpression()

     if Input then

          var.store("input", Input)

     end

     screen:invalidate()

end

function on.escapeKey()

     TextBox1:setExpression(" ")

     screen:invalidate()

end

 

f:id:ti-nspire:20141209104454j:plain

  1. テキストで遊ぶ

遊んでみましょう。

まずは課題から。もう1つテキスト・ボックスを作成し、図のように上下に配置してください。うまく行かない場合は、サンプル・ファイルのscript_tut21.tnsを参照してください。

まず、うえのテキスト・ボックスに入力した内容が下のテキスト・ボックスに表示されるようにしてみます。

コードをよく見てください。特にon.timer函数に注目してください。必要な作業は、Inputに本当に入力されたかどうかを確認したあとに、TextBox2:setExpression(Input)という行を追加することだけです(getExpressionはgetTextと交換可能です。setExpressionはsetTextと交換可能です)。

では、この行をTextBox2:setExpression("\\1keyword "..Input)に置き換え、どうなるかを確認してください。"\\1keyword"とコマンドは、面白いのでいろいろいじってみてください。このキーワードを入力したあとに入力した文字が太字になりましたね。

このようなテキスト・スタイル・コマンドを使用するときの注意:OSが将来アップデートされたときに、これらのコマンドが変更されない保証はありません。これらのコマンドは、将来的に動作しなくなる可能性があるわけですから、重要な用途での使用は避けたほうが良いでしょう。

ドキュメントに記載されていないこうした素晴らしいコマンドを見つけてくれたのは、Inspired-Luaチームです。TI-NspireでLuaを最大限活用すべく学んでいる我々をサポートしてくれているジェレミーとエイドリアンとに感謝します。

こうした書式設定コマンドには、太字(keyword)やイタリック(subhead)のようなスタイルに関するものだけでなく、幾何学記号もいくつかあります。Notesアプリケーションで利用できるものと同じです。

こうしたコマンドにはさまざまな用途があります。たとえば"circle"という単語を検索して、それを自動的に記号に置き換えることが可能です。

わたくしの作成したサンプル・ファイルは、HTMLの記述スタイルを借用しましたので、用いた特殊コマンドは、その末尾をコロンで示すという方法で定義しています。こうした特殊コマンドが入力されると、それぞれのコマンドに定義されている機能が実行されます。たとえば記号入力(円、三角)、特殊表記(矢印、線)、文字強調などが行われます。TextBox2:setText(pretty(Input))を自分のページにコピー・アンド・ペーストし、先にtimer函数に入力した行を1箇所だけ変更してください。そのあとで、以下のテキストをTextBox 1にコピー・アンド・ペーストして、新たに加わった機能を試してください。

u:Underline can be mixed with b:bold, i:italic, and sup:superscript with sub:subscript . b:Geometry symbols include triangle:ABC, circle:P, rtri:ABC, line line:AB, segment segment:AB and ray ray:AB and vector vector:ABC .

ハンドヘルドの場合は、フォント・サイズを調整しないと、TextBox 1にペースとしたテキストが表示しきれないかもしれません。この処理は、OS 3.2なら簡単に実行できます。しかし2つ目のボックスは、スクロールすることもフォント・サイズを調整することも不可能です。ボックス2は、ボックス1とは違って、いわゆるライブ・ボックスではないからです。ボックス2は、ボックス1に何が入力されたかに依存しますので、最適な表示を実現したい場合は、ページを設定する際にフォント・サイズに気を付けなければなりません。

function pretty(input)

      input = input:gsub("circle:", "\\1circle ")

      input = input:gsub("triangle:", "\\1tri ")

      input = input:gsub("angle:", "\\1angle ")

      input = input:gsub("ray:", "\\1ray ")

      input = input:gsub("line:", '\\1line ')

      input = input:gsub("segment:", "\\1lineseg ")

      input = input:gsub("rtri:", "\\1rtri ")

      input = input:gsub("vector:", "\\1vector ")

      input = input:gsub("u:", "\\1title ")

      input = input:gsub("b:", "\\1keyword ")

      input = input:gsub("sup:", "\\1supersc ")

      input = input:gsub("sub:", "\\1subscrp ")

      input = input:gsub("i:", "\\1subhead ")

      return input

end

 

f:id:ti-nspire:20141209104525j:plain

今回紹介したスクリプトの用途について考えてみましょう。上記のような方法を使うと、キーワードを検索して見つかった場合に点数を与えるという試験問題が簡単に作成できます。それどころか、所定のキーワードが入力されるや太字やイタリック体で強調表示されるようにボックスを設定することができますので、学習者の注意が惹き付けられます。

 次のレッスンでは、引き続き、リッチ・テキスト・ボックスの可能性を探り、ダイナミックな数式ボックスおよび化学式ボックスの作成方法を学びます。