bool wxSafeYield(wxWindow* win = NULL, bool onlyIfNeeded = false)
This function is similar to wxYield, except that it disables the user input to all program windows before calling wxYield and re-enables it again afterwards. If win is not NULL, this window will remain enabled, allowing the implementation of some limited user interaction.
Returns the result of the call to ::wxYield.
で、実装はこうなっている。
// Yield to other apps/messages and disable user input to all windows except
// the given one
bool wxSafeYield(wxWindow *win, bool onlyIfNeeded)
{
wxWindowDisabler wd(win);
bool rc;
if (onlyIfNeeded)
rc = wxYieldIfNeeded();
else
rc = wxYield();
return rc;
}
あとはwxYieldだが次のようになっている。
bool wxYield()
{
return wxTheApp && wxTheApp->Yield();
}
bool wxYieldIfNeeded()
{
return wxTheApp && wxTheApp->Yield(true);
}
で、wxApp::Yieldに帰結する。あー、ながかった。
Yieldするとイベントがプロセスされるが、その中でYieldしたDialogを殺したら当然、戻ってきたときにthisがNULLなのでアプリがクラッシュしてしまいます!
今回の場合はDialogのEventHandlerがYield中であることは知らないのでこれに該当するでしょう。ネットワークから届いたデータが引き金となって受信スレッドからwx.CallAfterで呼ばれている。CallAfterはイベントの処理が終わった後に実行されるので、CallAfterの処理がYieldで行われている可能性は否定できない(どこを読めばいいのだ?)。
windowを開いたままイベントハンドラを抜けてしまうなら、そのwindowはwxのDialogである必要がなく(Yieldしてもらいたくない)て、親のWindow側からpollできることになるので親をプログラム的にDisableしてprogress barを自前で描くwindowを作るというのがひとつの解。
もうひとつは、前の可能性が正しいとしてYield中だったらもういちどCallAfterかなんかしてYieldを抜けてから処理が行われるようにする。wxの側でこの手のガードをすることも考えられるが、微妙な気がする。
0 件のコメント:
コメントを投稿