MFCで作成される通常のアプリケーションはドキュメント-ビュー構造を持っています。
ドキュメントはひとつの拡張子を持っていて、ファイルオープンダイアログではその拡張子の
ファイルのみが表示されるので、ユーザの好みに応じてファイル
種別を選択することができません。これは、独自のファイルフォーマットに加え一般的な
ファイルフォーマット(たとえばテキストファイル)を取り扱いたいといった極めて一
般的な要求があるときに困ってしまいます。
本Tipsでは CDocManager をサブクラス化することで、上記の機能をインプリメントする
方法について説明します。
MFCではファイルオープン・セーブの時にコモンダイアログを用いてファイル名
の取得を行いますが、この部分の処理は、"mfc\src\Docmgr.cpp": BOOL CDocManager::
DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog,
CDocTemplate* pTemplate) で行われます。この中で、通常はアプリケーションが保持する
ドキュメントテンプレートから各ドキュメントクラスを参照し、ドキュメントクラスが
もつフィルターストリングをコモンダイアログのフィルターストリングに追加していきます。
その後すべてのファイル(*.*)のためのフィルタストリングを追加し、コモンダイアログ
をオープンしています。
この DoPromptFileName は仮想関数なので、これをオーバーライドすることで
フィルタストリングを追加することができます。
インプリメント手順は以下のようになります。
以下、詳細に述べます(ここでは CWinApp の派生クラスを CMyApp としている)。
class CWinApp : public CWinThread { DECLARE_DYNAMIC(CWinApp) public: CDocManager* m_pDocManager; : };
m_pDocManager の初期化は CMyApp::InitInstance() からコールされる CMyApp::AddDocTemplate() で行われる。したがって、クラスの定義に AddDocTemplate を加え、ポインタの初期化部分で クラス名を派生クラスに置き換える。
class CMyApp : public CWinApp { public: : virtual void AddDocTemplate(CDocTemplate* pTemplate); // 追加 : }; void CMyApp::AddDocTemplate(CDocTemplate* pTemplate) // 追加 { if (m_pDocManager == NULL) m_pDocManager = new CMyDocManager; // クラス名を CDocManager から変更 m_pDocManager->AddDocTemplate(pTemplate); }
CDocManager の派生クラスを定義する。
// // DoPromptFileName をオーバーライドするためのクラス // class CMyDocManager : public CDocManager { DECLARE_DYNAMIC(CMyDocManager) public: // helper for standard commdlg dialogs virtual BOOL DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate); };
インプリメントを行う。
コードのほとんどはMFCのソースそのままである。ここで追加した部分はボールドのところのみ。
ここでは、無条件に "Text Files (*.txt)\0*.txt\0" を追加している。
(ほんとはストリングリソースにすべき)
//--------------------------------------------------------------------------- // Implementation of CMyDocManager class //--------------------------------------------------------------------------- IMPLEMENT_DYNAMIC( CMyDocManager, CDocManager ) 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++; } } BOOL CMyDocManager::DoPromptFileName(CString& fileName, 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 "*.txt" text files filter // 追加した部分 strFilter += _T("Text Files (*.txt)"); strFilter += (TCHAR)'\0'; // next string please strFilter += _T("*.txt"); strFilter += (TCHAR)'\0'; // last string dlgFile.m_ofn.nMaxCustFilter++; // 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; }
前のTips 次のTips 津田伸秀 のホームページに戻る。
Last Updated on 22-Aug-1996, Copyright (c) 1996 by Nobuhide Tsuda, All Right Reserved.
このホームページに関するご質問、ご要望、バグレポート等は
Nobuhide_Tsuda@jsn.justnet.or.jp までメールをいただければ幸いです。