プロが教える店舗&オフィスのセキュリティ対策術

毎度お世話になっておりますsassakunと申します。
変な回答をすることがありフォローを入れていただきありがとうございます。
Flashカテゴリでの質問は初心者です。

訳あってActionScriptエディタを作成中です。
「Flash Player de ActionScript」(今閃いた仮称)。
大した物ではないです。
テキストエディタでスクリプトを作る事が多々あるのですが,定型句みたいなものをキーボードを叩くのが面倒です。
またifをIFと書いてしまったり書き間違いが多いです。
蛇のアイコンのソフトも知っていますが,あれはFlashより使い勝手が悪い。
それなら自分で作ってしまおうと思ったのです。

TXTという変数名のダイナミックテキストエリアを作成し,あるボタンをクリックすると,そのボタンのスクリプトで

 on (release) {
  TXT = TXT + "ActionScript(値)"
 }

みたいなスクリプトで,
変数TXTにどんどんスクリプトを加算していく方法で大体はできました。
大体と言うのは自分がよく使うスクリプトの範囲内という意味です。
でも上のスクリプトだとどうしても文字列の後に,"ActionScript(値)" が付いてしまいます。

そうではなくて,

 onClipEvent (load) {
 | (←マウスカーソルのつもり)
 }

のカーソル部分に
_root.stop(); などというスクリプトが入れたい場合が多々あります。
タグ挿入型HTMLエディタならぬ,Script挿入型ActionScriptエディタです。
イメージをスクリプトにするなら,

on (release) {
 TXT1 = TXT の1文字目からカーソルまで;
 TXT2 = TXT のカーソルから最終文字まで;
 TXT = TXT1 + "ActionScript(値)" + TXT2;
}

みたいな感じです。
これを実現するActionScript,または方法はあるのでしょうか。
そんなことも知らないのか! などと思われそうな気もしますが,ここでの質問は初心者ですのでよろしくおねがいします。

A 回答 (1件)

フォーカスに関する制御を担当する、Selection というクラス( MX 以前ではオブジェクト)があります。


テキストフィールド内にある入力カーソル(点滅している” | ”型のカーソル)の位置は Selection.getCaretIndex メソッドで、表示されている文字列は TextField クラスの text プロパティで取得できます。
text プロパティには文字列が入っているので、文字列でできることは一通り可能です。
取得したカーソルの位置を境に2つに分割し、任意の文字列を挿入してはいかがでしょう。


仮に、ステージに「テキスト入力」にしたテキストフィールドがあるとします。
入力カーソルの位置が変わる可能性があるのは

 1) キー入力が行われた時
 2) マウスでテキストフィールド内をクリックされた時

ですから、これらのイベントを使って監視します。
1) は Key クラスの onKeyUp 、2) はムービークリップの onMouseUp か Mouse クラスの onMouseUp イベントが利用できます。
どちらの場合も処理は同じなので、関数を1つ作り、これをイベント発生時に呼ぶ関数として登録しておくと便利です。

取得したカーソルの位置は、変数に保存しておきます。
この位置を元にテキストフィールドの内容を分割し、指定の文字列を挿入する関数を作ります。
後は、テキストを挿入する時に、挿入する文字列を引数にしてこの関数を呼ぶだけです。


スクリプトにすると、大体、次のようになります。
このスクリプトは、メインのタイムラインに設定してください。
ステージに、「テキスト入力」にしたテキストフィールド” editor ”があるものとします。

(↓各行頭に全角のスペースが入っています。コピーする際はご注意ください)


 //入力カーソル位置を保持
 edit_pos = 0;


 /////////////////////////////////////////
 //入力位置を把握する関数
 /////////////////////////////////////////
 function Get_InsertPosition()
 {
  //編集画面にフォーカスがある場合のみ、文字カーソルの位置を取得
  if( Selection.getFocus() == "_level0.editor" )
  {
   edit_pos = Selection.getCaretIndex();
  }
 }


 /////////////////////////////////////////
 //指定の文字列を、現在の入力位置に挿入
 //引数:挿入する文字列
 /////////////////////////////////////////
 function Insert_Text( insert_str )
 {
  var head , tail , org_length , insert_length;


  //編集前の文字列と挿入する文字列の長さを取得
  org_length = editor.text.length;
  insert_length = insert_str.length;

  //編集画面のテキストを、現在の入力位置で分割
  head = editor.text.substring( 0 , edit_pos );
  tail = editor.text.substring( edit_pos , org_length );

  //指定の文字を挿入
  editor.text = head + insert_str + tail;


  //選択範囲を利用して入力カーソルを移動
  edit_pos += insert_length;
  Selection.setFocus( "editor" );
  Selection.setSelection( edit_pos , edit_pos );
 }


 //キー入力があった時とマウスのボタンが押された時、
 //入力カーソルの位置を監視
 key_obj = new Object();
 Key.addListener( key_obj );
 key_obj.onKeyUp = Get_InsertPosition;

 mouse_obj = new Object();
 Mouse.addListener( mouse_obj );
 mouse_obj.onMouseUp = Get_InsertPosition;


