在做一个文本编辑器,需要能对至少两种文件进行编辑(如.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不胜熟悉,也许哪位高人一看便知,希望大家多多帮忙啊。(有兴趣的朋友可以留下邮箱,我给您发过去,运行一下可能会对问题比较清楚)
用的是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不胜熟悉,也许哪位高人一看便知,希望大家多多帮忙啊。(有兴趣的朋友可以留下邮箱,我给您发过去,运行一下可能会对问题比较清楚)
{
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()返回的文档指针,如果返回没有文档的话自己创建一个...........
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);
}
敢问还有没有哪位大哥知道这个问题呢?
“如何新建一个呢?如何新建一个视图、文档、并把他们联系在一起呢?烦高手指点啊!”
一般上来说 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处理代码就行了!
特别注意: 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();
}上面和上一帖的代码是匆忙写成的, 可能存在有错误的地方!
写OnFileOpen是为了重载它,也包括OnFileNew,想让程序运行时调用我自己写的打开或新建对话框,如:
CFileDialog dlg(true,NULL,NULL,OFN_OVERWRITEPROMPT,"ASM Files(*.asm)|*.asm|C Files(*.c)|*.c||",NULL);可能正如你说的,我应该把重载函数写在App里吧。
至于你说的方法,我之前也想过,但两种文件只是关键字不一样,对于视图什么的都一样,所以就不想建立两个文档模板了。不过,这样看来,这种方法虽然有点复杂化了,但调理上更清楚了,我试试吧!谢谢指点啊!那再问一下,多个文档的话,在Frame、或是CChildFrame中要想得到某一种文档类型的指针,要怎么做呢?
比如现在C文件的视图正处于活跃状态,我想得到ASM文件文档的指针,以写入数据,最后将ASM文件以其视图显示出来,怎么做呢?麻烦了。
代码太多就不发上来了,可以研究一下。但在这要提醒一下,因为你用了两个类型,保存的时候文档模板是不知道怎么处理的,
所以要自己加上些代码。下面是保存文件的一部分代码, 主要是在 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)) 检查是否要找的文档模板;