拆分窗口中的无限数量的可切换视图






3.67/5 (36投票s)
2004年2月20日
4分钟阅读

98453

2789
允许用户拥有与拆分窗格关联的无限数量的视图
引言
本文详细介绍如何使用我的 CMultiSplitterView
类,该类允许在一个拆分器窗格内实现多个可切换视图。在上图中,灰色区域是第一个视图。通过转到菜单栏并单击“视图 > 显示第二个视图”,程序将动态地将第一个视图更改为第二个视图。
此类允许您通过一个函数调用切换到您创建的任何视图,无需任何额外操作!添加视图也像调用一个函数一样简单。现在,让我们进入细节...
代码详情
一切的核心都位于 MultiSplitterView.cpp 和 MultiSplitterView.h 文件中。
在此处将视图添加到拆分器窗格
bool CMultiSplitterView::AddSwitchableView(UINT id,
CRuntimeClass * pView,
CCreateContext* pContext,
CRect & size, bool isFirstView, UINT altId)
{
CWnd* pWin;
DWORD style;
pWin = (CWnd*) pView->CreateObject();
style = WS_CHILD ;
if (isFirstView)
{
style |= WS_VISIBLE ;
}
pWin->Create(NULL, NULL, style, size , this, id, pContext);
if (isFirstView) // id provided is usually diff. so use alternate
{
views[pWin] =altId ;
}
else
{
views[pWin] = id;
}
return true;
}
第一个参数是您与视图关联的视图 ID,以便可以轻松查找。第二个参数是通过调用 RUNTIME_CLASS(SomeViewClass)
创建的,该函数返回 CRuntimeClass
类的指针。第三个参数是在 CMainFrame
类中由 OnCreateClient
函数提供的 CCreateContext
。第四个参数是窗口的尺寸。现在,最后两个参数是可选的,并且仅在首次调用 AddSwitchableView()
时使用。因为第一个参数的 ID 是第一个视图将设置为的窗格的 ID,所以我需要传递用户将视图关联的实际 ID,因此最后一个参数称为 altId
。
好的,我们传入所有这些参数,然后创建一个类型为传入的运行时类的对象,并将其转换为其基类 CWnd
以便创建和存储。请注意,在对 CWnd
对象调用 Create 时,我始终使用传入的 ID 和此指针,该指针将视图与拆分器关联起来。然后,我将 CWnd
的指针存储在 map<> 中作为“键”,并将 ID 或备用 ID 作为值用于后续查找。
接下来,我们需要动态切换视图,以便一个显示而另一个隐藏。
以下代码处理任意数量视图的切换
bool CMultiSplitterView::SwitchView(UINT id, int paneRow, int paneCol)
{
CView* pOldView = (CView*) GetPane(paneRow, paneCol); // get current view
if (pOldView == NULL) // serious prob
{
return false;
}
CView* pNewView = (CView*) GetDlgItem(id); // get new view
if(pNewView == NULL ) // bad view id or this is already the view we requested
{
return false;
}
CFrameWnd * mainWnd = (CFrameWnd *)AfxGetMainWnd();
if (mainWnd == NULL) // serious prob
{
ASSERT(false);
return false;
}
if(mainWnd->GetActiveView() == pOldView)
mainWnd->SetActiveView(pNewView);
pNewView->ShowWindow(SW_SHOW);
pOldView->ShowWindow(SW_HIDE);
pNewView->SetDlgCtrlID( IdFromRowCol(paneRow, paneCol));
CWnd * bCwnd =(CWnd *)pOldView; // upcast to CWnd ptr
if (views.find(bCwnd) == views.end()) // search for CWnd ptr
{
return false;
}
UINT oldId = views[bCwnd]; // get id of this view for future lookup
pOldView->SetDlgCtrlID(oldId); // reset view id, so we can look it up
}
好的,现在用户或 GUI 已调用 SwitchView()
并传入了某个 ID 以及视图所属拆分器的行和列。我们首先使用用户提供的行和列获取当前视图的指针。接下来,我们获取新视图(即将显示的与传入 ID 关联的视图)。我们验证它们不是 NULL
,然后从主窗口获取 CFrameWnd
指针。然后,我们比较活动视图与旧视图,看它们是否相同(它们应该是相同的),然后将新视图设置为请求的视图。在隐藏和显示旧视图和新视图之后,将新视图的 ID 设置为与视图关联的行和列的 ID 至关重要,因为它是窗格的子窗口。然后,我们在 map<> 中查找旧视图的 ID,因为它的控件 ID 仍然是 IdFromRowCol()
中的 ID。然后,我们将控件 ID 重置为 map<> 中存储的值,以便稍后可以检索视图指针。
如何使用
在您的 CMainFrame
中,您必须首先包含 MultiViewSplitter.h 头文件。接下来,声明一个类型为 CMultiViewSplitter
的成员 var
。接下来,在 CMainFrame
中的 OnCreateClient()
中
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
CRect r;
GetWindowRect(r);
m_SplitterFirst.CreateStatic(this,1,2);
m_SplitterFirst.CreateView(0,0, RUNTIME_CLASS( CSomeView) ,
CSize(r.Width() *0.14, r.Height()), pContext);
m_SplitterSeconde.CreateStatic(&m_SplitterFirst, 2, 1, WS_CHILD | WS_VISIBLE |
WS_BORDER, m_SplitterFirst.IdFromRowCol(0, 1));
/******************* Add switchable views **************************/
m_SplitterSeconde.AddSwitchableView(m_SplitterSeconde.IdFromRowCol(0, 0),
RUNTIME_CLASS(CFirstView) ,pContext, CRect(0,0,r.Width(), r.Height()) ,
true , FIRST_VIEW);
m_SplitterSeconde.AddSwitchableView(SECOND_VIEW,
RUNTIME_CLASS( CSecondView), pContext,
CRect(0,0,r.Width(), r.Height()*0.60) );
/******************************************************************/
...
}
对于此示例,真正重要的是“添加可切换视图”注释之后的部分。我首先将第一个拆分器 m_SplitterFirst
拆分为 2 列。然后,我将第二个拆分器创建为第一个拆分器的子对象,并将其拆分为两行。现在,这一切对您来说都不重要,因为您可以根据自己的需要拆分窗口。
对于首次调用 AddSwitchableView()
,请务必使用调用 m_SplitterSeconde.IdFromRowCol(x, x)
提供的拆分器 ID,并将备用视图 ID 作为最后一个参数,将 true
作为倒数第二个参数,以指示这是第一个视图。
在 RUNTIME_CLASS( x )
的调用内部,添加封装您的视图的任何类的类名。
哇,就是这样!现在,无论何时您想动态切换视图,只需调用 SwitchView( x )
,其中 x
是视图的 ID。请下载示例演示项目以全面了解其工作原理。
如果有人给本文投了低分(低于 4 或 5),您能否告诉我您给的评分原因以及我如何做得更好。欢迎提供建议、好评或指出问题。感谢您的时间。
其他有用函数
GetViewPtr(UINT id, int paneRow, int paneCol)
- 获取与拆分器关联的基类CWnd
指针
许可证
本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。
作者可能使用的许可证列表可以在此处找到。