CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
最后 , 我们可以总结一下ParseCommandLine的作用 . ParseCommandLine的作用主要是分析命令行参数,如果没有命令行参数 ,ParseCommandLine()就假定用户想新建一个文档,于是设置一个FileNew命令,如果命令行参数中有一个文件名,ParseCommandLine()就假定用户想打开该文件,于是设置一个FileOpen命令。
CCommandLineInfo cmdInfo;
1: 当CCommandLineInfo cmdInfo进行定义时 , 首先调用构造函数 , 构造函数中m_nShellCommand被设置为FileNew
2: 然后执行ParseCommandLine(cmdInfo);对命令进行分析 。
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;
ParseCommandLine(cmdInfo);
默认"文档类型选择"对话框的定义为:
class CNewTypeDlg : public CDialog
可以在VC6.0安装目录的vc98/mfc/src/docmgr.cpp文件中找到. 下面将会仿照这个对话框来设计自定义的"文档类型选择"对话框, 并可以添加自己需要的各种功能。
首先观察mfc"新建文件"操作的过程源码. 对于ID_FILE_NEW消息, 利用VC6.0 IDE的搜索功能,找到: /VC98/MFC/SRC/APPDLG.CPP(25):void CWinApp::OnFileNew()如下:
void CWinApp::OnFileNew()
{
if (m_pDocManager != NULL)
m_pDocManager->OnFileNew();
}
m_pDocManager是CWinApp的成员. 类型为CDocManager*
然后继续找到: /VC98/MFC/SRC/DOCMGR.CPP(802):void CDocManager::OnFileNew()如下:
void CDocManager::OnFileNew()
{
if (m_templateList.IsEmpty())
{
TRACE0("Error: no document templates registered with CWinApp./n");
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
return;
}
CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();
if (m_templateList.GetCount() > 1)
{
// more than one document template to choose from
// bring up dialog prompting user
CNewTypeDlg dlg(&m_templateList);
int nID = dlg.DoModal();
if (nID == IDOK)
pTemplate = dlg.m_pSelectedTemplate;
else
return; // none - cancel operation
}
ASSERT(pTemplate != NULL);
ASSERT_KINDOF(CDocTemplate, pTemplate);
pTemplate->OpenDocumentFile(NULL);
// if returns NULL, the user has already been alerted
}
在这个函数中, 就可以发现CNewTypeDlg的踪迹。
工程的名字假定为My, 则我们有CMyApp派生类。
我们所需要做的工作是:
1, 在菜单中添加一个新的菜单项例如ID_FILE_NEW_1, 并添加消息响应函数例如OnFileNew1(); 或者直接为原来的ID_FILE_NEW添加消息响应函数OnFileNew. 这里采用后一种。
2, 添加CMyApp::OnFileNew()后, 不要忘记删除My.cpp中MESSAGE_MAP里的这一项:
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
3, 在CMyApp::OnFileNew()中, 把上面的CWinApp::OnFileNew()和CDocManager::OnFileNew()的代码拷贝过去, 并加以改造如下:
void CMyApp::OnFileNew()
{
// from CWinApp::OnFileNew():
if (m_pDocManager == NULL)
{
return;
}
// from CDocManager::OnFileNew():
// 由于无法访问CDocManager的保护数据成员m_templateList
// 故要使用CDocManager::GetFirstDocTemplatePosition()
// 和CDocManager::GetNextDocTemplate()接口来获得所有文档模板类指针
// 并将其添加到自定义的列表m_DocTplList中
POSITION pos = m_pDocManager->GetFirstDocTemplatePosition();
if (pos == NULL)
{
TRACE0("Error: no document templates registered with CWinApp./n");
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
return;
}
// 遍历获得各个文档模板类指针
// 注意, 在CMyApp的定义中添加成员CPtrList m_DocTplList用以放置这些指针
CDocTemplate* pTemplate = NULL;
while (pos != NULL)
{
pTemplate = m_pDocManager->GetNextDocTemplate(pos);
ASSERT(pTemplate != NULL);
this->m_DocTplList.AddTail(pTemplate);
}
// 如果文档类型超过1个则使用自定义的"文档类型选择"对话框CDlgChooseClass
// 在资源编辑器中添加一个对话框, 并创建对话框类CDlgChooseClass
// 在对话框中放置一个ListBox控件, 用来容纳多个文档类型
// 稍后有具体说明
if (m_DocTplList.GetCount() > 1)
{
CDlgChooseClass dlg(&m_DocTplList); // 输入文档模板类指针的列表
int nID = dlg.DoModal(); // 对话框CDlgChooseClass完成选择文档类型
// 并且可以有其他自定义的操作
if (nID == IDOK)
{
pTemplate = dlg.m_pSelectedTemplate;
}
else
{
m_DocTplList.RemoveAll(); // 注意: 清空自定义的列表
return; // none - cancel operation
}
}
m_DocTplList.RemoveAll(); // 注意: 清空自定义的列表
// 检查返回的值
ASSERT(pTemplate != NULL);
ASSERT_KINDOF(CDocTemplate, pTemplate);
// 选定的文档模板类: 创建新文档
pTemplate->OpenDocumentFile(NULL);
// if returns NULL, the user has already been alerted
}
接下来是设计CDlgChooseClass, 仿照CNewTypeDlg的定义进行(vc98/mfc/src/docmgr.cpp).
class CDlgChooseClass : public CDialog
{
// Construction
public:
// 修改默认构造函数, 增加一个参数CPtrList* pList
CDlgChooseClass(CPtrList* pList, CWnd* pParent = NULL);
// Dialog Data
public:
CDocTemplate* m_pSelectedTemplate; // 选定的文档模板类
//{{AFX_DATA(CDlgChooseClass)
enum { IDD = IDD_DLG_CHOOSE_CLASS };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDlgChooseClass)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
CPtrList* m_pList; // 文档模板类指针列表
// Generated message map functions
//{{AFX_MSG(CDlgChooseClass)
virtual BOOL OnInitDialog();
virtual void OnOK();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
实现OnInitDialog()和OnOk()如下:
基本上是拷贝CNewTypeDlg::OnInitDialog()和CNewTypeDlg::OnOk()的代码, 并略做修改
BOOL CDlgChooseClass::OnInitDialog()
{
// IDC_DOC_TPL_LIST是ListBox的ID
CListBox* pListBox = (CListBox*)GetDlgItem(IDC_DOC_TPL_LIST);
ASSERT(pListBox != NULL);
// fill with document templates in list
pListBox->ResetContent();
POSITION pos = m_pList->GetHeadPosition();
// add all the CDocTemplates in the list by name
while (pos != NULL)
{
CDocTemplate* pTemplate = (CDocTemplate*)m_pList->GetNext(pos);
ASSERT_KINDOF(CDocTemplate, pTemplate);
// 这里是添加fileNewName来代表各个文档模板。也可以设计其他的显示方式
CString strTypeName;
if (pTemplate->GetDocString(strTypeName, CDocTemplate::fileNewName) &&
!strTypeName.IsEmpty())
{
// add it to the listbox
int nIndex = pListBox->AddString(strTypeName);
if (nIndex == -1)
{
EndDialog(-1);
return FALSE;
}
pListBox->SetItemDataPtr(nIndex, pTemplate);
}
}
int nTemplates = pListBox->GetCount();
if (nTemplates == 0)
{
TRACE0("Error: no document templates to select from!/n");
EndDialog(-1); // abort
}
else if (nTemplates == 1)
{
// get the first/only item
m_pSelectedTemplate = (CDocTemplate*)pListBox->GetItemDataPtr(0);
ASSERT_VALID(m_pSelectedTemplate);
ASSERT_KINDOF(CDocTemplate, m_pSelectedTemplate);
EndDialog(IDOK); // done
}
else
{
// set selection to the first one (NOT SORTED)
pListBox->SetCurSel(0);
}
return CDialog::OnInitDialog();
}
void CDlgChooseClass::OnOK()
{
// TODO: Add extra validation here
CListBox* pListBox = (CListBox*)GetDlgItem(IDC_DOC_TPL_LIST);
ASSERT(pListBox != NULL);
// if listbox has selection, set the selected template
int nIndex;
if ((nIndex = pListBox->GetCurSel()) == -1)
{
// no selection
m_pSelectedTemplate = NULL;
}
else
{
m_pSelectedTemplate = (CDocTemplate*)pListBox->GetItemDataPtr(nIndex);
ASSERT_VALID(m_pSelectedTemplate);
ASSERT_KINDOF(CDocTemplate, m_pSelectedTemplate);
}
CDialog::OnOK();
}
当然, 构造函数也要注意修改:
CDlgChooseClass::CDlgChooseClass(CPtrList* pList, CWnd* pParent /* = NULL */)
: CDialog(CDlgChooseClass::IDD, pParent)
{
//{{AFX_DATA_INIT(CDlgChooseClass)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_pList = pList; // 文档模板类指针列表
m_pSelectedTemplate = NULL; // 最后选择的文档模板类
}
到这里就完成了. 进入程序, 选择"文件"-"新建", 或者直接Ctrl+N, 出来的已经是我们自定义的CDlgChooseClass对话框了, 且基本功能和原来默认的完全一样(选择文档类型). 要增加新的功能, 或者改善外观? 这就是对话框设计的问题了。