1. 程式人生 > >MFC 多文件中同時開啟多個文件

MFC 多文件中同時開啟多個文件

MFC多文件中的開啟繼承自CWinAppEx中的函式OnFileOpen(),這一點在CXXX.cpp中可以看到。比如如下:

// CCVMFCApp

BEGIN_MESSAGE_MAP(CCVMFCApp, CWinAppEx)
	ON_COMMAND(ID_APP_ABOUT, &CCVMFCApp::OnAppAbout)
	// 基於檔案的標準文件命令
	ON_COMMAND(ID_FILE_NEW, &CWinAppEx::OnFileNew)
	ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen)
	// 標準列印設定命令
	ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinAppEx::OnFilePrintSetup)
END_MESSAGE_MAP()

中的ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen)

它預設的只能開啟一個文件,那如果想開啟多個文件腫麼辦呢?

這裡給一個輔助類MutiOpenDocManager,程式碼如下:

MutiOpenDocManager.h:

// MutiOpenDocManager.h: interface for the CMutiOpenDocManager class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_MUTIOPENDOCMANAGER_H__8E7F5957_C207_4C9E_BA92_979203C32025__INCLUDED_)
#define AFX_MUTIOPENDOCMANAGER_H__8E7F5957_C207_4C9E_BA92_979203C32025__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CMutiOpenDocManager : public CDocManager  
{
public:
	virtual BOOL DoPromptFileNames(CStringList& fileNames,UINT nIDSTitle,DWORD lFlags,BOOL bOpenFileDialog,CDocTemplate* pTemplate);
	virtual void OnFileOpen();
	CMutiOpenDocManager();
	virtual ~CMutiOpenDocManager();
    void AppendFilterSuffix(CString &filter, OPENFILENAME &ofn, CDocTemplate *pTemplate, CString *pstrDefaultExt);

};

#endif // !defined(AFX_MUTIOPENDOCMANAGER_H__8E7F5957_C207_4C9E_BA92_979203C32025__INCLUDED_)

MutiOpenDocManager.cpp:
// MutiOpenDocManager.cpp: implementation of the CMutiOpenDocManager class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MutiOpenDocManager.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMutiOpenDocManager::CMutiOpenDocManager()
{

}

CMutiOpenDocManager::~CMutiOpenDocManager()
{

}

void CMutiOpenDocManager::OnFileOpen()
{
	CStringList newNames;
	if(!DoPromptFileNames(newNames,AFX_IDS_OPENFILE,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_ALLOWMULTISELECT,TRUE,NULL))
		return;
	POSITION pos=newNames.GetHeadPosition();
	while(pos)
	{
		CString newName=newNames.GetNext(pos);
		AfxGetApp()->OpenDocumentFile(newName);
	}

}

BOOL CMutiOpenDocManager::DoPromptFileNames(CStringList& fileNames, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate *pTemplate)
{
	CFileDialog dlgFile(bOpenFileDialog);

	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

	CString strFileNames;
	dlgFile.m_ofn.lpstrFile=strFileNames.GetBuffer(2048);
	dlgFile.m_ofn.nMaxFile=2048;
	BOOL bResult=dlgFile.DoModal()==IDOK?TRUE:FALSE;
	strFileNames.ReleaseBuffer();
	if(!bResult)
		return FALSE;//取消開啟檔案操作
	//將檔名拷貝到一個字串列表中
	POSITION pos=dlgFile.GetStartPosition();
	while(pos)
	{
		fileNames.AddTail(dlgFile.GetNextPathName(pos));
	}
	return
		TRUE;
}

//下面的函式是DoPromptFileNames函式中需要呼叫的模組函式
void CMutiOpenDocManager::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
		ASSERT(strFilterExt[0] == '.');
		if (pstrDefaultExt != NULL)
		{
			// set the default extension
			*pstrDefaultExt = ((LPCTSTR)strFilterExt) + 1;  // skip the '.'
			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
		filter += (TCHAR)'*';
		filter += strFilterExt;
		filter += (TCHAR)'\0';  // next string please
		ofn.nMaxCustFilter++;
	}
}


