2010.8.9 CEditView的使用(未完成)

一、当在MFC程序中,一个view上,根据菜单,展现不同的view 的时候。比如Outlook类似程序,根据左边的Pane,右边显示不同的view 。

     如果右边要显示的是一个EditView,如何实现呢?

 

疑问:

1、加入新建一个类,继承之CEditView,那么需要document配合吗?

 

参考:http://www.skinplusplus.com/bbs/archiver/tid-114896.html

http://www.vckbase.com/study/article/vc_chap/chap5_3.htm

1、CView继承类,和其他窗口类的区别,很重要的就是对CDocument类和CFrameWnd类的操作,

2、还应注意,默认的从CView继承的类,其构造函数和析构函数是protected的,需要修改成public。

 

 

 

新建一个应用程序,应用程序的View继承之CEditView类;
一、假若要显示一个txt文本文件,可以使用CString存储文本文件(CString最大可以存储2G大小的内容)
    并在OnUpdate()中显示文本内容
void CEditViewView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
 CString content;
 CStdioFile file;
 CString fileName=_T("D:\\析构顺序.txt");
 if (file.Open(fileName,CFile::modeRead|CFile::typeBinary))
 {
  TCHAR buf[512];
  memset(buf,0,sizeof(buf));
  int len=512-2;
  LPTSTR pText=file.ReadString(buf,len); // A null character ('\0') is appended.
  while (NULL!=pText)
  {
   content+=pText;
   pText=file.ReadString(buf,len);
  }
  file.Close();
 }
 this->SetWindowText(content);
}
请注意工程的编码方式,否则某些txt文件打开会是乱码。

二、文件修改后如何保存?
1、假若什么都没做,并在view中更改了文件内容,然后点击保存(菜单或者工具栏),会触发下列流程:
(1)、保存菜单对应 ID_FILE_SAVE 消息,该消息在
       ON_COMMAND(ID_FILE_SAVE, &CDocument::OnFileSave)   (见doccore.cpp文件)
(2)、触发OnFileSave函数
void CDocument::OnFileSave()
{
 DoFileSave();
}
(3)、触发DoFileSave函数
BOOL CDocument::DoFileSave()
{
 DWORD dwAttrib = GetFileAttributes(m_strPathName);
 if (dwAttrib & FILE_ATTRIBUTE_READONLY)
 {
  // we do not have read-write access or the file does not (now) exist
  if (!DoSave(NULL))
  {
   TRACE(traceAppMsg, 0, "Warning: File save with new name failed.\n");
   return FALSE;
  }
 }
 else
 {
  if (!DoSave(m_strPathName))
  {
   TRACE(traceAppMsg, 0, "Warning: File save failed.\n");
   return FALSE;
  }
 }
 return TRUE;
}
(4)、触发DoSave函数
BOOL CDocument::DoSave(LPCTSTR lpszPathName, BOOL bReplace)
 // Save the document data to a file
 // lpszPathName = path name where to save document file
 // if lpszPathName is NULL then the user will be prompted (SaveAs)
 // note: lpszPathName can be different than 'm_strPathName'
 // if 'bReplace' is TRUE will change file name if successful (SaveAs)
 // if 'bReplace' is FALSE will not change path name (SaveCopyAs)
{
 CString newName = lpszPathName;
 if (newName.IsEmpty())
 {
  CDocTemplate* pTemplate = GetDocTemplate();
  ASSERT(pTemplate != NULL);

  newName = m_strPathName;
  if (bReplace && newName.IsEmpty())
  {
   newName = m_strTitle;
   // check for dubious filename
   int iBad = newName.FindOneOf(_T(":/\\"));
   if (iBad != -1)
    newName.ReleaseBuffer(iBad);

   // append the default suffix if there is one
   CString strExt;
   if (pTemplate->GetDocString(strExt, CDocTemplate::filterExt) &&
     !strExt.IsEmpty())
   {
    ASSERT(strExt[0] == '.');
    int iStart = 0;
    newName += strExt.Tokenize(_T(";"), iStart);
   }
  }

  if (!AfxGetApp()->DoPromptFileName(newName,
    bReplace ? AFX_IDS_SAVEFILE : AFX_IDS_SAVEFILECOPY,
    OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, FALSE, pTemplate))
   return FALSE;       // don't even attempt to save
 }

 CWaitCursor wait;

 if (!OnSaveDocument(newName))
 {
  if (lpszPathName == NULL)
  {
   // be sure to delete the file
   TRY
   {
    CFile::Remove(newName);
   }
   CATCH_ALL(e)
   {
    TRACE(traceAppMsg, 0, "Warning: failed to delete file after failed SaveAs.\n");
    DELETE_EXCEPTION(e);
   }
   END_CATCH_ALL
  }
  return FALSE;
 }

 // reset the title and change the document name
 if (bReplace)
  SetPathName(newName);

 return TRUE;        // success
}
(5)、AfxGetApp()->DoPromptFileName(newName,
    bReplace ? AFX_IDS_SAVEFILE : AFX_IDS_SAVEFILECOPY,
    OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, FALSE, pTemplate)
