在单文档里如何关闭当前打开的文件?

时间:2022-06-01 20:08:43
我想在单文档里实现多文档里的文件关闭功能,即关闭当前打开的文件,而不关闭当前应用程序,我该怎么弄?

7 个解决方案

#1


ding

#2


SDI中我该怎么关闭当前打开的文档,而不关闭当前程序,

#3


这个问题我研究了一下,还是比较复杂的。
首先,如果只是实现“怎么关闭当前打开的文档,而不关闭当前程序”,还是比较简单的:
在菜单中添加一个“关闭文件”菜单,菜单ID选择ID_FILE_CLOSE,这是一个预定义的ID,也可以自己添加一个ID。在文档类中添加菜单消息响应:
void C...Doc::OnClose()
{
// TODO: 在此添加命令处理程序代码
if (!SaveModified())
return;

BOOL bAutoDelete = m_bAutoDelete;
m_bAutoDelete = FALSE; // don't destroy document while closing views
while (!m_viewList.IsEmpty())
{
// get view attached to the document
CView* pView = (CView*)m_viewList.GetHead();
ASSERT_VALID(pView);
pView->DestroyWindow();
}
m_bAutoDelete = bAutoDelete;

// clean up contents of document before destroying the document itself
DeleteContents();

// delete the document if necessary
if (m_bAutoDelete)
delete this;
}
这些代码是综合了CDocument::OnFileClose()和CDocument::OnCloseDocument()两个函数修改的,主要目的是实现关闭文档和视图而不关闭框架。

#4


接下来的问题是这样关闭了视图之后,默认的单文档框架类没有绘制客户区,因此比较难看(试一下就知道了)。
这个问题比较简单,重载框架类的OnEraseBkgnd()函数自己绘制一个背景就可以了:

BOOL C...Frame::OnEraseBkgnd(CDC* pDC)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    CRect rcClient;
    GetClientRect(rcClient);
    pDC->FillSolidRect(rcClient, GetSysColor(COLOR_APPWORKSPACE));
    return TRUE;

    //return CFrameWnd::OnEraseBkgnd(pDC);
}
如果要效果好一些,可以像MDI一样在客户区创建一个窗口来绘制背景。

#5


但是还有一个严重的问题,SDI的在新建的时候会创建一个新的框架窗口。所以如果用上面的方法来关闭文档,再新建一个文档就会出来一个新的框架窗口,而旧的又不会关闭。
解决这个问题稍微复杂一些。
我们可以重载文档模板。
从CSingleDocTemplate继承一个CSingleDocTemplateEx类,在
C...App::InitInstance()中将
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CShowBitmapDoc),
        RUNTIME_CLASS(CShowBitmapFrame),       // 主 SDI 框架窗口
        RUNTIME_CLASS(CShowBitmapView));
替换为:
    CSingleDocTemplateEx* pDocTemplate;
    pDocTemplate = new CSingleDocTemplateEx(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CShowBitmapDoc),
        RUNTIME_CLASS(CShowBitmapFrame),       // 主 SDI 框架窗口
        RUNTIME_CLASS(CShowBitmapView));