Get_InsertPosition 関数では、入力カーソルの位置を getCaretIndex で取得し、この位置を変数 edit_pos に保存しています。
この関数は、キーを押して離した時と、マウスのボタンを押して離した時に呼び出されます。

Key クラスや Mouse クラスは、Key.onKeyUp = ・・・というように、クラス(のオブジェクト)に直接イベント発生時の処理を定義することができません。
これらのクラスでイベントを利用する時は、イベントの通知を代理で受け取る”リスナーオブジェクト”が必要です。
リスナーオブジェクトは汎用型である Object 型の変数を作り、これを addListener メソッドで登録します。

これらのイベントが発生するのは、テキストフィールド内でキーボードやマウスを操作した時とは限りません。例えばマウスのボタンは、スクリプトを挿入するボタンをクリックする時にも押されるので、onMouseUp イベントはこの時にも発生します。
ムービー内のボタンをクリックすると、フォーカスが外れて文字入力カーソルは消えますから、getCaretIndex の戻り値は -1 になります。

この状態で文字を挿入しようとすると、テキストフィールドに格納された文字列の分割に失敗し、テキストフィールドの先頭にしか挿入されなくなってしまいます。
そこで、イベント発生時に条件を付け、テキストフィールドが対象の時にキーまたはマウスを操作した場合、つまり、テキストフィールド” editor ”にフォーカスが当たっている時だけ、入力カーソルの位置を保存することにします。
フォーカスが当たっているインスタンスは、Selection クラスの getFocus で取得できます。
trace アクションで見てみると分かりますが、getFocus の戻り値はレベルからの絶対パスです。通常はステージは _level0 ですから、ステージにあるテキストフィールド editor にフォーカスがある時は、” _level0.editor ”という文字列が返されます。


Insert_Text は実際にテキストを挿入する関数です。
例えば” _root.stop(); ”というスクリプトを挿入するボタンでは、これを引数として

 on(release)
 {
  Insert_Text( "_root.stop();\n" );
 }

というように呼び出してください。
最後の” \n ”は改行のコードで、入れておくと改行も挿入されます。
文字列を引数とするスクリプトは、

 Insert_Text( "_root.gotoAndPlay( \"Start\" );\n" );

このように ¥ でつなぐと、" " の部分で切られずに関数に文字列が渡ります。

Insert_Text 関数の中でやっていることは、ご質問文にある

 > TXT1 = TXT の1文字目からカーソルまで;
 > TXT2 = TXT のカーソルから最終文字まで;
 > TXT = TXT1 + "ActionScript(値)" + TXT2;

と、全く同じことです。
入力カーソルの位置を境にしてテキストフィールドに入っている文字列を分割し、作業用変数 head に前半部分、tail に後半部分を入れて、引数で渡されてきた文字列を連結しています。


テキストエディタでは普通は、文字を挿入した分だけカーソルもずれて連続的に入力できるものですが、Flash のテキスト入力では、スクリプトで操作して文字を挿入した場合はカーソルが移動しません。
例えば、テキストフィールドの表示が

 //サンプル
 trace( "サンプル" );
 |

(↑” | ”は入力カーソルです)

だとして、ここに” _root.stop(); ”をスクリプトで挿入すると、

 //サンプル
 trace( "サンプル" );
 |_root.stop();

となり、入力位置は変わらないままです。
ざっと見た限りでは、Selection.getCaretIndex でカーソルの位置の取得はできても、任意の位置にカーソルを移動するメソッドはないようです。

Selection クラスには、指定の範囲を選択状態にする setSelection というメソッドがあります。
字数は配列と同様に0から数えますので、例えば

 Selection.setSelection( 0 , 4 );

とすると、フォーカスの当たっているテキストフィールドの最初から5文字までが選択された状態になります。
この時、入力位置を表すカーソルは5文字目(インデックス値では4)の位置に移動しています。
Insert_Text 関数内ではこの特徴を利用して、擬似的にカーソルを進めています。

setSelection は、フォーカスの当たっているテキストフィールドでなければ何も起こりません。
Insert_Text 関数が呼び出されるのは、スクリプトを挿入するボタンをクリックした時などです。
ボタンをクリックした時点で editor はフォーカスを失っていますから、setFocus で再度 editor にフォーカスを与えています。

---------------------------------------------------------

ご承知の上だとは思いますが。
Flash は、本格的なアプリケーションを作ることが目的のソフトではありません。
ActionScript でも、指定された位置に文字を挿入するくらいのことであれば、まあ、一応はできるという程度です。
エディタの機能を付け足していこうとすると、どうしても、弱い部分が目立ってきます。
例えば、テキストフィールドの都合上、文字を挿入する位置によっては挿入した文字が上に送られて見えなくなってしまうことがあり、これはエディタとしては使いにくいです。

