プログラム講座 中級編18

- 簡易マルチウィンドウエディタの作成(その1) -

 中級編18です。今回は「簡易マルチウィンドウエディタの作成(その1)」です。本当は前半と後半に分けて解説しようと思ったのですが、多少長くなりそうなので数回に分ける事にしました。最初の1回目はテキストの入力、カット、コピー、ペースト等クリップボード処理、入力されたテキストファイルの保存と読み込みまで行います。面倒くさそうですが、こういう事は割と手軽に実現できます。Program Generatorでは、もっと高機能かつ簡単に実現できるようです。




◆エディットフィールドについて
 Future BASICには「エディットフィールド」という一般的なテキストの入力を取り扱う命令が用意されています。元々Toolboxに用意されているのですがFuture BASICではスクロールバー等の連携やスタイル付きテキストも標準で取り扱えます。入力されたスタイル付きテキストの保存や読み込みも命令およびサンプルが用意されています。
 エディットフィールドは文字や数値の入力などに使用します。一口にエディットフィールドと言っても指定できるオプションは非常にたくさんあり、ここでは説明しきれません。これらのオプションと種類についてはリファレンスマニュアルの131ページ以降を参照して下さい。

 今回は「簡易エディタ」ですのでエディットフィールドは以下のようになります。
 エディットフィールド内への文字入力は全て自動的に行われますので何も処理する必要はありません。マウスによる選択、ドラッグも全て自動で行われます。とても楽でいいですね。

「それでは、細かい処理はできないのか?」

 細かい処理ができない事はありません。入力されたキーやエディットフィールド内の文字の処理なども行うことが出来ます。ちょっとしたエディタ等を作る場合や、単純に数値を入力したりするだけであれば十分と言えます。ウィンドウにエディットフィールドを貼り付けるだけで「SimpleText」ができると思えば良いでしょう。

 エディットフィールドを生成する命令は以下のようになっています。

EDIT FILED エディットフィールド番号,デフォルト文字列,座標,表示形式,テキスト位置

エディットフィールド番号正数であればスタイルなしテキスト、負数であればスタイル付きテキスト。
デフォルト文字列最初からエディットフィールド内に文字列を入れる。空の場合は""(ダブルクオーテーション)といった具合に指定。最大255文字まで。
座 標エディットフィールドの表示座標を指定。DIM rect.8;のレコード形式または(0,0)-(320,240)といった形式で指定。
表示形式エディットフィールドに枠を表示するか等の指定。
テキスト位置エディットフィード内に表示する文字の位置。

 エディットフィールドのサイズですが、ウィンドウのサイズが変更されたら大きさを変更する必要があります。これはイベント処理になるので、次項で説明します。



◆ウィンドウサイズが変更された場合の処理
 ウィンドウサイズが変更されたらエディットフィールドのサイズも変更しなければなりません。イベントはを受け取る場合はいつものようにON DIALOG FN〜命令を使います。

ON DIALOG FN 処理関数名

 といった具合になります。関数側の処理ですが以下のようになっています。
LOCAL FN doDialog
  events = DIALOG(0)
  eType = DIALOG(events)
  IF eType = _wndSized THEN EDIT FIELD #-1,,(0,0)-(WINDOW(_width)-15,WINDOW(_height)-15)
END FN
 取得したイベントがウィンドウサイズ変更だったら(_wndSized)エディットフィールドのサイズをウィンドウサイズに調整します。ウィンドウの横幅と縦幅を取得するには

縦幅 = WINDOW(_width)
横幅 = WINDOW(_height)

 といったWINDOW関数で取得する事ができます。ウィンドウサイズよりも内側にしてあるのはエディットフィールドスクロール時にスクロールバーまでスクロールしないようにするためです。



◆クリップボード処理と編集メニュー
 今回はクリップボード処理も行います。つまり「カット」「コピー」「ペースト」の処理も加えます。以前お絵かきソフトでグラフィックのコピーをやりましたが、エディットフィールドを使用している限り何も考えることはありません。

EDIT MENU メニュー番号

 と編集メニューを作成すれば自動的に処理してくれるのです。エディットフィールド内へのペースト処理やクリア処理も全て行ってくれます。大変便利ですね。
 ところが、割と使う「全てを選択」というメニューは標準では入っていません。そこで、このメニュー項目を編集メニューにつけ加える必要があります。これは簡単で

MENU 編集メニューのメニュー番号,項目番号,状態,表示文字

 として追加するだけです。ただし、処理は当然自前で行わなければなりません。幸いFuture BASICには、エディットフィールド内の文字を選択するための命令SETSELECTがあります。この命令の書式は以下のようになっています。

SETSELECT 選択開始文字位置,選択終了文字位置

 ところで入力されている文字の数が分からないと選択終了文字位置の指定ができません。実はこれも簡単な方法があって最大文字数(32767)を設定すれば自動的に判断して全てのテキストを選択してくれます。つまり

SETSELECT 0,32767

 とすると全て選択してくれます。
 これで編集メニューの処理は完了です(^^)



◆ファイルの保存と読み込み
 エディットフィールドの保存と読み込みについては専用の命令が用意されています。

READ FIELD ファイル番号,ハンドルハンドルにテキストを読み込む
WRITE FILED ファイル番号,ハンドルハンドルの内容をファイルに書き出す
GET FIELD ハンドル,フィールド番号エディットフィールドのハンドルを取得する

 これらを使ったエディットフィールドの保存、読み込みに関してはハンドブックの136ページにサンプルがあります。今回はこのサンプルを流用しました。
 実際に保存してテキストとして開いてみると、なんか意味不明な文字列が表示される場合があります。これは標準のテキスト形式ではないためです。エディットフィールドで保存されるのはZTXTというフォーマットで以下のようになっています。

0〜1バイト以下に続く文字列の総数。スタイル情報は含みません。
2バイト〜テキストデータ
nバイト〜スタイル情報(n = テキストサイズ+2)

 他のテキストエディタ等で読み込むためには、スタイル情報は削除して保存しなければなりません。となるとマニュアルから流用しただけでは駄目だという事がわかります。これに付いては次回解説したいと思います。HTML形式でも保存できるようにもしたいと考えています。これは3回目で追加する予定です。



◆終わりに
 とりあえず最低限のテキストエディタはできました。次回は拡張してマルチウィンドウエディタを作成します。マルチウィンドウにすると言っても、あまり複雑になるわけではありません。余裕があればHTML保存や縦書き保存なども考えていますが、先行きは不透明ですf(^^;



◆今回のプログラムリスト
' ' "簡易テキストエディタ" ' OUTPUT FILE "fbEdit" ' "----------------------- 定数の定義 ----------------------" _fileMenu = 1 _editMenu = 2 _quit = 4 _openText = 1 _saveText = 2 _selectAll = 8 gQuit_flag = _false: ' "プログラム終了フラグ" ' "------------------ グローバル変数の定義 -----------------" END GLOBALS '-------------------------------------------------------- ' "テキストを開く" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN openText filename$ = FILES$(_fOpen,"ZTXT",,volRefNum%) LONG IF filename$<>"" OPEN "I",#1,filename$,,volRefNum% READ FIELD #1,efHandle& EDIT FIELD #1,&efHandle& CLOSE #1 KILL FIELD efHandle& END IF END FN '-------------------------------------------------------- ' "テキストを保存する" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN saveText filename$ = FILES$(_fSave,"保存ファイル名:",".txt",volRefNum%) LONG IF filename$<>"" DEF OPEN "ZTXTztxt" OPEN "O",#1,filename$,,volRefNum% GET FIELD efHandle&,#1 WRITE FIELD #1,efHandle& CLOSE #1 KILL FIELD efHandle& END IF END FN '-------------------------------------------------------- ' "テキストを選択する" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN selectText SETSELECT 0,32767 END FN '-------------------------------------------------------- ' "ウィンドウを構築する" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN initWindow WINDOW #1,"FB-EDIT",(0,0)-(480,360),_doc EDIT FIELD #-1,"",(0,0)-(480-15,360-15),_noFramed SCROLL BUTTON #-1,1,1,1,32,,_scrollVert END FN '-------------------------------------------------------- ' "メニューを構築する" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN initMenu '"ファイルメニュー" MENU _fileMenu,0,_enable,"ファイル" MENU _fileMenu,_openText,_enable,"/O開く..." MENU _fileMenu,_saveText,_enable,"/S保存..." MENU _fileMenu,_quit-1,_enable,";" MENU _fileMenu,_quit,_enable,"/Q終 了" ' "編集メニュー" EDIT MENU _editMenu MENU _editMenu,_selectAll-1,_disable,";" MENU _editMenu,_selectAll,_enable,"/A全てを選択" END FN '--------------------------------------------- ' "メニューの選択" '--------------------------------------------- CLEAR LOCAL LOCAL FN doMenus menuID = MENU(_menuID): '"選択されたメニューバー項目の番号" itemID = MENU(_itemID): '"プルダウンメニューで選択された項目番号" SELECT menuID CASE _fileMenu : ' "ファイルメニュー" SELECT itemID CASE _openText: ' "開く" FN openText CASE _saveText: ' "保存" FN saveText CASE _quit: ' "終了が選択された" gQuit_flag = _true END SELECT CASE _editMenu: ' "編集メニュー" SELECT itemID CASE _selectAll: FN selectText END SELECT END SELECT MENU: ' "これがないとメニューバーの項目が強調表示されたままになってしまいます" END FN '-------------------------------------------------------- ' "イベントの処理(ウィンドウリサイズの時だけ処理します)" '-------------------------------------------------------- LOCAL FN doDialog events = DIALOG(0) eType = DIALOG(events) IF eType = _wndSized THEN EDIT FIELD #-1,,(0,0)-(WINDOW(_width)-15,WINDOW(_height)-15) END FN WINDOW OFF ON MENU FN doMenus: '"メニューが選択された時の飛び先" ON DIALOG FN doDialog FN initMenu: '"メニューの初期化" FN initWindow DO HANDLEEVENTS: ' "イベント処理は自動で行ってくれます" UNTIL gQuit_flag