プログラム講座 中級編19

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

 中級編19です。今回は「簡易マルチウィンドウエディタの作成(その2)」です。今回は「マルチウィンドウ」への対応と「イベント処理」そして「テキスト形式での保存」を行います。




◆マルチウィンドウへの対応
 マルチウィンドウ対応にしようとすると何か難しい事をしないといけないような気もしますが実際は異なるウィンドウ番号でウィンドウを開いてオープンするだけです。エディットフィールドの変更や保存、読み込みはカレントウィンドウのエディットフィールドに対して行われるため、わざわざ調べて難しい処理を行う必要はありません。
 今回はオープンされたファイル名をウィンドウのタイトルにします。次回の追加処理でウィンドウメニュー構築用にtheName$という配列を用意しています(今回は使用しません)。ウィンドウがオープンされているかどうかを示すフラグ用の配列としてtheWindowを用意しています。theWindowは_trueでウィンドウが有る、_falseでウィンドウがない、という意味になっています。これはテキストファイルが新しくオープンされた場合、ウィンドウの空いている番号を探し出すために使用しています。
 エディットフィールドのID番号ですが、これは同じウィンドウ内で同じIDがなければ良いだけです。つまり複数ウィンドウを開いていても他のウィンドウのエディットフィールド番号を気にする必要はありません。
 次回のメニュー処理のためにwindowTotalという変数を用意しています。これはファイルメニューで「閉じる...」「保存する」といったメニュー項目を有効/無効にするためのものです。今回は使用していません。



◆イベント処理
 ウィンドウが複数ある場合「タイトルバーがクリックされた場合のみ」ウィンドウを自動的にアクティブにしてくれます。逆に言うとウィンドウの中身の部分をクリックした場合、自動的にクリックされたウィンドウはアクティブになりません。つまり、このイベント処理は自前で行う必要があります。同様にクローズボックスがクリックされた場合でもFuture BASICは自動的にウィンドウを閉じてくれません。これらはイベントタイプからクリックされたウィンドウ番号を割り出して処理しなければなりません。
 まず以下の命令で「イベントタイプ」を取得します。

events = DIALOG(0)

 このイベントタイプが「ウィンドウ内がクリックされた(_wndClick)」「クローズボックスがクリックされた(_wndClose)」場合に処理を行います。これらのイベントが発生した場合、クリックされたウィンドウ番号を求めなければなりません。クリックされたウィンドウ番号を求めるには以下のようになります。

eType = DIALOG(events)

 このeTypeに「ウィンドウ番号」が返ってきます。後はWINDOW(eType)としてウィンドウをアクティブにすればできあがりです。



◆テキスト形式での保存
 前回はZTXTというエディットフィールドの読み書き専用のデータ形式を使用していました。これでは他のテキストエディタで読み込めない、もしくは読み込むとスタイルデータ部分まで表示されてしまいます。そこで、テキスト部分のみファイルに書き出すことにします。
 幸いエディットフィールドの格納形式ZTXTについてはデータ形式がわかっていますので(中級編18を参照)、そのデータに従ってファイルに書き出します。WRITE FILEDを使っていた部分をWRITE FILEにし、テキストデータ分だけ書き出します。実際のプログラムは以下のようになっています。
CLEAR LOCAL
LOCAL FN saveTextFile
  filename$ = FILES$(_fSave,"保存ファイル名:",".txt",volRefNum%)
  LONG IF filename$<>""
    DEF OPEN "TEXTttxt"
    OPEN "O",#1,filename$,,volRefNum%
    GET FIELD efHandle&,#1
    err% = FN HLOCK(efHandle&):                   ' "ハンドルをロック"
    textSize& = PEEK WORD([efHandle&]):           ' "先頭2バイトがテキストサイズ"
    WRITE FILE #1,[efHandle&]+2,textSize&:        ' "データ保存"
    CLOSE #1
    KILL FIELD efHandle&:                         ' "ハンドルを破棄"
    wNum = WINDOW(_activeWnd):                    ' "アクティブウィンドウの番号を調べる"
    WINDOW wNum,filename$
  END IF
END FN
 太字になっている所がポイントです。まずエディットフィールドのハンドルをロックします。次に先頭2バイトに格納されているテキストサイズを読み出します。読みだしたテキストサイズ分だけファイルに書き出します。



◆ウィンドウタイトルの変更
 ファイルが保存されたらウィンドウのタイトルバーの部分の名前を変更する必要があります。異なる名前で保存したのに以前と同じ名前ではちょっと違和感があります。
 すでに存在するウィンドウのタイトル文字列を再設定するにはWINDOW命令を使用します。ウィンドウをオープンする時と同様の指定方法で、タイトル文字列を変更する事ができます。つまり

WINDOW ウィンドウ番号,文字列

 といった具合になります。



◆終わりに
 実はテキスト形式のファイルが読めないという、笑えないオチがまだ残っています。次回はメニューの処理とウィンドウの枚数に応じて自動的に変化するメニュー、HTML形式での保存について解説します。



