MFC打开大文档

时间:2015-05-25 10:57:38

标签: c++ mfc

我有一个单文档界面(SDI)Microsoft基础类(MFC)应用程序,必须加载一个大文档文件(大约需要2分钟)。出于这个原因,我打开文档时,我的应用程序仍然没有响应。

但是,我希望我的应用在打开文档时能够快速响应。问题是,如果我尝试在线程上加载我的文档,我的OnopenDocument函数(在我的文档中)将在我实际打开文档之前返回:

BOOL CmodguiDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
  if (!CDocument::OnOpenDocument(lpszPathName))
    return FALSE;
  start_tread(_open_doc); // just an example
  return TRUE; // Will return before the document will actually be open
}

我怎样才能做到非锁定但只在文档实际打开后返回?或者我如何在加载文档时至少使我的应用程序响应?

由于

2 个答案:

答案 0 :(得分:6)

创建线程后返回是OK。您应该为文档定义状态,例如loadingloaded。启动线程时,状态应为loading。视图应该查看状态并相应地显示。当线程完成加载文档时,它应该向文档发送一条消息。在处理程序中,将状态设置为loaded并调用UpdateAllViews()以使视图有机会使用新文档数据进行更新。

示例:这将打印" loading"当文档正在加载和加载时#34;并在视图中完成后加载。

enter image description here

在resource.h中:

#define IDD_NotifyDocumentFinished        101

在文件标题中:

public:
   enum DocState
   {
      None,
      Failed,
      Loading,
      Loaded
   };

   DocState GetDocState() const {return m_state;}
private:
   DocState m_state;
   void StartLoading();

在文件实施中:

BOOL CMFCDocViewAsyncDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
   if(!CDocument::OnOpenDocument(lpszPathName))
      return FALSE;   

   m_state = Loading;

   StartLoading();

   return TRUE;
}

UINT LongRunningFunction(LPVOID param)
{
   Sleep(3000);

   HWND hWnd = AfxGetApp()->m_pMainWnd->GetSafeHwnd();

   NMHDR hdr = {hWnd, IDD_NotifyDocumentFinished, 0};
   ::SendMessage(hWnd, WM_NOTIFY, 0, reinterpret_cast<LPARAM>(&hdr));

   return 0;
}

void CMFCDocViewAsyncDoc::StartLoading()
{
   AfxBeginThread(&LongRunningFunction, nullptr);
}

BOOL CMFCDocViewAsyncDoc::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
   if(HIWORD(nCode) == WM_NOTIFY)
   {
      WORD wCode = LOWORD(nCode);
      AFX_NOTIFY * notify = reinterpret_cast<AFX_NOTIFY*>(pExtra);
      if(notify->pNMHDR->idFrom == IDD_NotifyDocumentFinished)
      {
         m_state = Loaded;
         UpdateAllViews(nullptr);
      }
   }

   return TRUE;
}

在视图中:

void CMFCDocViewAsyncView::OnDraw(CDC* pDC)
{
    CMFCDocViewAsyncDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    CMFCDocViewAsyncDoc::DocState state = pDoc->GetDocState();
   CString sstate;
   switch(state)
   {
   case CMFCDocViewAsyncDoc::None:
      sstate = "None";
      break;
   case CMFCDocViewAsyncDoc::Failed:
      sstate = "Failed";
      break;
   case CMFCDocViewAsyncDoc::Loading:
      sstate = "Loading";
      break;
   case CMFCDocViewAsyncDoc::Loaded:
      sstate = "Loaded";
      break;
   }
   pDC->TextOut(50, 50, sstate);
}

更新:此处还可以查看类似的,更详细的示例http://www.codeproject.com/Articles/14706/Notifying-the-Document

答案 1 :(得分:1)

当需要两分钟才能加载某些东西时,有两个原因:

  1. 你在加载时做了些蠢事,例如在索引或图形渲染等数据上运行昂贵的算法。如果将数据存储在容器中,分配的开销也可能变得很大。如果是这种情况,则仅按需执行它们或在后台异步执行这些操作。例如,您可以在完成后通知主线程(运行UI的主线程)以显示渲染的图形。
  2. 数据非常大。在这种情况下,您无论如何都必须重新考虑如何访问此数据,因为任何操作都可能很昂贵。您最好的选择是使用异步模型,例如向模型发送请求以执行某些操作。然后,模型向UI发送响应以显示数据。在这种情况下,您需要考虑如何使用户透明。一种方法是在更改请求后使显示区域变暗,并且只在响应或进度条之后将其变亮。