在我告诉大家怎么样修改MFC浏览程序中文件读写对话框的缺省设置之前呢,我们应该先知道MFC是怎么样显示 文件打开和文件保存对话框的。如果你选择了文件菜单中的打开,那么就会有一个消息发送给CWinApp::OnFileOpen,通过一个成员变量 m_pDocManager(一个指向CDocManager 对象的指针)来调用CDocManager::OnFileOpen,那么函数就会调用CDocManager的虚函数 DoPromptFileName,成功后再调用CWinApp::OpenDocumentFile函数,这个文件对话框就是在 DoPromptFileName的虚函数中显示的。当我们打开的是保存对话框时,文件保存(或另存为)命令消息就会发给CDocument:: OnFileSave (or CDocument::OnFileSaveAs),在这2种情况下,CDocument::DoSave函数都会被调用。最后,如果文件名是空的,那么 CDocument::DoSave就会调用CWinApp::DoPromptFileName,使得成员变量m_pDocManager有效,并且调 用CDocManager::DoPromptFileName来显示保存对话框。
那么现在大家都明白了,CDocManager::DoPromptFileName函数(注意它是一个虚函数)就是负责显示标准的文件打开和保存对话框的(可是有一个BOOL变量来决定显示哪一个对话框的)。
现在看起来,这好象对改变默认的对话框设置没什么用。你可能也没有考虑过在类CDocManager中的DoPromptFileName函 数,或者不知道怎么改,来使用你自己的CDocManager类。那么你不用急,下面的代码就是告诉你怎么自定义CDocManager。
// CDocManager class declaration //
class CDocManagerEx : public CDocManager { DECLARE_DYNAMIC(CDocManagerEx)
// Construction public: CDocManagerEx();
// Attributes public:
// Operations public:
// Overrides // helper for standard commdlg dialogs virtual BOOL DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate);
// Implementation public: virtual ~CDocManagerEx(); };
// DocManager.cpp : implementation file //
#include "stdafx.h" #include "PreviewFileDlg.h" #include "DocManager.h" // the header with the class declaration
#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif
static void AppendFilterSuffix(CString& filter, OPENFILENAME& ofn, CDocTemplate* pTemplate, CString* pstrDefaultExt) { ASSERT_VALID(pTemplate); ASSERT_KINDOF(CDocTemplate, pTemplate);
CString strFilterExt, strFilterName; if (pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt) && !strFilterExt.IsEmpty() && pTemplate->GetDocString(strFilterName, CDocTemplate::filterName) && !strFilterName.IsEmpty()) { // a file based document template - add to filter list #ifndef _MAC ASSERT(strFilterExt[0] == '.'); #endif if (pstrDefaultExt != NULL) { // set the default extension #ifndef _MAC *pstrDefaultExt = ((LPCTSTR)strFilterExt) + 1; // skip the '.' #else *pstrDefaultExt = strFilterExt; #endif ofn.lpstrDefExt = (LPTSTR)(LPCTSTR)(*pstrDefaultExt); ofn.nFilterIndex = ofn.nMaxCustFilter + 1; // 1 based number }
// add to filter filter += strFilterName; ASSERT(!filter.IsEmpty()); // must have a file type name filter += (TCHAR)'/0'; // next string please #ifndef _MAC filter += (TCHAR)'*'; #endif filter += strFilterExt; filter += (TCHAR)'/0'; // next string please ofn.nMaxCustFilter++; } }
/ // CDocManagerEx
IMPLEMENT_DYNAMIC(CDocManagerEx, CDocManager)
CDocManagerEx::CDocManagerEx() { }
CDocManagerEx::~CDocManagerEx() { }
BOOL CDocManagerEx::DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate) { CPreviewFileDlg dlgFile(bOpenFileDialog); // this is the only modified line!
CString title; VERIFY(title.LoadString(nIDSTitle));
dlgFile.m_ofn.Flags |= lFlags;
CString strFilter; CString strDefault; if (pTemplate != NULL) { ASSERT_VALID(pTemplate); AppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate, &strDefault); } else { // do for all doc template POSITION pos = m_templateList.GetHeadPosition(); BOOL bFirst = TRUE; while (pos != NULL) { CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos); AppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate, bFirst ? &strDefault : NULL); bFirst = FALSE; } }
// append the "*.*" all files filter CString allFilter; VERIFY(allFilter.LoadString(AFX_IDS_ALLFILTER)); strFilter += allFilter; strFilter += (TCHAR)'/0'; // next string please #ifndef _MAC strFilter += _T("*.*"); #else strFilter += _T("****"); #endif strFilter += (TCHAR)'/0'; // last string dlgFile.m_ofn.nMaxCustFilter++;
dlgFile.m_ofn.lpstrFilter = strFilter; #ifndef _MAC dlgFile.m_ofn.lpstrTitle = title; #else dlgFile.m_ofn.lpstrPrompt = title; #endif dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);
BOOL bResult = dlgFile.DoModal() == IDOK ? TRUE : FALSE; fileName.ReleaseBuffer(); return bResult; }
以上代码是从MFC原代码中完整的拷贝过来的,当中只有一行需要改:对话框的声明(当然,由于这是CFileDialog的子类,你可以有更多 的修改权),而且对于标准对话框来说,还应该有预览功能。AppendFilterSuffix函数是从DoPromptFileName中被调用的,原 代码可以从你的工程中获得。如果你想显示打开和保存对话框,你可以使用bOpenFileDialog参数,TRUE表示对话框是打开对话框,反之,亦 然。
当然我们也可以使用我们自己定义的CDocManagerEx类来代替原来的CDocManager类, CWinApp是通过成员变量m_pDocManager来使用文档管理器,所以我们必须正确的初始化这个变量。有必要特别关注一下在CWinApp:: AddDocTemplate中CWinApp创建对象的原代码,这其中有一个很普通的函数调用,我们把它给忽略了,那就是CWinApp:: InitInstance函数。当m_pDocManager参数是NULL的时候,CWinApp::AddDocTemplate函数只是创建 CDocManager对象,那么一旦m_pDocManager指针被正确的初始化,CWinApp::AddDocTemplate函数也就能够被正 确的调用了。因此,这最后一步就是在调用CWinApp::AddDocTemplate之前就初始化成员变量m_pDocManager,以达到我们想 要的样子。(当然你也不一定得调用CWinApp::AddDocTemplate,而是直接调用m_pDocManager-> AddDocTemplate也行) 以下就是代码:
BOOL COurApp::InitInstance() { // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need.
#ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif
// Change the registry key under which our settings are stored. // You should modify this string to be something appropriate // such as the name of your company or organization. SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
// Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views.
CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_DIBTYPE, RUNTIME_CLASS(COurDoc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame RUNTIME_CLASS(COurView)); ASSERT(m_pDocManager == NULL); m_pDocManager = new CDocManagerEx; m_pDocManager->AddDocTemplate(pDocTemplate); // or just AddDocTemplate(pDocTemplate);
// create main MDI Frame window CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame;
// Enable drag/drop open m_pMainWnd->DragAcceptFiles();
// Enable DDE Execute open EnableShellOpen(); RegisterShellFileTypes(TRUE);
// Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line if (!ProcessShellCommand(cmdInfo)) return FALSE;
// The main window has been initialized, so show and update it. pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow();
return TRUE; }