仅允许在MFC MDI应用程序中打开一个CDocument

时间:2015-04-17 10:59:05

标签: c++ mfc

正如问题所说,我试图在MFC MDI应用程序中一次只允许一个文档。由于许多(无关)原因,我没有使用SDI文档模板。很多地方评论这样做,但我不知道如何。最接近的是此链接中的建议:http://computer-programming-forum.com/82-mfc/06d5cebffaeefeae.htm但它不能与CWinAppEx一起使用 - 文档已关闭,即使用户取消了“文件打开”对话框。此外,使用MRU列表或工具栏按钮可以绕过此建议。

非常感谢任何帮助!


BOOL CMyDoc::closeDocument()
{
    if (!SaveModified())
    {
        // User has vetoed the close, return error
        return TRUE;
    }
    else
    {
        // OK to close
        OnCloseDocument();
        return FALSE;
    }
}

在CMyApp中:

void CMyApp::OnFileOpen()
{
    CMyDoc* pDoc = CMyDoc::GetDoc();
    if (pDoc != NULL && pDoc->closeDocument())
        // user has vetoed the close - can't create new one
        return;
    // no document currently open, or we succesfully closed it    

    CWinAppEx::OnFileOpen();
}


void CMyApp::OnFileNew()
{
    CMyDoc* pDoc = CVATDoc::GetDoc();
    if (pDoc != NULL && pDoc->closeDocument())
        // user has vetoed the close - can't create new one
        return;
    // no document currently open, or we succesfully closed it
    CWinAppEx::OnFileOpen();
}

虽然这可能适用于旧版本的MFC,但现在似乎无法正常工作(VS2013)。在用户选择(或取消)新文档之前,文档已关闭。

2 个答案:

答案 0 :(得分:2)

有一种更简单的方法,并不涉及挂钩所有这些功能。将一些ON_UPDATE_COMMAND_UI()消息映射处理程序添加到应用程序对象。具体来说,ID_FILE_NEW和ID_FILE_OPEN。如果有打开的文档,请禁用该命令。这是一些代码。不能保证工作,但应该让你到那里。

ON_UPDATE_COMMAND_UI(ID_FILE_NEW, SomeUpdateHandler)
ON_UPDATE_COMMAND_UI(ID_FILE_OPEN, SomeUpdateHandler)

void CMyApp::SomeUpdateHandler(CCmdUI* pCmdUI)
{
    POSITION pos = GetFirstDocTemplatePosition();

    CDocTemplate* pTemplate = GetNextDocTemplate(pos);

    POSITION posDoc = pTemplate->GetFirstDocPosition();
    pCmdUI->Enable(posDoc != NULL);
}

如果您有一个打开的文档,则将禁用File-New和File-Open。关闭文档后,您可以打开或创建一个新文档。

答案 1 :(得分:0)

所以我找到了一个解决方案,并认为解释它很有用。我希望这对某人有用。我已经花了很长时间来度过MFC(这是一件好事)并且现在看看为什么上面链接的解决方案不再是MFC9中的解决方案。

文件打开命令

从最近使用的列表

调用堆栈是这样的:

CWinApp::OnOpenRecentFile(UINT nID) // Non-virtual – cannot override
CWinApp::OpenDocumentFile(LPCTSTR lpszFileName) // Virtual – can override in CMyApp
CDocManager::OpenDocumentFile(LPCTSTR lpszFileName)
CDocManager::OpenDocumentFile(LPCTSTR lpszFileName, BOOL bAddToMRU)
CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bAddToMRU, BOOL bMakeVisible); // here is the actual creation of the new frame etc

所以唯一可以加入的地方是覆盖OpenDocumentFile课程中的CMyApp

从对话框

这更容易 - 有多个地方可以挂钩,但是在开始时挂钩不会允许用户显示文件打开对话框并取消它,同时保持现有文档打开。

CMyApp::OnFileOpen(); // override
CWinAppEx::OnFileOpen(); // call base class
CDocManager::OnFileOpen(); // This one is key – in here the File Open dialog is shown
CMyApp::OpenDocumentFile(LPCTSTR lpszFileName) // And here we can hook into the call stack
CWinAppEx::OpenDocumentFile(lpszFileName);
CDocManager::OpenDocumentFile(LPCTSTR lpszFileName)
CDocManager::OpenDocumentFile(LPCTSTR lpszFileName, BOOL bAddToMRU)
CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bAddToMRU, BOOL bMakeVisible) // here is the actual creation of the new frame etc

文件新命令

这个很棘手,因为一旦OnFileNew被调用就没有钩子。

CMyApp::OnFileNew(); // virtual override
CWinAppEx::OnFileNew(); // base class
CDocManager::OnFileNew(); // this calls the doc template without another hook back into our derived classes
CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bAddToMRU, BOOL bMakeVisible)

解决方案

解决方案是派生我们自己的DocTemplate类并重写一些函数,但这是一项很重要的工作。 A' hackier'方法如下。

打开文件

此挂钩适用于MRU和对话框命令 - 请参阅上面的调用堆栈。 “文件打开”对话框已显示并已选中文件。如果取消“文件打开”对话框,我们就无法到达此处。

CDocument* CMyApp::OpenDocumentFile(LPCTSTR lpszFileName)
{
    CMyDoc* pDoc = CMyDoc::GetDoc(); // static func that gets pointer to MyDoc
    if (pDoc != NULL && pDoc->closeDocument())
        // user has vetoed the close - can't create new one
        return NULL; // here we prevent opening by by-passing base class call
    return CWinAppEx::OpenDocumentFile(lpszFileName);
}

新文件

由于没有要取消的对话框,我们可以在开始时直接挂钩,如果用户不允许关闭现有文档,则阻止创建新文件。

void CMyApp::OnFileNew()
{
    CMyDoc* pDoc = CMyDoc::GetDoc();
    if (pDoc != NULL && pDoc->closeDocument())
        // user has vetoed the close - can't create new one
        return;
    // no document currently open, or we succesfully closed it
    CWinAppEx::OnFileNew();
}

最后,closeDocument()功能符合上述链接:

BOOL CMyDoc::closeDocument()
{
    if (!SaveModified())
    {
        // User has vetoed the close, return error
        return TRUE;
    }
    else
    {
        // OK to close
        OnCloseDocument();
        return FALSE;
    }
}