デル株式会社

CFrameWnd 雑記

Last Updated: Jan.5,2007
使用しているコンパイラは、Microsoft Visual C++ 6.0 です。これ以外のバージョンでは記述と食い違うことがあるかも知れません。

4. MDI で「すべて閉じる」の実装

巷のほとんどの MDI アプリケーションにはあるのですが、MFC では標準でサポートされていない機能です。絶対無いと困るというわけでもないのですが、いろいろやってみました。状況に応じて使い分けるのがよいかも知れません。

まず、もっとも少ないコードで実装してみます。

void CMainFrame::OnWindowCloseAll() 
{
    if (AfxGetApp()->SaveAllModified())
        AfxGetApp()->CloseAllDocuments(FALSE);
}

これでも、実際使ってみるとそれほどの不都合はないだろうと思います。すべてのドキュメントの保存確認が行われてから、すべてのドキュメントを閉じるので、保存確認のどこかでキャンセルされるとすでに保存確認が済んだドキュメントも含めてすべてが閉じられないままになります。

これをすでに保存確認が済んだものは閉じるようにするには、ひとつひとつドキュメントを辿る必要があります。

void CMainFrame::OnWindowCloseAll()
{
    POSITION posDocTemplate = AfxGetApp()->GetFirstDocTemplatePosition();
    while (posDocTemplate)
    {
        CDocTemplate* pDocTemplate = AfxGetApp()->GetNextDocTemplate(posDocTemplate);
        ASSERT(pDocTemplate);
        POSITION posDocument = pDocTemplate->GetFirstDocPosition();
        while (posDocument)
        {
            CDocument* pDocument = pDocTemplate->GetNextDoc(posDocument);
            ASSERT(pDocument);
            /* (1) */
            if (!pDocument->SaveModified())
                return;
            pDocument->OnCloseDocument();
        }
    }
}

かなりいい感じです、と言いたいところなのですが、保存確認の順序がドキュメントが開かれた順番なので、たとえば「新規作成」を複数回行い、いろいろ編集してから実行するとどのドキュメントの保存確認なのかがよく分からなくなります。そこで、(1) のところに以下のコードを挿入します。

...

POSITION posView = pDocument->GetFirstViewPosition();
if (posView)
{
    CView* pView = pDocument->GetNextView(posView);
    if (pView) pView->GetParentFrame()->BringWindowToTop();
}

...

保存確認を出す前に、そのドキュメントのフレームウィンドウを前面に持ってくるという処理です。今度はかなりいい感じになりました。

さて、ここまでくると欲が出てきます。前面にあるウィンドウから順番に保存確認が出るようになれば、更に感覚的に受け入れやすいものになります。そこで考え方を変えて、ドキュメントを辿るのではなく、アクティブなフレームウィンドウを辿ることにしました。

void CMainFrame::OnWindowCloseAll()
{
    CMDIChildWnd *pChild = MDIGetActive();
    CDocument* pDoc;
    while (pChild)
    {
        if ((pDoc = pChild->GetActiveDocument()) != NULL)
        {
            if (!pDoc->SaveModified())
                return;
            pDoc->OnCloseDocument();
        }
        pChild = MDIGetActive();
    }
}

MDIGetActive ですべてのフレームウィンドウが取得できるのかどうかが、少々不安要素ではありますが、いまのところ不具合には出会っていません。


Back Copyright (c) 2007 AOK. All Rights Reserved.