弹出保存窗口
(6)、
BOOL CWinApp::DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags,
 BOOL bOpenFileDialog, CDocTemplate* pTemplate)
  // if pTemplate==NULL => all document templates
{
 ENSURE(m_pDocManager != NULL);
 return m_pDocManager->DoPromptFileName(fileName, nIDSTitle, lFlags,
  bOpenFileDialog, pTemplate);
}
(7)、如果选择保存,将会触发
OnSaveDocument(newName)操作,该操作最终导致序列化。
BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName)
{
 ENSURE(lpszPathName);

 CFileException fe;
 CFile* pFile = NULL;
 pFile = GetFile(lpszPathName, CFile::modeCreate |
  CFile::modeReadWrite | CFile::shareExclusive, &fe);

 if (pFile == NULL)
 {
  ReportSaveLoadException(lpszPathName, &fe,
   TRUE, AFX_IDP_INVALID_FILENAME);
  return FALSE;
 }

 CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete);
 saveArchive.m_pDocument = this;
 saveArchive.m_bForceFlat = FALSE;
 TRY
 {
  CWaitCursor wait;
  Serialize(saveArchive);     // save me
  saveArchive.Close();
  ReleaseFile(pFile, FALSE);
 }
 CATCH_ALL(e)
 {
  ReleaseFile(pFile, TRUE);

  TRY
  {
   ReportSaveLoadException(lpszPathName, e,
    TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);
  }
  END_TRY
  DELETE_EXCEPTION(e);
  return FALSE;
 }
 END_CATCH_ALL

 SetModifiedFlag(FALSE);     // back to unmodified

 return TRUE;        // success
}
(8)、真正执行保存操作
void CEditViewDoc::Serialize(CArchive& ar)
{
 // CEditView contains an edit control which handles all serialization
 reinterpret_cast<CEditView*>(m_viewList.GetHead())->SerializeRaw(ar);
}
2、假若什么都没做,并在view中更改了文件内容,然后关闭应用程序,会触发如下流程
(1)、点击关闭,会触发VM_Close消息,并在CFrameWnd中捕获
void CFrameWnd::OnClose()
{
 if (m_lpfnCloseProc != NULL)
  (*m_lpfnCloseProc)(this);

 // Note: only queries the active document
 CDocument* pDocument = GetActiveDocument();
 if (pDocument != NULL && !pDocument->CanCloseFrame(this))
 {
  // document can't close right now -- don't close it
  return;
 }
(2)、当前文档会判断是否需要可以关闭主框架
pDocument->CanCloseFrame(this)

BOOL CDocument::CanCloseFrame(CFrameWnd* pFrameArg)
 // permission to close all views using this frame
 //  (at least one of our views must be in this frame)
{
 ASSERT_VALID(pFrameArg);
 UNUSED(pFrameArg);   // unused in release builds

 POSITION pos = GetFirstViewPosition();
 while (pos != NULL)
 {
  CView* pView = GetNextView(pos);
  ASSERT_VALID(pView);
  CFrameWnd* pFrame = pView->GetParentFrame();
  // assume frameless views are ok to close
  if (pFrame != NULL)
  {
   // assumes 1 document per frame
   ASSERT_VALID(pFrame);
   if (pFrame->m_nWindow > 0)
    return TRUE;        // more than one frame refering to us
  }
 }

 // otherwise only one frame that we know about
 return SaveModified();
}
(3)、SaveModified()判断文档是否有修改
BOOL CDocument::SaveModified()
{
 if (!IsModified())
  return TRUE;        // ok to continue

 // get name/title of document
 CString name;
 if (m_strPathName.IsEmpty())
 {
  // get name based on caption
  name = m_strTitle;
  if (name.IsEmpty())
   ENSURE(name.LoadString(AFX_IDS_UNTITLED));
 }
 else
 {
  // get name based on file title of path name
  name = m_strPathName;
  AfxGetFileTitle(m_strPathName, name.GetBuffer(_MAX_PATH), _MAX_PATH);
  name.ReleaseBuffer();
 }

 CString prompt;
 AfxFormatString1(prompt, AFX_IDP_ASK_TO_SAVE, name);
 switch (AfxMessageBox(prompt, MB_YESNOCANCEL, AFX_IDP_ASK_TO_SAVE))
 {
 case IDCANCEL:
  return FALSE;       // don't continue

 case IDYES:
  // If so, either Save or Update, as appropriate
  if (!DoFileSave())
   return FALSE;       // don't continue
  break;

 case IDNO:
  // If not saving changes, revert the document
  break;

 default:
  ASSERT(FALSE);
  break;
 }
 return TRUE;    // keep going
}
请注意,switch (AfxMessageBox(prompt, MB_YESNOCANCEL, AFX_IDP_ASK_TO_SAVE))弹出对话框,询问是否保存。
case IDYES:
  // If so, either Save or Update, as appropriate
  if (!DoFileSave())
执行DoFileSave()操作,转到1中的流程。

 

请思考:

3、如果我想在保存的时候,不需要弹出询问的对话框,直接保存文件,该如何做呢?

4、为什么有的程序在退出的时候,点击关闭按钮,不会提示保存文档呢?


 

posted @ 2010-08-09 17:57  pjh123  阅读(2187)  评论(0编辑  收藏  举报