Treeアイテムの編集
次に、アウトラインエディタの処理で重要な、アイテムの編集処理について見ていきましょう。ドラッグ&ドロップによるアイテムの移動は、先ほど見たようにTreeのdragEnabled
、dropEnabled
、dragMoveEnabled
をtrueにするだけで実現できます。
そして、アイテムの追加・削除などは、dataProvider
に指定したXMLを変更することで対応できます。ここで私もしばらく悩んだのが、アイテムの削除でした。XMLクラスには、アイテムを削除するようなメソッドが用意されていません。それではどうするのかと言うと、delete
演算子で要素を削除します。
ただし、delete
演算子は、動的なプロパティのみ削除することができるので、Treeコントロール(index_tree
)の選択されたアイテムを削除しようとしたとき、次のように書くとエラーになってしまいます。
delete index_tree.selectedItem;
そこで、一度、選択されたアイテムの親を取得し、親の子要素を削除するという処理を行います。
private function removeCard():void { var card:XML = index_tree.selectedItem as XML; if (card == null) return; var parent:XML = card.parent(); // 親を取得 if (parent == null) { // ----(*1) 親がない時 var ci:int = index_data.getItemIndex(card); index_data.removeItemAt(ci); index_tree.selectedIndex = index_data.source.children().length(); } else { delete parent.children()[card.childIndex()]; } index_data.refresh(); }
ここで問題になるのが、親が存在しない場合、つまりXMLのトップレベルのノードだった場合の対処です。プログラム中の(*1)からの部分ですが、トップレベルの場合には、これを削除するremoveItemAt
メソッドが用意されています。子要素について、removeItemAt
メソッドを利用することはできません。トップレベルか否かによって削除の方法が変わってくるので注意が必要です。
ダイアログのポップアップ
それから、アウトラインエディタのファイルメニューにある[開く]や[保存]のメニューをクリックすると、ファイル選択ダイアログが表示されるようになっています。これは、PopUpManager
を使うと簡単に実現できます。
ウィンドウのポップアップを行う手順は、次のようになります。
- Flex Builderのメニューから[ファイル]-[新規]-[MXMLコンポーネント]で新規コンポーネントを作る
- コンポーネントのベースを
TitleWindow
に設定して、[終了]をクリック - ウィンドウのデザインを作る
PopUpManager.createPopUp()
メソッドでウィンドウをポップアップする
アウトラインエディタの[出力]メニューをクリックすると、TextAreaを貼り付けただけの簡単なダイアログが表示されますが、これは次のように定義されています。
<?xml version="1.0" encoding="utf-8"?> <mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" width="450" height="360" title="出力"> <mx:VBox width="100%" height="100%"> <mx:TextArea id="out_txt" width="100%" height="100%"/> <mx:HBox width="100%" horizontalAlign="right"
paddingBottom="4" paddingLeft="4"
paddingRight="4" paddingTop="0"> <mx:Button label="コピー" click="copyText()"/> <mx:Button label="閉じる"
click="PopUpManager.removePopUp(this);"/> </mx:HBox> </mx:VBox> <mx:Script> <![CDATA[ import mx.managers.PopUpManager; private function copyText():void { // select all out_txt.setFocus(); out_txt.setSelection(0, out_txt.text.length); // copy System.setClipboard(out_txt.text); } ]]> </mx:Script> </mx:TitleWindow>
このダイアログをモーダルで表示するには、次のように記述します。
var frm:ExportDialog = PopUpManager.createPopUp( this, ExportDialog, true) as ExportDialog; PopUpManager.centerPopUp(frm); frm.out_txt.text = "表示する内容";
ローカル共有オブジェクトへのデータ保存
このアウトラインエディタでは、編集したファイルの内容を、Flash Playerのローカル共有オブジェクト(SharedObject
)に保存するようにしています。これは、ブラウザのクッキーと似た機能なのですが、クッキーには、保存容量の制限があるのに対して、SharedObject
が提供する共有オブジェクトは、ユーザーがアプリケーションごとに任意の保存可能容量を指定することができるようになっています。
共有オブジェクトには、単純な形式のオブジェクトをそのまま保存することができます。以下のプログラムは、ローカル共有オブジェクトにアウトラインエディタのデータを読み書きするクラスSOFiles
からの抜粋です。
public class SOFiles { private static var _instance:SOFiles = null; private var files_so:SharedObject; public function SOFiles(seed:Object) { if (seed == null || seed.getInstance == undefined) { throw Error("Please use getInstance()."); } files_so = SharedObject.getLocal("SOFiles"); // --------- (*1) } public static function save(item:SOFileItem):void { // ------ (*2) var files_so:SharedObject = SOFiles.getInstance().files_so; if (files_so.data.files == undefined) { files_so.data.files = new Object(); } files_so.data.files[item.filename] = item; files_so.data.lastfile = item.filename; files_so.flush(); }
クラスのコンストラクタで、ローカル共有オブジェクトを取得しています(*1)。そして、このオブジェクトにデータを書き込むには、data
プロパティにオブジェクトを代入するだけです。
SOFileItem
は、アウトラインエディタのドキュメントの情報を定義したクラスですが、単純なオブジェクトなら、特別なシリアライズ処理をすることなくデータを保存できるようになっています。
しかし、単純なオブジェクトというのが落とし穴で、オブジェクトのプロパティが別のオブジェクトへの参照だったりすると、うまく保存できません。また、ユーザーが定義したデータを保存した場合に、同じ型での読み込みがうまくいかず、次のようにオブジェクトのプロパティを列挙して、代入する必要がありました。
public static function load(filename:String):SOFileItem { var files_so:SharedObject = SOFiles.getInstance().files_so; if (files_so.data.files == undefined) return null; files_so.data.lastfile = filename; // データの読み込み var o:Object = files_so.data.files[filename]; // ユーザーの定義したクラスのオブジェクトに値を再設定する var res:SOFileItem = new SOFileItem(); for each (var key:String in ['filename','update_date','data']) { res[key] = o[key]; } return res; }
まとめ
本稿では、Flexを利用して、アウトラインエディタを製作する様子を紹介しました。Flexに用意されている高度なコンポーネントを利用することで、Windowsアプリケーションのような複雑なアプリケーションが手軽に作成できることをお分かりいただけたかと思います。
なお、このアウトラインエディタを友人に見せたら、「せっかくWebブラウザで動くんだから、ログインしてユーザーごとにサーバーにデータを保存するようにして欲しい」などなど、いろいろな要望が寄せられました。ゆっくりバージョンアップさせていこうと考えています。