要注意:不要忘了添加CSingleDocTemplateEx的头文件;
CSingleDocTemplateEx类的构造函数和析构函数按照CSingleDocTemplate类改写一下,然后重载CSingleDocTemplateEx::OpenDocumentFile()函数:
CDocument* CSingleDocTemplateEx::OpenDocumentFile(LPCTSTR lpszPathName,
    BOOL bMakeVisible)
    // if lpszPathName == NULL => create new file of this type
{
    CDocument* pDocument = NULL;
    CFrameWnd* pFrame = NULL;
    BOOL bCreated = FALSE;      // => doc and frame created
    BOOL bWasModified = FALSE;
    pFrame = (CFrameWnd*)AfxGetMainWnd();

    if (m_pOnlyDoc != NULL)
    {
        // already have a document - reinit it
        pDocument = m_pOnlyDoc;
        if (!pDocument->SaveModified())
            return NULL;        // leave the original one

        ASSERT(pFrame != NULL);
        ASSERT_KINDOF(CFrameWnd, pFrame);
        ASSERT_VALID(pFrame);
    }
    else
    {
        // create a new document
        pDocument = CreateNewDocument();
        //ASSERT(pFrame == NULL);     // will be created below
        bCreated = TRUE;
    }

    if (pDocument == NULL)
    {
        AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
        return NULL;
    }
    ASSERT(pDocument == m_pOnlyDoc);

    if (pFrame == NULL)
    {
        ASSERT(bCreated);

        // create frame - set as main document frame
        BOOL bAutoDelete = pDocument->m_bAutoDelete;
        pDocument->m_bAutoDelete = FALSE;
                    // don't destroy if something goes wrong
        pFrame = CreateNewFrame(pDocument, NULL);
        pDocument->m_bAutoDelete = bAutoDelete;
        if (pFrame == NULL)
        {
            AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
            delete pDocument;       // explicit delete on error
            return NULL;
        }
    }
    else
    {
        CCreateContext context;
        context.m_pCurrentFrame = pFrame;
        context.m_pCurrentDoc = pDocument;
        context.m_pNewViewClass = m_pViewClass;
        context.m_pNewDocTemplate = this;

        if (pFrame->CreateView(&context, AFX_IDW_PANE_FIRST) == NULL)
            return FALSE;

        //// make sure the child windows have been properly sized
        pFrame->RecalcLayout();
    }

    if (lpszPathName == NULL)
    {
        // create a new document
        SetDefaultTitle(pDocument);

        // avoid creating temporary compound file when starting up invisible
        if (!bMakeVisible)
            pDocument->m_bEmbedded = TRUE;

        if (!pDocument->OnNewDocument())
        {
            // user has been alerted to what failed in OnNewDocument
            TRACE(traceAppMsg, 0, "CDocument::OnNewDocument returned FALSE.\n");
            if (bCreated)
                pFrame->DestroyWindow();    // will destroy document
            return NULL;
        }
    }
    else
    {
        CWaitCursor wait;

        // open an existing document
        bWasModified = pDocument->IsModified();
        pDocument->SetModifiedFlag(FALSE);  // not dirty for open

        if (!pDocument->OnOpenDocument(lpszPathName))
        {
            // user has been alerted to what failed in OnOpenDocument
            TRACE(traceAppMsg, 0, "CDocument::OnOpenDocument returned FALSE.\n");
            if (bCreated)
            {
                pFrame->DestroyWindow();    // will destroy document
            }
            else if (!pDocument->IsModified())
            {
                // original document is untouched
                pDocument->SetModifiedFlag(bWasModified);
            }
            else
            {
                // we corrupted the original document
                SetDefaultTitle(pDocument);

                if (!pDocument->OnNewDocument())
                {
                    TRACE(traceAppMsg, 0, "Error: OnNewDocument failed after trying "
                        "to open a document - trying to continue.\n");
                    // assume we can continue
                }
            }
            return NULL;        // open failed
        }
        pDocument->SetPathName(lpszPathName);
    }

    CWinThread* pThread = AfxGetThread();
    ASSERT(pThread);
    if (bCreated && pThread->m_pMainWnd == NULL)
    {
        // set as main frame (InitialUpdateFrame will show the window)
        pThread->m_pMainWnd = pFrame;
    }
    InitialUpdateFrame(pFrame, pDocument, bMakeVisible);

    return pDocument;
}
这里的代码是参照CSingleDocTemplate::OpenDocumentFile()函数和CSingleDocTemplate::CreateNewDocument()、CFrameWnd::LoadFrame()改写的。
这样一来,基本很好地实现了搂主的要求。

#6


谢谢mackz 。

