Macromedia Director非公式テクニカルノート

MIAWを閉じるとプロジェクタが落ちる

ID: FN0108018 Product: Director

Platform: All
Viersion: 8.0 and 8.5

1. 現象
MIAW(Movie In A Window: ウィンドウ内ムービー)をLingoで閉じると、プロジェクタがエラーで終了してしまうことがあります。

2. 原因
Windows版のDirector 8.0および8.5のプロジェクタで報告されている現象です(7.0.1/7.0.2でも同様の報告がありましたが、本稿では8.0以降の対処法をご紹介します)。MIAWから自身を'forget window'で閉じると、発生することがあります。MIAWから'close window'で自身を閉じただけで、この問題が発生したという例もあるようです。

なお、MIAWから'tell'コマンドで、ステージに対して自分を閉じるステートメント(tell the stage to window(ウィンドウ).forget())を実行しても回避はできません。MIAWを'forget window'で消去したために、コールバックの受取りに問題が生じているものと推測されます。

3. 対処法
MIAWからは、ステージに対して自身を'forget window'する「予約」を行うに止め、MIAWからの処理を完了させる必要があります。そして、改めてステージからMIAWを消去します。

Director 8.0から、こうした処理に最適のタイムアウトオブジェクトが実装されました。これを親スクリプトと組合わせて対応するスクリプトのサンプルをご紹介します。親スクリプトについて詳しくは、『Lingo辞書』または市販の解説書(たとえば大重美幸『Lingoスーパーマニュアル−Director 8対応−』オーム社)をご参照ください。

--[ForgetWindow]
-- MIAWの親スクリプトとして設定します
property pMyWindow, pbClosed

on new(me, oWindow)
   pMyWindow = oWindow
   tell the stage to timeOut(me.string).new(0, #xNothing, me)
end

on exitFrame(me, oTimeOut)
   oTimeOut.forget()
   oTimeOut.target = void
   oTimeOut = void
   pMyWindow.close()
   pMyWindow.forget()
end

まず、'on new'ハンドラは、パラメータとして消去すべきウィンドウへの参照oWindowを受取ります。そして、第1ステートメントで、そのウィンドウへの参照をプロパティに設定します。

第2ステートメントでは、タイムアウトオブジェクトを作成します(タイムアウトオブジェクトについて、詳しくは『Lingo辞書』の'timeout()'関数および'new()'関数をご参照ください)。タイムアウトオブジェクト名はユニークな名前なら何でもよいので、親スクリプトのアドレス参照をストリングにして使っています。タイムアウト時間を0とすると無指定となり、'forget()'で明示的に削除するまでタイムアウトオブジェクトは存在し続けます(ドキュメント化されてはいません)。タイムアウトハンドラの#xNothingは、ダミーとして設定しました。このハンドラは、スクリプト中にありません。ターゲットオブジェクトはこの親スクリプトで生成した子オブジェクト('me')です。

'on new'ハンドラの最終ステートメントに、'return me'がありません。これは、生成された子オブジェクトを受取って変数に格納するという必要がないからです。子オブジェクトは、タイムアウトオブジェクトのターゲットオブジェクトとして参照されています。ですから、タイムアウトオブジェクトが存在する間、子オブジェクトも存在します。タイムアウトオブジェクトが消えれば、参照はなくなり、メモリから削除されます。

もうひとつ、'timeOut'オブジェクトは、ステージに対して('tell the stage to')生成しました。それは、タイムアウトオブジェクトが(ステージを含めた)ウィンドウごとに設定されるものだからです。MIAWを消去すると、タイムアウトオブジェクトも消滅してしまいます。今回は、MIAWを消去するスクリプトですから、それでも実際上は問題ないかもしれません。けれど、スクリプト中の正規の処理で自身を消去する方が、より安定したスクリプティングだといえます。

このスクリプトの処理の本体は、'on exitFrame'ハンドラです。ここで、ドキュメントに記載のない点が、2つあります。ひとつは、タイムアウトオブジェクトも通常のフレームイベントを受取ることです。もうひとつ、ハンドラは、第2パラメータとしてタイムアウトオブジェクトを受取ります。

第1ステートメントで、受取ったタイムアウトオブジェクトを'forget()'しています。したがって処理が終了すれば、子オブジェクトもメモリから消去されます。したがって、スクリプトは、一度だけしか実行されません。これが、タイムアウトオブジェクトを使う利点です。

第2ステートメントは、タイムアウトオブジェクトのターゲットオブジェクトに設定したこの親スクリプトへの参照を、破棄しています。これを実行しない場合には、MIAWへの参照がメモリに残り、同じMIAWを再び開くことができないという問題が確認されています。

第3ステートメントでは、タイムアウトオブジェクトの参照を破棄します。'forget()'は「[タイムアウトオブジェクト]をthe timeoutListから削除」(『Lingo辞書』の'forget()'の項)するだけで、タイムアウトオブジェクトそのものが消去される訳ではありません。何らかの問題が生じることを防ぐために、これを明示的に破棄しておきます。

第4および第5ステートメントは、プロパティに設定しておいたウィンドウの参照に対して、'close window'および'forget window'を実行します。これで、MIAWがメモリから削除されます。

実際に使う場合には、MIAWからこの親スクリプトの子オブジェクトを生成すればよいです。たとえば、MIAWのボタンに設定するビヘイビアは、以下のようになります。on xForgetハンドラは、念のため受取ったパラメータが(ウィンドウ)オブジェクトかどうかの確認をしています。

on mouseUp(me)
   me.xForget(the activeWindow)
end

on xForget(me, oWindow)
   if objectP(oWindow) then
     -- 親スクリプト"ForgetWindow"から子オブジェクトを生成
     script("ForgetWindow").new(oWindow)
   end if
end

_____

作成者: 野中文雄
更新日: 2001年9月20日 サンプルの親スクリプトにステートメントおよびその解説を追加
作成日: 2001年8月24日


© 2001 and beyond Fumio Nonaka All rights reserved.