2.2--当用户每次创建一个新文档时,如何管理 多文档模板 而不用弹出对话框?.......包含2.6的内容

   一旦用户开始使用多于一个的文档模板对象,MFC就会弹出一个New对话框,让用户选择需要的文档模板类型。当在应用程序的InitInstance()函数中调用AddDocTemplate()来注册多个文档模板对象时,MFC无法知道应该使用哪一个文档模板对象来完成用户的“File->New”请求。因此,MFC弹出一个对话框,该对话框列出了 各种注册过的文档模板对象 以允许用户指出应该使用哪一个来调用CDocTemplate::OpenDocumentFile(),来创建一个新文档,以下MFC的源码,有助于理解这种逻辑:

 

当应用程序启动时,在InitInstance()中由标准AppWizard生成的代码ProcessShellCommand()将直接调用CWinApp::OnFileNew(),调用顺如下:

[cpp]  view plain  copy
  1. CWinApp::OnFileNew()->CDocManager::OnFileNew()  
  2. Void CWinApp::OnFileNew()  
  3. {  
  4.       if(m_pDocManager!=NULL)  
  5.       {  
  6.             m_pDocManager->OnFileNew();//m_pDocManager为CDocManager类型  
  7.       }  
  8. }  
  9. CDocManager::OnFileNew()  
  10. {  
  11.       //1、如果没有注册文档模板,提示错误  
  12.       if( m_templateList.IsEmpty() )  
  13.       {  
  14.             TRACE0("ERROR:no document templates registered with CWinApp./n");  
  15.             AfxMessageBox("AFX_IDP_FAILED_TO_CREATE_DOC");  
  16.             return ;  
  17.       }  
  18.       //2、默认选择第一个文档模板对象  
  19.       CDocTemplate* pTemplate=(CDocTemplate*)m_templateList.GetHead();  
  20.       //3、如何有多个注册过的文档模板对象,则弹出“New”对话框  
  21.       if( m_templateList.GetCount() > 1)  
  22.       {  
  23.             //显示对话框提示用户从多个文档模板中选择  
  24.             CNewTypeDlg dlg(&m_templateList);  
  25.             int nID=dlg.DoModal();  
  26.             if(nID==IDOK)  
  27.                   pTemplate=dlg.m_pSelectedTemplate;//4、存储所选择的模板对象的指针  
  28.             else  
  29.                   return;  
  30.       }  
  31.       //5、使用所选择的 文档模板对象 来创建新文档、框架窗口和视图  
  32.       pTemplate->OpenDocumentFile(NULL);  
  33. }  
 

应用程序启动时,如果不想弹出对话框(直接用用户希望的 文档模板 创建新的空文档) 供用户选择文档模板,遵循以下步骤:

 

第一步:在应用程序的InitInstance()函数中创建各种文档模板对象,并把指向每个对象的指针存储在 应用程序类 的成员变量中。

 

第二步:使用ClassWizard在 应用程序类中 增加“File->New”菜单命令的句柄,在句柄内,从存储的 文档模板对象的指针 中选择你希望的文档模板对象指针,传递一个NULL参数来请求创建一个新(空)文档,如下:

void CTestApp::OnFileNew() 
{
       m_ptDefaultTemplate->OpenDocumentFile(NULL);
}

上面解决方案第二步时,标准的MFC消息映射机制 能够保证 在用户选择File->New菜单命令时调用自己的句柄( CMyApp::OnFileNew() ),而不是默认的CWinApp::OnFileNew()函数。

上面代码段中的CNewTypeDlg类在其表中只显示那些文档模板资源ID的fileNewName字串不为空的文档模板对象。如果只有一个文档模板对象满足这一条件,那么就自动返回该对象,作为所“选择”的模板对象,而不显示对话框。为了更好的理解这种行为,看一下CNewTypeDlg()的伪代码,程序清单如下:

[cpp]  view plain  copy
  1. BOOL CNewTypeDlg::OnInitDialog()  
  2. {  
  3.     //1、------得到对话框上的列表框的指针  
  4.     CListBox* pListBox = (CListBox*)GetDlgItem(AFX_IDC_LISTBOX);  
  5.     ASSERT(pListBox != NULL);  
  6.     // 使用文档模板填充列表  
  7.     pListBox->ResetContent();  
  8.     //2、------遍历应用程序的文档模板表  
  9.     POSITION pos = m_pList->GetHeadPosition();  
  10.     //通过名称在表中增加所有的CDocTemplates  
  11.     while (pos != NULL)  
  12.     {  
  13.         //3、------对每一个文档模板对象  
  14.         CDocTemplate* pTemplate = (CDocTemplate*)m_pList->GetNext(pos);  
  15.         ASSERT_KINDOF(CDocTemplate, pTemplate);  
  16.         //4、在把字符串添加到列表框中之前,检查“fileNewName”字串是否为空  
  17.         CString strTypeName;  
  18.         if (pTemplate->GetDocString(strTypeName, CDocTemplate::fileNewName) &&  
  19.            !strTypeName.IsEmpty())  
  20.         {  
  21.             // 增加到列表框  
  22.             int nIndex = pListBox->AddString(strTypeName);  
  23.             if (nIndex == -1)  
  24.             {  
  25.                 EndDialog(-1);  
  26.                 return FALSE;  
  27.             }  
  28.             pListBox->SetItemDataPtr(nIndex, pTemplate);  
  29.         }  
  30.     }  
  31.     int nTemplates = pListBox->GetCount();  
  32.     if (nTemplates == 0)  
  33.     {  
  34.         //5、如果为空,则list->error!  
  35.         TRACE0("Error: no document templates to select from!/n");  
  36.         EndDialog(-1); // abort  
  37.     }  
  38.     else if (nTemplates == 1)  
  39.     {  
  40.         // 6、如果只有一个,则自动选择这个文档模板对象 并赋值给item,不显示对话框  
  41.         m_pSelectedTemplate = (CDocTemplate*)pListBox->GetItemDataPtr(0);  
  42.         ASSERT_VALID(m_pSelectedTemplate);  
  43.         ASSERT_KINDOF(CDocTemplate, m_pSelectedTemplate);  
  44.         EndDialog(IDOK);    // 完成  
  45.     }  
  46.     else  
  47.     {  
  48.         // 把所选择的模板对象设置为第一个  
  49.         pListBox->SetCurSel(0);  
  50.     }  
  51.     //至此,将出现New对话框  
  52.     return CDialog::OnInitDialog();  
  53. }  
 

 

      每次当启动一个标准AppWizard生成的应用程序时,MFC就会自动的创建一个新(空)文档,同时还有关联的视图和框架窗口。你可能会很想知道,这个空文档是在代码的什么位置被创建的。同时,如果在应用程序启动时不初始创建任何文档?

如果不想再在应用程序启动时打开一个新(空)文档应遵循以下步骤:

[cpp] view plain copy
  1. 在InitInstance()函数中修改代码如下:  
  2. BOOL CTestApp::InitInstance()  
  3. {  
  4.        // ......  
  5.        // 解析 标准shell命令、DDE、打开文档 的命令行   
  6.       CCommandLineInfo cmdInfo;  
  7.       //取消默认的OnFileNew调用  
  8.       cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;  
  9.       ParseCommandLine(cmdInfo);  
  10.       // 分派命令行中确定的命令  
  11.       if (!ProcessShellCommand(cmdInfo))  
  12.             return FALSE;  
  13.       //......  
  14. }  
 

解释:

从MFC4.0版本开始,在应用程序启动时,程序在何处初始化新文档就不是非常明显了。你可能理解最好要调用CWinApp::OnFileNew(),但是这种调用来自于何处呢?实际上,导致CWinApp::OnFileNew()调用的整个过程都隐藏在这3行代码中:

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);//遍历命令行,搜寻以字符'/'或'-'开头的选项,根据找到的命令行参数,设置cmdInfo对象的成员变量

if(!processShellCommand(cmdInfo))//该函数根据cmdInfo中的m_nShellCommand变量 进行不同的函数调用

       return false;

      1、以上代码在堆栈中创建了一个名为cmdInfo的CCommandLineInfo对象,MFC将用该对象分析各种转换开关,并把对象的信息存储在该cmdInfo对象的public成员变量中,其中的各种转换开关可能出现在应用程序的命令行中。

      CCommandLineInfo类的定义如下:

      class CCommandLineInfo

      {

           //......

           enum {FileNew , FileOpen , FilePrint , FilePrintTo , FileDDE , AppUnregistr ,

                 FileNothing=-1 }m_nShellCommand;

          //......

      };

 

      2、cmdInfo对象创建时调用该类的(CCommandLineInfo)构造函数,该构造函数初始化m_nShellCommand成员,赋值CCommandLineInfo::FileNew;

 

      3、CWinApp::ParseCommandLine(cmdInfo)函数遍历命令行,搜寻以字符‘/’或 ‘-’开头的选项。对每一个找到的命令行参数

      ParseCommandLine()就对CmdInfo对象应用CCommandLineInfo::ParaseParam()方法,该方法根据各种命令行参数设置CmdInfo对象的成员变量,这些参数由PraseCommandLine()传送。只有在命令行中找到实际参数时,才改变m_nShellCommand成员,否则m_nShellCommand保留它上一次的值(即在构造函数中设置的值CCommandLineInfo::FileNew)。

 

      4、CWinApp::ParseCommandLine(cmdInfo)函数返回后CmdInfo对象作为一个参数调用ProcessShellCommand(cmdInfo)函数,该函数执行基于cmdInfo.m_nShellCommand值的相应动作。最常发生的动作如下表所示:

cmdInfo.m_nShellCommand的数值                               ProcessShellCommand()进行的函数调用

CCommandLineInfo::FileNew                                      CWinApp::OnFileNew();//这个函数不是虚函数

CCommandLineInfo::FileOpen                                     OpenDocumentFile(cmdInfo.m_strFileName);

CCommandLineInfo::FilePrint                                      m_pMainWnd->SendMessage(WM_COMMAND,

CCommandLineInfo::FilePrintTo                                        ID_FILE_PRINT_DIRECT);

CCommandLineInfo::FileNothing                                 None

因此,可以看出cmdInfo对象的成员变量m_nShellCommand在第2步中,被初始化为了FileNothing,最终导致了ProcessShellCommand()内部调用什么也不做,正好达到了我们的目的。

你可能感兴趣的:(管理,文档,mfc,对话框)