#7


简单的方法:
AfxGetMainWnd()->PostMessage(WM_COMMAND,ID_FILE_NEW);

#1


ding

#2


SDI中我该怎么关闭当前打开的文档,而不关闭当前程序,

#3


这个问题我研究了一下,还是比较复杂的。
首先,如果只是实现“怎么关闭当前打开的文档,而不关闭当前程序”,还是比较简单的:
在菜单中添加一个“关闭文件”菜单,菜单ID选择ID_FILE_CLOSE,这是一个预定义的ID,也可以自己添加一个ID。在文档类中添加菜单消息响应:
void C...Doc::OnClose()
{
// TODO: 在此添加命令处理程序代码
if (!SaveModified())
return;

BOOL bAutoDelete = m_bAutoDelete;
m_bAutoDelete = FALSE; // don't destroy document while closing views
while (!m_viewList.IsEmpty())
{
// get view attached to the document
CView* pView = (CView*)m_viewList.GetHead();
ASSERT_VALID(pView);
pView->DestroyWindow();
}
m_bAutoDelete = bAutoDelete;

// clean up contents of document before destroying the document itself
DeleteContents();

// delete the document if necessary
if (m_bAutoDelete)
delete this;
}
这些代码是综合了CDocument::OnFileClose()和CDocument::OnCloseDocument()两个函数修改的,主要目的是实现关闭文档和视图而不关闭框架。

#4


接下来的问题是这样关闭了视图之后,默认的单文档框架类没有绘制客户区,因此比较难看(试一下就知道了)。
这个问题比较简单,重载框架类的OnEraseBkgnd()函数自己绘制一个背景就可以了:

BOOL C...Frame::OnEraseBkgnd(CDC* pDC)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    CRect rcClient;
    GetClientRect(rcClient);
    pDC->FillSolidRect(rcClient, GetSysColor(COLOR_APPWORKSPACE));
    return TRUE;

    //return CFrameWnd::OnEraseBkgnd(pDC);
}
如果要效果好一些,可以像MDI一样在客户区创建一个窗口来绘制背景。

#5


但是还有一个严重的问题,SDI的在新建的时候会创建一个新的框架窗口。所以如果用上面的方法来关闭文档,再新建一个文档就会出来一个新的框架窗口,而旧的又不会关闭。
解决这个问题稍微复杂一些。
我们可以重载文档模板。
从CSingleDocTemplate继承一个CSingleDocTemplateEx类,在
C...App::InitInstance()中将
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CShowBitmapDoc),
        RUNTIME_CLASS(CShowBitmapFrame),       // 主 SDI 框架窗口
        RUNTIME_CLASS(CShowBitmapView));
替换为:
    CSingleDocTemplateEx* pDocTemplate;
    pDocTemplate = new CSingleDocTemplateEx(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CShowBitmapDoc),
        RUNTIME_CLASS(CShowBitmapFrame),       // 主 SDI 框架窗口
        RUNTIME_CLASS(CShowBitmapView));