◆今回のプログラムリスト
' ' "簡易テキストエディタ" ' OUTPUT FILE "fbEdit" ' "----------------------- 定数の定義 ----------------------" _maxWindows = 33: ' "32枚までウィンドウを開くことが出来ます(33-1)" _fileMenu = 1 _editMenu = 2 _openText = 1 _closeText = 2 _saveText = 4: ' "ZTXT形式で保存" _saveTextFile = 5: ' "TEXT形式で保存" _quit = 7: ' "終了メニュー" _selectAll = 8: ' "「全てを選択」のメニュー項目番号" gQuit_flag = _false: ' "プログラム終了フラグ" ' "------------------ グローバル変数の定義 -----------------" DIM theWindow(_maxWindows): ' "ウィンドウの有無を示す配列(_trueであり、_falseでなし)" DIM theName$(_maxWindows): ' "ウィンドウ名" windowTotal = 0: ' "開いているウィンドウの総数" END GLOBALS '-------------------------------------------------------- ' "空いているウィンドウを探して空いている場合は、" ' "新しくウィンドウをオープンし登録する" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN newWindows(wnd$) flag = _false FOR i=1 TO _maxWindows LONG IF theWindow(i) = _false flag = _true theWindow(i) = _true: ' "ウィンドウがあることを示すフラグをオンにする" theName$(i) = wnd$: ' "ウィンドウリストに名前を追加" WINDOW #i,wnd$,(0,0)-(480,360),_doc EDIT FIELD #-1,"",(0,0)-(480-15,360-15),_noFramed SCROLL BUTTON #-1,1,1,1,32,,_scrollVert windowTotal = windowTotal + 1 i = 999 END IF NEXT END FN = flag '-------------------------------------------------------- ' "カレントウィンドウをクローズする。自動的にエディットフィールドもクローズされます" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN closeWindow wNum = WINDOW(_activeWnd): ' "アクティブウィンドウの番号を調べる" LONG IF wNum <> 0 WINDOW CLOSE wNum: ' "ウィンドウをクローズします" theWindow(wNum) = _false: ' "ウィンドウの存在を消します" theName$(wNum) = "": ' "ウィンドウ名を空にします" END IF END FN '-------------------------------------------------------- ' "テキストを開く(ZTXT形式のみ)" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN openWindow filename$ = FILES$(_fOpen,"ZTXT",,volRefNum%) LONG IF filename$<>"" flag = FN newWindows(filename$): ' "ウィンドウが、開けるかどうか調べる" LONG IF flag OPEN "I",#1,filename$,,volRefNum% READ FIELD #1,efHandle&: ' "フィールド内にテキストを読み込む" EDIT FIELD #1,&efHandle&: ' "エディットフィールドに設定" CLOSE #1 KILL FIELD efHandle&: ' "ハンドルを破棄" END IF END IF END FN '-------------------------------------------------------- ' "テキスト形式で保存する" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN saveTextFile filename$ = FILES$(_fSave,"保存ファイル名:",".txt",volRefNum%) LONG IF filename$<>"" DEF OPEN "TEXTttxt" OPEN "O",#1,filename$,,volRefNum% GET FIELD efHandle&,#1 err% = FN HLOCK(efHandle&): ' "ハンドルをロック" textSize& = PEEK WORD([efHandle&]): ' "先頭2バイトがテキストサイズ" WRITE FILE #1,[efHandle&]+2,textSize&: ' "データ保存" CLOSE #1 KILL FIELD efHandle&: ' "ハンドルを破棄" wNum = WINDOW(_activeWnd): ' "アクティブウィンドウの番号を調べる" WINDOW wNum,filename$ END IF END FN '-------------------------------------------------------- ' "テキストを保存する" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN saveText filename$ = FILES$(_fSave,"保存ファイル名:",".ztxt",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& wNum = WINDOW(_activeWnd): ' "アクティブウィンドウの番号を調べる" WINDOW wNum,filename$ END IF END FN '-------------------------------------------------------- ' "テキストを選択する" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN selectText SETSELECT 0,32767 END FN '-------------------------------------------------------- ' "メニューを構築する" '-------------------------------------------------------- CLEAR LOCAL LOCAL FN initMenu '"ファイルメニュー" MENU _fileMenu,0,_enable,"ファイル" MENU _fileMenu,_openText,_enable,"/O開く..." MENU _fileMenu,_closeText,_enable,"/W閉じる" MENU _fileMenu,_closeText+1,_enable,";" MENU _fileMenu,_saveText,_enable,"/S保存..." MENU _fileMenu,_saveTextFile,_enable,"/TTEXT形式で保存..." 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 openWindow CASE _closeText: ' "閉じる" FN closeWindow CASE _saveText: ' "保存" FN saveText CASE _saveTextFile: ' "TEXT形式で保存" FN saveTextFile 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) IF events = _wndClick THEN WINDOW(eType): ' "ウィンドウをアクティブにする" IF events = _wndClose THEN WINDOW(eType):FN closeWindow:' "ウィンドウを閉じる" END FN WINDOW OFF ON MENU FN doMenus: '"メニューが選択された時の飛び先" ON DIALOG FN doDialog FN initMenu: '"メニューの初期化" DO HANDLEEVENTS: ' "イベント処理は自動で行ってくれます" UNTIL gQuit_flag