只允许在 MFC MDI 应用程序中打开一个 CDocument
Allow only one CDocument to be opened in an MFC MDI app
如问题所述,我试图在 MFC MDI 应用程序中一次只允许一个文档。由于许多(不相关的)原因,我没有使用 SDI 文档模板。很多地方评论说这样做,但我不知道如何做。最接近的是 link: 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)。在用户选择(或取消)新文档之前关闭文档。
所以我有一个有效的解决方案,我认为解释它很有用。我希望这对某人有用。我花了很长时间研究 MFC(这是一件好事),现在明白为什么上面的解决方案 link 不再是 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
所以唯一可以挂钩的地方是覆盖 CMyApp
class.
中的 OpenDocumentFile
来自对话框
这更容易 - 有多个地方可以挂接,但在开始时挂接将不允许用户显示文件打开对话框并取消它,同时保持现有文档打开。
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 class 并重写一些功能,但这是一项艰巨的工作。 '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()
函数按照上面的link:
BOOL CMyDoc::closeDocument()
{
if (!SaveModified())
{
// User has vetoed the close, return error
return TRUE;
}
else
{
// OK to close
OnCloseDocument();
return FALSE;
}
}
有一种更简单的方法,不需要挂钩所有这些函数。将一些 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);
}
如果您有打开的文档,则文件-新建和文件-打开将被禁用。关闭文档后,您可以打开或创建一个新文档。
如问题所述,我试图在 MFC MDI 应用程序中一次只允许一个文档。由于许多(不相关的)原因,我没有使用 SDI 文档模板。很多地方评论说这样做,但我不知道如何做。最接近的是 link: 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)。在用户选择(或取消)新文档之前关闭文档。
所以我有一个有效的解决方案,我认为解释它很有用。我希望这对某人有用。我花了很长时间研究 MFC(这是一件好事),现在明白为什么上面的解决方案 link 不再是 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
所以唯一可以挂钩的地方是覆盖 CMyApp
class.
OpenDocumentFile
来自对话框
这更容易 - 有多个地方可以挂接,但在开始时挂接将不允许用户显示文件打开对话框并取消它,同时保持现有文档打开。
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 class 并重写一些功能,但这是一项艰巨的工作。 '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()
函数按照上面的link:
BOOL CMyDoc::closeDocument()
{
if (!SaveModified())
{
// User has vetoed the close, return error
return TRUE;
}
else
{
// OK to close
OnCloseDocument();
return FALSE;
}
}
有一种更简单的方法,不需要挂钩所有这些函数。将一些 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);
}
如果您有打开的文档,则文件-新建和文件-打开将被禁用。关闭文档后,您可以打开或创建一个新文档。