テキストフィールドや変数内に作ったスクリプトはただの文字列で、スクリプトとして機能はしません。SharedObject に書き出して保存することはできても、SharedObject の内容を他のムービーに読み込んでも文字列として扱われるだけです。
テキストファイルに書き出せるなら、外部ファイルとして #include で組み込む手もありますが、Flash 単体ではファイル出力は無理です。
編集したものを有効な形式で保存できないのは、エディタとしては致命的な欠陥です。
テキストフィールドの内容をコピーして他の FLA ファイルに貼り付けるくらいなら、最初から「アクション」パネルで編集した方が早くて確実です。


エディタはスクリプトの勉強としては面白い題材ですが、実用レベルのものを作るとなると、Flash ではかえって難関が多く、難しいのではないでしょうか。

この回答への補足

(補足に書いていますが補足ではなく,お礼の第1弾です。)

オー! さすがDPEさん。スゴイ…。
これで,また一儲けができる~~! やっぱりFlashはおいしいソフトだ~~!!
というのは冗談です。
これを使用することで儲けることはできても,これ自体で儲けるのは,ご指摘通り不可能だと思います。

しかし,そんな方法があるのですね。
ボタンをクリックすると同時にテキストエリアからフォーカスがなくなるので,
これは不可能かなと思っていました。
スクリプトを挿入したい部分に,Flashではあまり使わない $ マークでも入れて,
ボタンをクリックしたとき,その $ を "スクリプト(文字列)" で置換しようかなどと考えていました。
でもこれでは,すごく使い勝手が悪いです。

>> 編集したものを有効な形式で保存できないのは、
>> エディタとしては致命的な欠陥です。

おっしゃる通りです。
Flashで作るソフトの最大の弱点だと思っています。
でもそれができないところが,逆にFlashの良さですよね。
安心してFlashプレーヤーをインストールできて,安心してサイトが閲覧できる。

>> エディタはスクリプトの勉強としては面白い題材ですが、
>> 実用レベルのものを作るとなると、
>> Flash ではかえって難関が多く、難しいのではないでしょうか。

いえいえ,提示していただいた回答を元に本当に実用に使うつもりですよ。個人的に。
本当に回答してくださって感謝しております。

つまりはライセンスの問題です。
いつでも,どのPCからでもFlashを使える環境にないのです。
で,ふとひらめいたことを紙に書くか,メモ帳などテキストエディタなどに書くのですが,
綴りなどをよく間違えるのです。
で,思いも寄らないところにエラーの根源があったりするので,困っていたわけです。

まだ,回答して頂いたものは実際にしておりません。
ちゃんと理解して,実際にしてから,あらためてちゃんとしたお礼を書きます。

あと,質問で,ダイナミックテキストエリアと書きましたのは間違いで,テキスト入力のテキストフィールドです。失礼しました。

補足日時:2005/07/16 19:16
    • good
    • 0
この回答へのお礼

ありがとうございましたーーーー!
無事動き,9割方理解できました。

イベントを発生させるのに,
フレームアクションか,ボタンやムービークリップの onイベントパンドラ しかほとんど使ったことが無かったで勉強になりました。
また,カーソル位置の移動まで配慮したスクリプトを考案してくださって感謝感謝です。

改行コードの挿入位置に関しては,色々な場合があるので,ずっと迷っているのですが,
カーソルの後に改行コードがなければ,自動で改行を挿入みたいにしようかなと今は考えています。
さらに色々な条件分岐が必要かもしれません。

これで,日頃使わないスクリプトもどんどん入れたくなってきました。
スクリプトの意味がわからなくても,文字列を挿入すれば良いだけですから,同じ作業で作り続けられます。

現在インターフェイスを少々凝っても,現在ほんの数十KBのSWFファイルです。
フロッピーにでも楽々入って持ち運びにも便利。
Flashプレーヤーすら入れていないPCで使うために,プロジェクタにしたとしても1MB少々。
書いてくださったスクリプトはMXでも使用可能でしたから,MXでプロジェクタにすると1MBは切ります。
これで快適なFlash生活が送れそうです。

あとは,自動フォーマット(インデント)機能とエラーチェック機能を追加すれば完璧!
自動フォーマットは,じっくり考えればできるような気がします。
エラーチェックは例えば,
「スクリプトに全角空白が入っていないか。」とか
「"{" の数と "}" の数は等しいか。」
などできるところからしていけばある程度はできるような気もします。完全には無理でしょうけど。
今のところ,この2つの機能はあってもなくても良いので,後の研究課題とします。 

おかげさまで,自分が使う範囲での実用化の目星はつきましたーーー! (そのうちフリーソフトとしてなら出せるかも…。)

お礼日時:2005/07/17 07:03

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!