0

平台/工具链/工具包:Windows 10、Visual Studio 2019、MFC。

我想要做的是能够在事件处理程序(如双击处理程序或菜单或按钮处理程序)中将我的程序中的界面在单个 CChildView(派生自 CWnd)到包含两个窗格的 CSplitterWnd 之间来回更改(一个 CChildView 和一个基于 CListview 的类)。

这是对文件查看器的重写,我省略了所有特定于应用程序的内容。这个想法是,在一种模式下,用户只查看文件,而在另一种模式下,用户正在查看左侧的文件系统目录列表窗格和右侧的窗格,其中包含在文件列表中选择的任何文件。所以很常见的成语。

我有下面的代码。

两种 UI 模式(如果您愿意的话)是:

CSplitterWnd m_wndSplitter;
CChildView    m_simpleView;

我所做的是创建一个隐藏窗口,它成为未显示视图的父级,而我的 CMainFrame 是显示的任何视图的父级。为了隐藏 m_wndSplitter,我将其父级设置为隐藏窗口,然后隐藏它及其窗格的视图,最后将简单的 m_simpleView 父级设置为 CMainFrame 并显示它。切换以显示拆分器,步骤相反。

一对事件处理程序连接到视图菜单中的条目。一个隐藏简单的 m_simpleView 并显示 m_wndSplitter;另一个处理程序隐藏 m_wndSplitter 并显示简单的 m_simpleView。

我正在寻找有关我的事件处理程序的实现、我对 SetParent() 和 ShowWindow() 的使用的反馈。以我的经验,MFC 可以在释放和咬人之前的最后一秒跳出深奥的微妙之处。而这种切换 UI 视图的解决方案似乎太容易了……

所以,问题:

  • 这个方案合理吗?
  • MFC 框架在事件处理程序执行后不知道默认或活动视图是什么时,是否存在一些微妙之处?
  • 我是不是很简单(太聪明了)?

摘自股票发行的新项目向导为具有拆分窗口的 MFC、SDI、非文档/视图项目生成的代码:

主框架.h:

class CMainFrame : public CFrameWnd {
  public:
    CMainFrame() noexcept;
  protected: 
    DECLARE_DYNAMIC(CMainFrame)

  // Attributes
  protected:
    CSplitterWnd m_wndSplitter;
    CChildView    m_simpleView;
    CWnd offscreen_window;

  // ... generated boilerplate code ...
  // ... generated boilerplate code ...
  // ... generated boilerplate code ...

  public:
    afx_msg void OnViewSplitter();
    afx_msg void OnViewSingle();
};

主框架.cpp:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;

    offscreen_window.Create(L"STATIC", _T("Hi"), WS_CHILD,  CRect(0, 0, 20, 20), this, 1234);

    if (!m_simpleView.Create(nullptr, nullptr, AFX_WS_DEFAULT_VIEW, CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, nullptr)) {
        TRACE0("Failed to create view window\n");
        return -1;
    }
    if (!m_wndStatusBar.Create(this))   {
        TRACE0("Failed to create status bar\n");
        return -1;      // fail to create
    }
    m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
    return 0;
}

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)  {
    if (!m_wndSplitter.CreateStatic(this, 1, 2, WS_CHILD | WS_VISIBLE))
        return FALSE;
    if (   !m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CChildListView), CSize(100,0), pContext)
        || !m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CChildView), CSize(0, 0), pContext)) 
    {
        m_wndSplitter.DestroyWindow();
        return FALSE;
    }
    m_wndSplitter.SetParent(&offscreen_window);
    return TRUE;
}


void CMainFrame::OnViewSplitter() {
    // show the splitter with a pair of views
    m_simpleView.ShowWindow(SW_HIDE);
    m_simpleView.SetParent(&offscreen_window);

    m_wndSplitter.SetParent(this);
    m_wndSplitter.ShowWindow(SW_SHOW);
    m_wndSplitter.GetPane(0, 0)->ShowWindow(SW_SHOW);
    m_wndSplitter.GetPane(0, 1)->ShowWindow(SW_SHOW);
}


void CMainFrame::OnViewSingle() {
    // show the single view 
    m_wndSplitter.GetPane(0, 0)->ShowWindow(SW_HIDE);
    m_wndSplitter.GetPane(0, 1)->ShowWindow(SW_HIDE);
    m_wndSplitter.ShowWindow(SW_HIDE);
    m_wndSplitter.SetParent(&offscreen_window);

    m_simpleView.SetParent(this);
    m_simpleView.ShowWindow(SW_SHOW);
}

CChildView.h(.cpp 是项目向导的所有样板):

class CChildView : public CWnd
{
    DECLARE_DYNCREATE(CChildView)
// Construction
public:
    CChildView();

// Attributes
public:

// Operations
public:

// Overrides
    protected:
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

// Implementation
public:
    virtual ~CChildView();

    // Generated message map functions
protected:
    afx_msg void OnPaint();
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};

CChildListView.h

#pragma once
#include <afxcview.h>

// CChildListView view

class CChildListView : public CListView
{
    DECLARE_DYNCREATE(CChildListView)

protected:
    CChildListView();           // protected constructor used by dynamic creation
    virtual ~CChildListView();

public:
#ifdef _DEBUG
    virtual void AssertValid() const;
#ifndef _WIN32_WCE
    virtual void Dump(CDumpContext& dc) const;
#endif
#endif

protected:
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};
4

0 回答 0