在做一个文本编辑器,需要能对至少两种文件进行编辑(如.cpp和.asm)。(默认的打开和新建文件不能满足要求,即使修改字符串表也只能在过滤器加一个后缀名。)所以本人考虑重载open和new操作,已经忙了好一段时间,有个问题一直不能得意解决,请高手帮帮忙啊,救命啊!
用的是MDI,但没有建两个文档模板,只是用了一个全局的标志位表示是哪种文件,即:采用多视的思路。打开一个文件时,会根据后缀名设置标志位,然后调用不同的关键字集高亮显示关键字;新建也是如此,就像VC一样,让用户选一种文件,同时设置标志位,然后新建!思路就是这样的。
我已经基本实现,但为什么会这样:
要是没有这句:cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;(即程序初始会打开一个视图)的话新建和打开都是没问题的,但要是加了上边那句(即程序初始只有菜单没有视图)的话,打开和新建就会导致程序崩溃。(我怀疑是不是子框架已经销毁了啊)实在搞不懂,请高人帮忙啊!我的重载函数:
void CSampleView::OnFileOpen() 
{
CString m_szFilePathName; //图像文件路径
CString m_szFileName;
CFileDialog dlg(true,NULL,NULL,OFN_OVERWRITEPROMPT,"ASM Files(*.asm)|*.asm|C++ Files(*.c++)|*.cpp||",NULL);
if(dlg.DoModal()==IDOK)
{
m_szFileName = dlg.GetFileName();
m_szFilePathName = dlg.GetPathName();
CString type=dlg.GetFileExt();//得到文件扩展名
if(type=="asm")
isAsm=true;
else
isAsm=false;
}
else
return; CSampleDoc* pDoc = GetDocument();
pDoc->SetTitle(m_szFileName);
pDoc->OnOpenDocument(m_szFilePathName);
pDoc->UpdateAllViews(NULL);
}
void CSampleView::OnFileNew() 
{
CNewFileDlg nfDlg(this);
if(nfDlg.DoModal()==IDOK)
            ;
]
打开的对话框
void CNewFileDlg::OnOK() 
{
UpdateData(true);
CString m_szFilePathName;
m_szFilePathName=m_save_path;
m_szFilePathName+="\\";
        m_szFilePathName+=m_filename;

CString string;                           //从列表框中获得的字符串
int nIndex = m_NewListBox.GetCurSel();
if(nIndex!=LB_ERR)
m_NewListBox.GetText(nIndex,string);
//AfxMessageBox(string);
CString extStr;                //获得扩展名
if(string=="C File (*.c)")
{
extStr=".c";
isAsm=false;
}
else if(string=="Asm File (*.asm)")
{
extStr=".asm";
isAsm=true;
}
m_szFilePathName+=extStr; CSampleApp *theApp;
theApp=(CSampleApp   *)::AfxGetApp();   
CMainFrame   *myWin;   
        myWin=(CMainFrame   *)theApp->GetMainWnd();    CChildFrame  *myChildFrame;   
myChildFrame=(CChildFrame   *)myWin->MDIGetActive(); 
CSampleDoc   *pDoc;
pDoc=(CSampleDoc   *)myChildFrame->GetActiveView()->GetDocument();
pDoc->OnSaveDocument(m_szFilePathName);
CSampleView *pView;
pView=(CSampleView  *)myChildFrame->GetActiveView();
pView->OnFileOpen(m_szFilePathName); CDialog::OnOK();
}
代码帖的较多,其实问题没这么繁琐,由于本人对mfc不胜熟悉,也许哪位高人一看便知,希望大家多多帮忙啊。(有兴趣的朋友可以留下邮箱,我给您发过去,运行一下可能会对问题比较清楚)

