07-28-2011, 10:31 AM
Pages: 1 2
08-01-2011, 10:36 AM
画面のレンダリングがタイミング的な問題でうまくいかないときに使ったりします。
08-01-2011, 07:06 PM
ありがとうございます!
画面描画のタイミングを制御する際に使うのですね
08-02-2011, 08:32 AM
画面描画のタイミングを制御、というと誤解を招きそう。
質問者さんがいってるのは {after 0s do} というイディオムの話しですよね。
(0sより大きい値を指定して将来のあるタイミングに処理を予約する使い方はおそらくそれほど疑問はないと思うので)
よく乱用されることもあるこのイディオムの使い方を真面目に理解するにはまずイベントループとイベントキューについて分かる必要があります。
イベントループについてはWikipedia参照
Curlのことばで簡単に説明するとイベントループは以下のような概念として理解できます。
・Curlのシングルスレッドなアプレット毎にイベントループが裏で動いている
・ループの度にイベントキューから次に処理すべきEvent(とEventTarget)が取得される
・取得したイベントを処理する(EventTarget.handle-event)
・その後UIを再描画する
・次のループへ
イベントキューには、ユーザがUIを操作したり、プログラムから明示的に enqueue-event された場合などにエントリが追加されます。
こういった概念を前提にすると {after 0s do} というイディオムは、Event や EventTarget をとくに指定せずに処理だけをイベントキューの末尾に追加(enqueue)することといえます。
ちなみに似たような理解を必要とするものに dispatch-event がありますが、これは handle-event
の途中で呼ばれた場合に、そのループを中断して、イベントキューが空になるまでそれ以降のループを回しきる(待機中のイベントをすべて処理してUIの描画も行う)ということになります。中断したループは、イベントキューを空にしたあとに再開されます。
ついでに、View.update は handle-event の途中で呼ばれ、その時点で UI
の再描画のみを実行するものです。(呼ばなければ handle-event が完了するまで再描画されない)
dispatch-event でも再描画が行われる結果になりますが、説明したように後続のイベントまで(順番を無視して)処理してしまう点で View.update より副作用が大きいです。再描画のみであれば View.update を使うよう推奨されているのはこのためです。
※これはあくまで説明のために単純化しているので実際のCurlの仕組みは当然もっと複雑で詳細は異なります
質問者さんがいってるのは {after 0s do} というイディオムの話しですよね。
(0sより大きい値を指定して将来のあるタイミングに処理を予約する使い方はおそらくそれほど疑問はないと思うので)
よく乱用されることもあるこのイディオムの使い方を真面目に理解するにはまずイベントループとイベントキューについて分かる必要があります。
イベントループについてはWikipedia参照
Curlのことばで簡単に説明するとイベントループは以下のような概念として理解できます。
・Curlのシングルスレッドなアプレット毎にイベントループが裏で動いている
・ループの度にイベントキューから次に処理すべきEvent(とEventTarget)が取得される
・取得したイベントを処理する(EventTarget.handle-event)
・その後UIを再描画する
・次のループへ
イベントキューには、ユーザがUIを操作したり、プログラムから明示的に enqueue-event された場合などにエントリが追加されます。
こういった概念を前提にすると {after 0s do} というイディオムは、Event や EventTarget をとくに指定せずに処理だけをイベントキューの末尾に追加(enqueue)することといえます。
ちなみに似たような理解を必要とするものに dispatch-event がありますが、これは handle-event
の途中で呼ばれた場合に、そのループを中断して、イベントキューが空になるまでそれ以降のループを回しきる(待機中のイベントをすべて処理してUIの描画も行う)ということになります。中断したループは、イベントキューを空にしたあとに再開されます。
ついでに、View.update は handle-event の途中で呼ばれ、その時点で UI
の再描画のみを実行するものです。(呼ばなければ handle-event が完了するまで再描画されない)
dispatch-event でも再描画が行われる結果になりますが、説明したように後続のイベントまで(順番を無視して)処理してしまう点で View.update より副作用が大きいです。再描画のみであれば View.update を使うよう推奨されているのはこのためです。
※これはあくまで説明のために単純化しているので実際のCurlの仕組みは当然もっと複雑で詳細は異なります
08-02-2011, 09:11 AM
イベントループモデルは近頃また話題ですねー。Curlにも波及してきたり…?
08-02-2011, 11:01 AM
ありがとうございます!
きちんとイベント処理の概念を理解して、適切な使い方をする様にします
08-10-2011, 10:38 AM
>[url=http://communities.curl.com/member.php?action=profile&uid=13][/url]fukutaさん
横やりですいません。
この手の「イベントを操作する」という概念は"はまった"経験しかなく、可読性が落ちる原因と自分は思っています。
私個人は他言語で通常のローカルアプリ(EXE、DLL)を作成してきて、{after 0s do}の様な概念は使用せず構築してきたので
逆に「こういうときは結果的に使わざるを得ない」という例があればうれしいのですが・・・。
横やりですいません。
(08-02-2011, 08:32 AM)fukuta Wrote: [ -> ]こういった概念を前提にすると {after 0s do} というイディオムは、Event や EventTarget をとくに指定せずに処理だけをイベントキューの末尾に追加(enqueue)することといえます。概念は分かったのですが、これを使う簡単な局面・例ってありますでしょうか?
この手の「イベントを操作する」という概念は"はまった"経験しかなく、可読性が落ちる原因と自分は思っています。
私個人は他言語で通常のローカルアプリ(EXE、DLL)を作成してきて、{after 0s do}の様な概念は使用せず構築してきたので
逆に「こういうときは結果的に使わざるを得ない」という例があればうれしいのですが・・・。
08-10-2011, 09:06 PM
(08-10-2011, 10:38 AM)復活の帝王 Wrote: [ -> ]この手の「イベントを操作する」という概念は"はまった"経験しかなく、可読性が落ちる原因と自分は思っています。
私個人は他言語で通常のローカルアプリ(EXE、DLL)を作成してきて、{after 0s do}の様な概念は使用せず構築してきたので
逆に「こういうときは結果的に使わざるを得ない」という例があればうれしいのですが・・・。
確かにむやみな使用は避けるべきと思います。
妥当な例はすぐにたくさん思いつきませんが、例えばグラフィカルオブジェクトの大きさを表示時に取得したい場合など。
表示上のサイズはオブジェクトがグラフィカル階層にアタッチされた後、レイアウトネゴシエーションが完了するまで確定しないので、サイズの取得はそれを待ってから行う必要があります。
Code:
{on AttachEvent at g:Graphic do
{after 0s do
{do-something {g.layout.get-bounds}}
}
}
もうひとつの例は、例えば
「DateField の入力値を Delete キーで削除できるようにしたい」(※)
といった要望があった場合に、after を使って以下のように実現することがあります。
※CurlのDateFieldはフォーカスアウト時に未入力だと値を元に戻してくれるのでDeleteで削除できない。。
Code:
{define-class public MyDateField {inherits DateField}
{constructor public {default ...}
{construct-super {splice ...}}
}
{method public {get-parsed-value
val:String,
require-four-digit-year?:bool = false
}:(date:DateTime,
day-start-pos:int, day-end-pos:int,
month-start-pos:int, month-end-pos:int,
year-start-pos:int, year-end-pos:int)
{if {val.trim-clone}.empty? then
{after 0s do
{self.unset-value}
}
}
{return
{super.get-parsed-value
val,
require-four-digit-year? = require-four-digit-year?
}
}
}
}
これは、DateField の入力欄の「生の」値を見るために get-parsed-value というメソッドをオーバーライドして文字列が削除されたかどうか判断している例ですが、
このメソッド内で unset-value しても後続の処理で値が復活してしまいます。そのためここで after を用いて一連の処理が終わった後に unset-value が実行されるようにしています。
このように、組み込みAPIの動作など手を出せない部分に依存したり、それらの結果を覆したいような場合に after が使える場合があります。
基本的にはほとんどハック的な目的で使うものだと思います。
08-11-2011, 09:09 AM
>fukutaさん
ご回答ありがとうございます。
#~resizedイベント、みたいな感じのものです。
しかしこういった挙動をしたいという要求仕様+DateField使用は無理がある様に感じますね。(とはいうものの対案はないのですけど)
また{after 0s do} の0部分を1以上とするのも個人的には非常に違和感を感じます。
GUIのローカルアプリでは通常、タイマーコントロールが存在しますが、こういった概念がないから(いや、あるのかも分かりません)でしょうか?
質問ばっかりで申し訳ないですが、ご存じなら教えて下さい。
ご回答ありがとうございます。
(08-10-2011, 09:06 PM)fukuta Wrote: [ -> ]妥当な例はすぐにたくさん思いつきませんが、例えばグラフィカルオブジェクトの大きさを表示時に取得したい場合など。CurlのGUI歴があまり(=殆ど)ないので、「何を今更?」的な事を言っているかもしれませんが、この場合別途イベントは発生しないのでしょうか?
表示上のサイズはオブジェクトがグラフィカル階層にアタッチされた後、レイアウトネゴシエーションが完了するまで確定しないので、サイズの取得はそれを待ってから行う必要があります。
#~resizedイベント、みたいな感じのものです。
Quote:「DateField の入力値を Delete キーで削除できるようにしたい」(※)DateFieldの使用はないですが、こっちは意味は分かります。
といった要望があった場合に、after を使って以下のように実現することがあります。
※CurlのDateFieldはフォーカスアウト時に未入力だと値を元に戻してくれるのでDeleteで削除できない。。
しかしこういった挙動をしたいという要求仕様+DateField使用は無理がある様に感じますね。(とはいうものの対案はないのですけど)
また{after 0s do} の0部分を1以上とするのも個人的には非常に違和感を感じます。
GUIのローカルアプリでは通常、タイマーコントロールが存在しますが、こういった概念がないから(いや、あるのかも分かりません)でしょうか?
質問ばっかりで申し訳ないですが、ご存じなら教えて下さい。
08-11-2011, 01:40 PM
(08-11-2011, 09:09 AM)復活の帝王 Wrote: [ -> ]CurlのGUI歴があまり(=殆ど)ないので、「何を今更?」的な事を言っているかもしれませんが、この場合別途イベントは発生しないのでしょうか?そういったイベントは発生しないですね。
#~resizedイベント、みたいな感じのものです。
(08-11-2011, 09:09 AM)復活の帝王 Wrote: [ -> ]また{after 0s do} の0部分を1以上とするのも個人的には非常に違和感を感じます。
GUIのローカルアプリでは通常、タイマーコントロールが存在しますが、こういった概念がないから(いや、あるのかも分かりません)でしょうか?
違和感についてはよく分かりませんが、CurlにもTimerというAPIがありますよ。定期的に処理を行う場合などはこちらを使います。
Pages: 1 2