然後再在CXXX.cpp的一個位置插入一句話!至關重要:
BOOL CCVMFCApp::InitInstance()
{
	// 如果一個執行在 Windows XP 上的應用程式清單指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本來啟用視覺化方式,
	//則需要 InitCommonControlsEx()。否則,將無法建立視窗。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 將它設定為包括所有要在應用程式中使用的
	// 公共控制元件類。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinAppEx::InitInstance();

	// 初始化 OLE 庫
	if (!AfxOleInit())
	{
		AfxMessageBox(IDP_OLE_INIT_FAILED);
		return FALSE;
	}
	AfxEnableControlContainer();
	// 標準初始化
	// 如果未使用這些功能並希望減小
	// 最終可執行檔案的大小,則應移除下列
	// 不需要的特定初始化例程
	// 更改用於儲存設定的登錄檔項
	// TODO: 應適當修改該字串,
	// 例如修改為公司或組織名
	SetRegistryKey(_T("應用程式嚮導生成的本地應用程式"));
	LoadStdProfileSettings(4);  // 載入標準 INI 檔案選項(包括 MRU)

	InitContextMenuManager();

	InitKeyboardManager();

	InitTooltipManager();
	CMFCToolTipInfo ttParams;
	ttParams.m_bVislManagerTheme = TRUE;
	theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
		RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);

	// 註冊應用程式的文件模板。文件模板
	// 將用作文件、框架視窗和檢視之間的連線
	CMultiDocTemplate* pDocTemplate;
	m_pDocManager = new CMutiOpenDocManager;//注意必須在此位置新增此句

	pDocTemplate = new CMultiDocTemplate(IDR_CVMFCTYPE,
		RUNTIME_CLASS(CCVMFCDoc),
		RUNTIME_CLASS(CChildFrame), // 自定義 MDI 子框架
		RUNTIME_CLASS(CCVMFCView));
	if (!pDocTemplate)
		return FALSE;
	AddDocTemplate(pDocTemplate);

	// 建立主 MDI 框架視窗
	CMainFrame* pMainFrame = new CMainFrame;
	if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
	{
		delete pMainFrame;
		return FALSE;
	}
	m_pMainWnd = pMainFrame;
	// 僅當具有後綴時才呼叫 DragAcceptFiles
	//  在 MDI 應用程式中,這應在設定 m_pMainWnd 之後立即發生


	// 分析標準外殼命令、DDE、開啟檔案操作的命令列
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);


	// 排程在命令列中指定的命令。如果
	// 用 /RegServer、/Register、/Unregserver 或 /Unregister 啟動應用程式,則返回 FALSE。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;
	// 主視窗已初始化,因此顯示它並對其進行更新
	pMainFrame->ShowWindow(m_nCmdShow);
	pMainFrame->UpdateWindow();

	return TRUE;
}

注意45行的那句話,這是因為在建立類例項的時候將文件類定義為MutiOpenDocManager類,就可以使用其中的開啟函數了。

當然,如果工程是對話方塊就更好辦了,直接把onopen函式寫成這樣即可開啟多個文件:

void CCFileDialogST_demoDlg::OnOpen() 
{
	CFileDialogST	dlg(TRUE, NULL, NULL, /*OFN_HIDEREADONLY | */OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT, _T("All files\0*.*\0"), this);
	CString			sPathName;
	int				nRetValue;

	nRetValue = dlg.DoModal();
	if (nRetValue == IDOK)
	{
		POSITION	Pos;

		Pos = dlg.GetStartPosition();
		while (Pos != NULL)
		{
			sPathName = dlg.GetNextPathName(Pos);
			MessageBox(sPathName, _T("GetNextPathName"), MB_ICONINFORMATION);
		} 
	} // if
} // End of OnOpen