要注意:不要忘了添加CSingleDocTemplateEx的头文件;
CSingleDocTemplateEx类的构造函数和析构函数按照CSingleDocTemplate类改写一下,然后重载CSingleDocTemplateEx::OpenDocumentFile()函数:
CDocument* CSingleDocTemplateEx::OpenDocumentFile(LPCTSTR lpszPathName,
    BOOL bMakeVisible)
    // if lpszPathName == NULL => create new file of this type
{
    CDocument* pDocument = NULL;
    CFrameWnd* pFrame = NULL;
    BOOL bCreated = FALSE;      // => doc and frame created
    BOOL bWasModified = FALSE;
    pFrame = (CFrameWnd*)AfxGetMainWnd();

    if (m_pOnlyDoc != NULL)
    {
        // already have a document - reinit it
        pDocument = m_pOnlyDoc;
        if (!pDocument->SaveModified())
            return NULL;        // leave the original one

        ASSERT(pFrame != NULL);
        ASSERT_KINDOF(CFrameWnd, pFrame);
        ASSERT_VALID(pFrame);
    }
    else
    {
        // create a new document
        pDocument = CreateNewDocument();
        //ASSERT(pFrame == NULL);     // will be created below
        bCreated = TRUE;
    }

    if (pDocument == NULL)
    {
        AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
        return NULL;
    }
    ASSERT(pDocument == m_pOnlyDoc);

    if (pFrame == NULL)
    {
        ASSERT(bCreated);

        // create frame - set as main document frame
        BOOL bAutoDelete = pDocument->m_bAutoDelete;
        pDocument->m_bAutoDelete = FALSE;
                    // don't destroy if something goes wrong
        pFrame = CreateNewFrame(pDocument, NULL);
        pDocument->m_bAutoDelete = bAutoDelete;
        if (pFrame == NULL)
        {
            AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
            delete pDocument;       // explicit delete on error
            return NULL;
        }
    }
    else
    {
        CCreateContext context;
        context.m_pCurrentFrame = pFrame;
        context.m_pCurrentDoc = pDocument;
        context.m_pNewViewClass = m_pViewClass;
        context.m_pNewDocTemplate = this;

        if (pFrame->CreateView(&context, AFX_IDW_PANE_FIRST) == NULL)
            return FALSE;

        //// make sure the child windows have been properly sized
        pFrame->RecalcLayout();
    }

    if (lpszPathName == NULL)
    {
        // create a new document
        SetDefaultTitle(pDocument);

        // avoid creating temporary compound file when starting up invisible
        if (!bMakeVisible)
            pDocument->m_bEmbedded = TRUE;

        if (!pDocument->OnNewDocument())
        {
            // user has been alerted to what failed in OnNewDocument
            TRACE(traceAppMsg, 0, "CDocument::OnNewDocument returned FALSE.\n");
            if (bCreated)
                pFrame->DestroyWindow();    // will destroy document
            return NULL;
        }
    }
    else
    {
        CWaitCursor wait;

        // open an existing document
        bWasModified = pDocument->IsModified();
        pDocument->SetModifiedFlag(FALSE);  // not dirty for open

        if (!pDocument->OnOpenDocument(lpszPathName))
        {
            // user has been alerted to what failed in OnOpenDocument
            TRACE(traceAppMsg, 0, "CDocument::OnOpenDocument returned FALSE.\n");
            if (bCreated)
            {
                pFrame->DestroyWindow();    // will destroy document
            }
            else if (!pDocument->IsModified())
            {
                // original document is untouched
                pDocument->SetModifiedFlag(bWasModified);
            }
            else
            {
                // we corrupted the original document
                SetDefaultTitle(pDocument);

                if (!pDocument->OnNewDocument())
                {
                    TRACE(traceAppMsg, 0, "Error: OnNewDocument failed after trying "
                        "to open a document - trying to continue.\n");
                    // assume we can continue
                }
            }
            return NULL;        // open failed
        }
        pDocument->SetPathName(lpszPathName);
    }

    CWinThread* pThread = AfxGetThread();
    ASSERT(pThread);
    if (bCreated && pThread->m_pMainWnd == NULL)
    {
        // set as main frame (InitialUpdateFrame will show the window)
        pThread->m_pMainWnd = pFrame;
    }
    InitialUpdateFrame(pFrame, pDocument, bMakeVisible);

    return pDocument;
}
这里的代码是参照CSingleDocTemplate::OpenDocumentFile()函数和CSingleDocTemplate::CreateNewDocument()、CFrameWnd::LoadFrame()改写的。
这样一来,基本很好地实现了搂主的要求。

#6


谢谢mackz 。

#7


简单的方法:
AfxGetMainWnd()->PostMessage(WM_COMMAND,ID_FILE_NEW);