2008年5月1日木曜日

ProgressDialog(その4)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
長くなってしまったのエントリを変えた。まえのエントリではDestroyをちょっと追った。
こんどはProgressDialogを実装しているsrc/generic/progdlgg.cpp

まずは::Updateの中でbarがいっぱいになるようなvalueを渡したときの処理が行われる部分。

if ( value == m_maximum )
{
if ( m_state == Finished )
{
// ignore multiple calls to Update(m_maximum): it may sometimes be
// troublesome to ensure that Update() is not called twice with the
// same value (e.g. because of the rounding errors) and if we don't
// return now we're going to generate asserts below
return true;
}

// so that we return true below and that out [Cancel] handler knew what
// to do
m_state = Finished;
if( !(GetWindowStyle() & wxPD_AUTO_HIDE) )
{
EnableClose();
DisableSkip();
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
EnableCloseButton();
#endif // __WXMSW__

if ( newmsg.empty() )
{
// also provide the finishing message if the application didn't
m_msg->SetLabel(_("Done."));
}

wxYieldIfNeeded() ;

(void)ShowModal();
}
else // auto hide
{
// reenable other windows before hiding this one because otherwise
// Windows wouldn't give the focus back to the window which had
// been previously focused because it would still be disabled
ReenableOtherWindows();

Hide();
}
}
else // not at maximum yet if ( value == m_maximum )


デストラクタとReenableOtherWindows

// ----------------------------------------------------------------------------
// destruction
// ----------------------------------------------------------------------------

wxProgressDialog::~wxProgressDialog()
{
// normally this should have been already done, but just in case
ReenableOtherWindows();
}

void wxProgressDialog::ReenableOtherWindows()
{
if ( GetWindowStyle() & wxPD_APP_MODAL )
{
delete m_winDisabler;
m_winDisabler = (wxWindowDisabler *)NULL;
}
else
{
if ( m_parentTop )
m_parentTop->Enable();
}
}


でいくつか気になるメンバ変数があるが、m_parentTopはコンストラクタの中で

m_parentTop = wxGetTopLevelParent(parent);

となっている。

wxGetTopLevelParentの実装は、src/common/wincmn.cpp

// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------

wxWindow* wxGetTopLevelParent(wxWindow *win)
{
while ( win && !win->IsTopLevel() )
win = win->GetParent();

return win;
}


関連は不明だがなにかあるのかもしれない。一応よんでみた。
  • ::wxGetTopLevelParent() returns NULL @ wx-users
    要点:wxTopLevelWindowはDestroyの過程でwxWindowに成り下がった後、自分の子をDestroyし、最後になくなる。なので、Destroyされる子の側でよぶとNULL返すことになる

  • Why does wxGetTopLevelParent() not return a wxTopLevelWindow?



  • wxWindowDisablerも気になる。実装はsrc/common/utilscmn.cppにある。
    概要としてはwxTopLevelWindows.GetFirstでTopWindowのリストにあるwindowにたいしてdisableを呼んでいる。


    // ----------------------------------------------------------------------------
    // wxSafeYield and supporting functions
    // ----------------------------------------------------------------------------

    void wxEnableTopLevelWindows(bool enable)
    {
    wxWindowList::compatibility_iterator node;
    for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
    node->GetData()->Enable(enable);
    }

    wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
    {
    // remember the top level windows which were already disabled, so that we
    // don't reenable them later
    m_winDisabled = NULL;

    wxWindowList::compatibility_iterator node;
    for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
    {
    wxWindow *winTop = node->GetData();
    if ( winTop == winToSkip )
    continue;

    // we don't need to disable the hidden or already disabled windows
    if ( winTop->IsEnabled() && winTop->IsShown() )
    {
    winTop->Disable();
    }
    else
    {
    if ( !m_winDisabled )
    {
    m_winDisabled = new wxWindowList;
    }

    m_winDisabled->Append(winTop);
    }
    }
    }

    wxWindowDisabler::~wxWindowDisabler()
    {
    wxWindowList::compatibility_iterator node;
    for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
    {
    wxWindow *winTop = node->GetData();
    if ( !m_winDisabled || !m_winDisabled->Find(winTop) )
    {
    winTop->Enable();
    }
    //else: had been already disabled, don't reenable
    }

    delete m_winDisabled;
    }

    0 件のコメント: