在MFC DLL中的CDialog派生对象中使用CScrollView派生对象

时间:2014-01-26 14:07:59

标签: c++ user-interface dll mfc

我希望有人向我解释为什么以下在CDialog派生对象中使用CScrollView派生对象的方法以及此方法是否存在隐藏问题。

我关注的是向CFrameWnd投射CDialog,以便使用CFrameWnd类的CreateView()方法为CDialog对象中的CScrollView对象创建文档/视图对。

我正在构建一个MFC DLL,它将提供一系列GUI功能来显示,并允许在遗留应用程序中编辑某些类型的信息,一次显示一个页面。

首先要提供一种在对话框中显示报告的方法,该对话框在可滚动组件中显示报告,允许用户查看整个报告。

考虑在CDialog派生的GUI对象中使用CSrollView派生控件,我发现了这篇文章Creating a View in Dialog (An easy way),因为我在使用CScrollView时遇到了关于CDialog关闭异常的一些问题。我还在调试输出窗口中看到“警告:创建没有CD文档的窗格”的警告。我不再见了。

使用文章中的基本概念我有一些代码,它在调试器中的Windows XP中与Visual Studio 2005一起工作正常。

我在CDialog派生类中用于OnInitDialog()初始化的代码如下所示。我首先创建文档并将文本行放入内存区域,并为CDialog派生对象的构造函数提供文档的地址m_pDocument,然后在OnInitDialog()函数中使用该文档。

BOOL CScrollReportDialog::OnInitDialog ()
{
    // Get the client area size of the dialog we are putting the
    // CScrollView into and pull the right edge in sufficient to
    // clear buttons on the right hand side of the dialog.
    RECT  rectSize;
    GetClientRect (&rectSize);
    rectSize.right -= 120;

    // allocate and set up the view document context linking the view
    // to a particular document, in our case a CScrollDocument.
    CCreateContext pContext;
    pContext.m_pCurrentDoc = m_pDocument;
    pContext.m_pNewViewClass = RUNTIME_CLASS(CScrollReport);

    // Cast the pointer to this dialog into a CFrameWnd pointer allowing
    // us to access the CFrameWnd methods.  Both CDialog and CFrameWnd are
    // derived from CWnd so we can get away with this.
    CFrameWnd* pFrameWnd = (CFrameWnd *) ((CWnd *)this);
    CScrollReport *pView = (CScrollReport *)pFrameWnd->CreateView(&pContext);
    ASSERT(pView);

    // Set an initial scroll size for the CScrollView which will be
    // modified in the OnDraw () later when presenting the actual view
    // and we have the complete document and can calculate the document's
    // scrollable size properly.
    CSize sizeTotal;
    sizeTotal.cx = rectSize.right;
    sizeTotal.cy = 1 * rectSize.bottom;
    pView->SetScrollSizes(MM_TEXT, sizeTotal);

    pView->ShowWindow(SW_NORMAL);

    /**
    * After a view is created, resize window area of the view to fit into the
    * dialog.  Since this is a CScrollView, set an initial size for the
    * size of the object being scrolled.
    */
    pView->MoveWindow(&rectSize);
    return TRUE;
}

1 个答案:

答案 0 :(得分:0)

查看CFrameWnd::CreateView()的MFC源代码,不依赖于任何CFrameWnd数据。但是,该方法的实施可能会在以后发生变化。

CFrameWnd::CreateView()的MFC源版本使用MFC动态对象创建来创建视图的实例。然后,它将视图的实际窗口创建为具有特定MFC文档/视图窗口标识符的子窗口。

我们可以实现自己的版本,而不是依赖于CFrameWnd::CreateView()来保持相同的实现。

该函数的修改部分是将CDialog对象替换为CFrameWnd对象,以便使用CreateView()实现的特定代码访问CreateView()方法,如下所示。

#if 0
    // Cast the pointer to this dialog into a CFrameWnd pointer allowing
    // us to access the CFrameWnd methods.  Both CDialog and CFrameWnd are
    // derived from CWnd so we can get away with this.
    CFrameWnd* pFrameWnd = (CFrameWnd *) ((CWnd *)this);
    CScrollReport *pView = (CScrollReport *)pFrameWnd->CreateView(&pContext);
    ASSERT(pView);
#else
    // Use the approach from CFrameWnd::CreateView() to create a view and
    // link the view with the document.  We use the dynamic CreateObject()
    // functionality to create a CScrollReport view object.  We use the
    // standard child window id for the first view of an instance of the
    // MFC document/view architecture.  We are basing this on a copy of
    // the CFrameWnd::CreateView () method from the MFC source.
    int  nID = AFX_IDW_PANE_FIRST;
    CScrollReport *pView = (CScrollReport *)pContext.m_pNewViewClass->CreateObject();
    ASSERT(pView);
    ASSERT_KINDOF(CWnd, pView);

    if (pView) {
        if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), this, nID, &pContext)) {
            TRACE0("Warning: could not create view for dialog.\n");
            return FALSE;
        }
    } else {
        TRACE0("Warning: dynamic create of CScrollView for dialog failed.\n");
        return FALSE;
    }
#endif

编辑 Jan28

遇到的一个问题是,对话框有时会显示在全屏应用程序的下方。结果是没有看到带有CScrollView的对话框。

有关使用SetWindowPos()函数的示例,请参阅stackoverflow Always in Front Dialogs。我在返回之前在OnInitDialog()方法中使用它。