博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自定义MFC打开/保存对话框的扩展名
阅读量:4108 次
发布时间:2019-05-25

本文共 7192 字,大约阅读时间需要 23 分钟。

  • “打开文件”对话框

这里的顶目名称是D-TriNet,文档扩展名是.dtn和.csv。

要让打开/保存对话框支持多个扩展名,最简单的方法是修改资源文件中的IDR_DTriNetTYPE字段:

STRINGTABLE BEGIN    IDR_MAINFRAME           "D-TriNet"    IDR_DTriNetTYPE         "\nDTriNet\nD-TriNet\nD-TriNet     Files(*.dtn;*.csv)\n.dtn;.csv\nDTriNet.Document\nD-TriNet.Document"END
这样做的不足是,文件虽然可以有多个扩展名,但仍然只分为两类:"D-TriNet Files"和"All Files"。
要想更细致地分类,需要重写相关的虚函数,具体做法不唯一,我觉得比较好的一种是重写CDocManager::DoPromptFileName。

下面的文字有些凌乱,因为它的内容是按照我的探索过程组织的。

首先考虑打开对话框。第一步是要弄清,打开对话框是什么时候(在哪)弹出来的?

默认情况下,CDTriNetApp调用CWinApp::OnFileOpen方法处理FileOpen事件:

ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)
CWinApp::OnFileOpen又调用CDocManager::OnFileOpen处理FileOpen事件:
void CWinApp::OnFileOpen(){    ENSURE(m_pDocManager != NULL);    m_pDocManager->OnFileOpen();}
CDocManager::OnFileOpen显示对话框与用户交互,然后调用CWinApp::OpenDocumentFile方法:
void CDocManager::OnFileOpen(){    // prompt the user (with all document templates)    CString newName;    if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,        OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))	return; // open cancelled    AfxGetApp()->OpenDocumentFile(newName);    // if returns NULL, the user has already been alerted}
显然,一种可能的解决办法是绕过CWinApp和CDocManager,在CDTriNetApp::OnFileOpen方法中显示自定义对话框,然后调用CWinApp::OpenDocumentFile方法。

ON_COMMAND(ID_FILE_OPEN, &CDTriNetApp::OnFileOpen)void CDTriNetApp::OnFileOpen(){    LPCTSTR szFilter = L"DTriNet文件(*.dtn)|*.dtn|CSV文件(*.csv)|*.csv|所有文件(*.*)|*.*||";       CFileDialog oFileDlg(TRUE, L".dtn", NULL, 4|2, szFilter);    if(oFileDlg.DoModal() == IDOK)        OpenDocumentFile(oFileDlg.GetFileName());     // CDTriNetApp不需要重写CWinApp::OpenDocumentFile方法}

  • “保存文件”对话框

    现在考虑保存对话框。第一步仍然是弄清,保存对话框是什么时候(在哪)弹出来的?

   分发消息时,调用了CDocument::DoFileSave虚方法:

BOOL CDocument::DoFileSave(){    DWORD dwAttrib = GetFileAttributes(m_strPathName);    if (dwAttrib & FILE_ATTRIBUTE_READONLY)    {        // we do not have read-write access or the file does not (now) exist        if (!DoSave(NULL))        {            TRACE(traceAppMsg, 0, "Warning: File save with new name failed.\n");            return FALSE;        }    }    else    {        if (!DoSave(m_strPathName))        {            TRACE(traceAppMsg, 0, "Warning: File save failed.\n");            return FALSE;        }    }    return TRUE;}

    CDocument::DoFileSave调用CDocument::DoSave,也是一个虚方法:

    (注:没有DoSaveAs方法,lpszPathName参数决定了CDocument::DoSave是表现为“保存”还是“另存为”。)

BOOL CDocument::DoSave(LPCTSTR lpszPathName, BOOL bReplace)    // Save the document data to a file    // lpszPathName = path name where to save document file    // if lpszPathName is NULL then the user will be prompted (SaveAs)    // note: lpszPathName can be different than 'm_strPathName'    // if 'bReplace' is TRUE will change file name if successful (SaveAs)    // if 'bReplace' is FALSE will not change path name (SaveCopyAs){    CString newName = lpszPathName;    if (newName.IsEmpty())    {        CDocTemplate* pTemplate = GetDocTemplate();        ASSERT(pTemplate != NULL);	      newName = m_strPathName;	              if (bReplace && newName.IsEmpty())        {            newName = m_strTitle;            	          // check for dubious filename	          int iBad = newName.FindOneOf(_T(":/\\"));	          if (iBad != -1)		            newName.ReleaseBuffer(iBad);	          // append the default suffix if there is one	          CString strExt;	          if (pTemplate->GetDocString(strExt, CDocTemplate::filterExt) &&		            !strExt.IsEmpty())	          {		            ASSERT(strExt[0] == '.');		            int iStart = 0;		            newName += strExt.Tokenize(_T(";"), iStart);	          }	      }	      if (!AfxGetApp()->DoPromptFileName(newName,	          bReplace ? AFX_IDS_SAVEFILE : AFX_IDS_SAVEFILECOPY,	          OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, FALSE, pTemplate))	          return FALSE;       // don't even attempt to save    }    CWaitCursor wait;    if (!OnSaveDocument(newName))    {	      if (lpszPathName == NULL)	      {            // be sure to delete the file	          TRY	          {		            CFile::Remove(newName);	          }	          CATCH_ALL(e)	          {		            TRACE(traceAppMsg, 0, 	                  "Warning: failed to delete file after failed SaveAs.\n");		            DELETE_EXCEPTION(e);	          }	          END_CATCH_ALL    	  }	 	      return FALSE;    }    // reset the title and change the document name    if (bReplace) 	      SetPathName(newName);    return TRUE;        // success}
    CDocument::DoSave虚方法调用CWinApp::DoPromptFileName方法弹出保存对话框,后者又调用CDocManager::DoPromptFileName虚方法(情形与打开文件时相同):
BOOL CDocManager::DoPromptFileName(CString& fileName, UINT nIDSTitle, 	  DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate){    CFileDialog dlgFile(bOpenFileDialog, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, NULL, NULL, 0);    CString title;    VERIFY(title.LoadString(nIDSTitle));    dlgFile.m_ofn.Flags |= lFlags;    CString strFilter;    CString strDefault;    if (pTemplate != NULL)    {        ASSERT_VALID(pTemplate);        _AfxAppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate, &strDefault);    }    else    {// do for all doc template        POSITION pos = m_templateList.GetHeadPosition();        BOOL bFirst = TRUE;        while (pos != NULL)        {            pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);            _AfxAppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate,bFirst ? &strDefault : NULL);            bFirst = FALSE;        }    }    // append the "*.*" all files filterCString allFilter;    VERIFY(allFilter.LoadString(AFX_IDS_ALLFILTER));    strFilter += allFilter;strFilter += (TCHAR)'\0';           // next string please    strFilter += _T("*.*");    strFilter += (TCHAR)'\0';       // last string    dlgFile.m_ofn.nMaxCustFilter++;    dlgFile.m_ofn.lpstrFilter = strFilter;    dlgFile.m_ofn.lpstrTitle = title;    dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);    INT_PTR nResult = dlgFile.DoModal();    fileName.ReleaseBuffer();    return nResult == IDOK;}
    看起来,重写CDocManager::DoPromptFileName方法比重写CDocument::DoSave方法要省事些:
BOOL CDTriNetDocMgr::DoPromptFileName(CString& fileName, UINT nIDSTitle,			DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate){    LPCTSTR strFilter = L"DTriNet文件(*.dtn)|*.dtn|CSV文件(*.csv)|*.csv|所有文件(*.*)|*.*||";    CFileDialog dlgFile(bOpenFileDialog, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, strFilter, NULL, 0);	    CString title;    VERIFY(title.LoadString(nIDSTitle));    dlgFile.m_ofn.lpstrTitle = title;    dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);    INT_PTR nResult = dlgFile.DoModal();    fileName.ReleaseBuffer();        return nResult == IDOK;}
    CDTriNetDocMgr是派生自CDocManager的类。
   
    下一步的问题是:怎么为CWinApp::m_pDocManager创建CDTriNetDocMgr对象(而非CDocManager对象)?
    m_pDocManager是在重写的CWinApp::InitInstance虚方法中创建的,具体来说,是在CWinApp::AddDocTemplate方法中创建的,CWinApp::AddDocTemplate方法在创建m_pDocManager之前会检查它是否为NULL,只有当m_pDocManager为NULL时才为它创建CDocManager对象,所以现在并不需要重写CWinApp::AddDocTemplate方法,而只需要在重写的CWinApp::InitInstance方法中、在调用CWinApp::AddDocTemplate方法之前为m_pDocManager创建CDTriNetDocMgr对象。
    一旦重写了CDocManager::DoPromptFileName方法,之前提到的自定义打开对话框文件扩展名的方法也就多此一举了,也不再需要修改资源文件中的IDR_DTriNetTYPE字段,因为无论打开还是保存对话框,最终都是由CDocManager::DoPromptFileName执行的。

转载地址:http://httsi.baihongyu.com/

你可能感兴趣的文章
基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。...
查看>>
抄书 Richard P. Stanley Enumerative Combinatorics Chapter 2 Sieve Methods
查看>>
jQuery简单的Ajax调用示例
查看>>
分享一套精美的现代 UI PSD 工具包【免费下载】
查看>>
Hover States - 有趣的用户界面及交互设计
查看>>
最新10款好看的英文字体免费下载
查看>>
Java之Elasticsearch 增删改查
查看>>
【ZOJ月赛】【树形DP】【I.Destroy】
查看>>
初窥Linux 之 我最常用的20条命令
查看>>
一、ABP框架框架摘要
查看>>
解读《TCP/IP详解》(卷1):03章:IP(网际协议)
查看>>
jquery.spinner数字智能加减插件源代码效果
查看>>
Webx之表单验证
查看>>
mysql 5.7.15 安装配置方法图文教程(转)
查看>>
腾讯云SSL证书管理
查看>>
利用StrongOD漏洞反调试
查看>>
ctime 写到文件
查看>>
css3边框背景写法及简写。待续
查看>>
Gulp前端自动化工具
查看>>
无向图最小环
查看>>