解决方案 »

  1.   

    void CSampleView::OnFileOpen() 

    CString m_szFilePathName; //图像文件路径 
    CString m_szFileName; 
    CFileDialog dlg(true,NULL,NULL,OFN_OVERWRITEPROMPT,"ASM Files(*.asm)|*.asm|C++ Files(*.c++)|*.cpp||",NULL); 
    if(dlg.DoModal()==IDOK) 

    m_szFileName = dlg.GetFileName(); 
    m_szFilePathName = dlg.GetPathName(); 
    CString type=dlg.GetFileExt();//得到文件扩展名 
    if(type=="asm") 
    isAsm=true; 
    else 
    isAsm=false; 

    else 
    return; CSampleDoc* pDoc = GetDocument(); 
    pDoc->SetTitle(m_szFileName); 
    pDoc->OnOpenDocument(m_szFilePathName); 
    pDoc->UpdateAllViews(NULL); 

    需要判断getdocument()返回的文档指针,如果返回没有文档的话自己创建一个...........
      

  2.   

    我已经派生出CSampleView和CSampleDoc类了啊,麻烦你说的具体点啊
      

  3.   

    “打开”解决了:
    void CSampleView::OnFileOpen() 

             CString m_szFilePathName; //图像文件路径
    CString m_szFileName;
    CFileDialog dlg(true,NULL,NULL,OFN_OVERWRITEPROMPT,"ASM Files(*.asm)|*.asm|C Files(*.c)|*.c||",NULL);
    if(dlg.DoModal()==IDOK)
    {
    m_szFileName = dlg.GetFileName();
    m_szFilePathName = dlg.GetPathName();
    CString type=dlg.GetFileExt();//得到文件扩展名
    if(type=="asm")
    isAsm=true;
    else
    isAsm=false;
    }
    else
    return;
            //加了下面这句就没问了
    AfxGetApp()->OpenDocumentFile(m_szFilePathName);
    }
    敢问还有没有哪位大哥知道这个问题呢?
    “如何新建一个呢?如何新建一个视图、文档、并把他们联系在一起呢?烦高手指点啊!”
      

  4.   

    楼主的代码有点奇怪? 
    一般上来说 OnFileOpen 消息是 CSampleApp 响应的.
    楼主却在视图类上响应, 而 cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing.
    也就是说程序刚开始运行时是没有视图的, 
    既然没有视图又怎能响应OnFileOpen呢?
    如果已经在CSampleApp响应了, 而CSampleView::OnFileOpen又是多余的!
    现在在外面, 无法测试楼主的代码!不如楼主试试下面:
    为ASM类型建立两个类 CASMView 和 CASMDoc;
    为CPP类型建立两个类 CCPPView 和 CCPPDoc;

    BOOL CSampleApp::InitInstance()
    {
        ...
        CMultiDocTemplate *pASMTemplate = new CMultiDocTemplate(
            IDR_ASMTYPE, // ASM类型资源, 图标菜单或字符串之类的东西.
                         // 注意凡是 IDR_SampleTYPE(假如有)的资源改成 IDR_ASMTYPE,
                         // 还要把 string table 里面的 IDR_ASMTYPE 改成以下:
                         // \nSample\nASM File\nASM File (*.asm)\n.asm\nSample.Document\nSample.Document
                         // 上面字符串比较重要, 是用来确定"新建""打开""保存"的文件类型的!
            RUNTIME_CLASS(CASMDoc),
            RUNTIME_CLASS(CChildFrame),
            RUNTIME_CLASS(CASMView));
        AddDocTemplate(pASMTemplate);    CMultiDocTemplate *pCPPTemplate = new CMultiDocTemplate(
            IDR_CPPTYPE, // CPP类型资源, 同上!
                         // \nSample\nASM File\nASM File (*.asm)\n.asm\nSample.Document\nSample.Document
            RUNTIME_CLASS(CCPPDoc),
            RUNTIME_CLASS(CChildFrame),
            RUNTIME_CLASS(CCPPView));
        AddDocTemplate(pCPPTemplate);
        ...
    }

    以后在相应的C*View和C*Doc处理代码就行了!
      

  5.   

    哦,默认的只有一个 IDR_*TYPE 的, 可以自己建立所对应的资源!
    特别注意: ID_FILE_OPEN 和 ID_FILE_NEW 必须在 CSampleApp 里有响应!
    下面是项目标准的命令, 没什么特别需要就不要改
    BEGIN_MESSAGE_MAP(CSampleApp, CWinApp)
        ...
        ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew)
        ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)
        ...
    END_MESSAGE_MAP()
    非得要改就改成这样
    // Sample.h
    class CSampleApp : public CWinApp
    {
        ...
        afx_msg void OnFileOpen();
        afx_msg void OnFileNew();
        ...
    };
    // Sample.cppBEGIN_MESSAGE_MAP(CSampleApp, CWinApp)
        ...
        ON_COMMAND(ID_FILE_NEW, &CSampleApp::OnFileNew)
        ON_COMMAND(ID_FILE_OPEN, &CSampleApp::OnFileOpen)
        ...
    END_MESSAGE_MAP()void CSampleApp::OnFileOpen()
    {
        // 写入打开文件前的代码
        ...
        CWinApp::OnFileOpen();
    }void CSampleApp::OnFileNew()
    {
        // 写入新建文件前的代码
        ...
        CWinApp::OnFileNew();
    }上面和上一帖的代码是匆忙写成的, 可能存在有错误的地方!
      

  6.   

    谢谢你的耐心回答,主要是我对MFC不熟悉,所以写的代码比较奇怪!
    写OnFileOpen是为了重载它,也包括OnFileNew,想让程序运行时调用我自己写的打开或新建对话框,如:
    CFileDialog dlg(true,NULL,NULL,OFN_OVERWRITEPROMPT,"ASM Files(*.asm)|*.asm|C Files(*.c)|*.c||",NULL);可能正如你说的,我应该把重载函数写在App里吧。
    至于你说的方法,我之前也想过,但两种文件只是关键字不一样,对于视图什么的都一样,所以就不想建立两个文档模板了。不过,这样看来,这种方法虽然有点复杂化了,但调理上更清楚了,我试试吧!谢谢指点啊!那再问一下,多个文档的话,在Frame、或是CChildFrame中要想得到某一种文档类型的指针,要怎么做呢?
    比如现在C文件的视图正处于活跃状态,我想得到ASM文件文档的指针,以写入数据,最后将ASM文件以其视图显示出来,怎么做呢?麻烦了。
      

  7.   

    用一个文档模板的话也不会很难。你可以自己建立“新建”对话框类,根据自己的需要来处理结果。
    代码太多就不发上来了,可以研究一下。但在这要提醒一下,因为你用了两个类型,保存的时候文档模板是不知道怎么处理的,
    所以要自己加上些代码。下面是保存文件的一部分代码, 主要是在 CSampleDoc 类的:

    // SampleDoc.h
    class CSampleDoc : public CDocument
    {
        ...
    public:
        // DoSave 函数可以在 CDocument 找到原型。在保存文件时调用,是在打开保存文件对话框之前。
        // 重载它是为了调用自己的打开保存文件对话框。
        // lpszPathName 是文件路径名,如果文件是新建的话为 NULL. bReplace 是否替换现有文件。
        virtual BOOL DoSave(LPCTSTR lpszPathName, BOOL bReplace = TRUE);
        ...
    };// SampleDoc.cpp
    // 你最好在新建某类型文件设置一个标记,用以判断是新建什么类型。
    // 假如我现在在 CSampleApp 处设置一公共变量 m_nType, 
    // 新建 ASM 时为 TYPE_ASM, 新建 CPP 时为 TYPE_CPP.
    BOOL CSampleDoc::DoSave(LPCTSTR lpszPathName, BOOL bReplace)
    {
        if( lpszPathName == NULL ) // 判断文件是否新建的
        {
            TCHAR szPath[MAX_PATH];
            LPCTSTR pszFilter;
            DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
            switch( ((CSampleApp *)AfxGetApp())->m_nType )
            {
            case TYPE_ASM:
                pszFilter = _T("ASM文件 (*.asm)|*.asm|所有文件 (*.*)|*.*||");
                break;
            case TYPE_CPP:
                pszFilter = _T("CPP文件 (*.cpp)|*.cpp|所有文件 (*.*)|*.*||");
                break;
            default:
                ASSERT(0);
                break;
            }
            CFileDialog dlg(FALSE, NULL, NULL, dwFlags, pszFilter, NULL);
            if( dlg.DoModal() == IDOK )
            {
                CString strTemp = dlg.GetPathName();
                lstrcpy(szPath, strTemp.GetBuffer(0));
                lpszPathName = szPath;
            }
            else
                return TRUE;
        }
        return CDocument::DoSave(lpszPathName, bReplace);
    }
    至于多文档时得到其他文档指针,有几个函数:
    POSITION CWinApp::GetFirstDocTempalePosition();
    CDocTemplate * CWinApp::GetNextDocTemplate(POSITION &);
    POSITION CMultiDocTemplate::GetFirstDocPosition();
    CDocument * CMultiDocTemplate::GetNextDoc(POSITION &);
    得到 CDocument 指针后再用 CDocument::IsKindOf(RUNTIME_CLASS(C*Doc)) 检查是否要找的文档模板;