窗口靜態分割
單個分割器
聲明
首先在MainFrm.h
中聲明分割對象
CSplitterWnd m_wndSplitter;
准備視圖
從CView
或其派生類中派生四個類:CMyView1
、CMyView2
、CMyView3
、CMyView4
靜態分割窗口&添加視圖
在MainFrm.cpp
中添加虛函數OnCreateClient
,添加如下代碼
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: 在此添加專用代碼和/或調用基類
CRect rectClient;
GetClientRect(&rectClient);
if (!m_wndSplitter.CreateStatic(this, 2, 2) ||
!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CListView), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext) ||
!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CListView), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext) ||
!m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CListView), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext) ||
!m_wndSplitter.CreateView(1, 1, RUNTIME_CLASS(CListView), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext))
return FALSE;
// return CFrameWnd::OnCreateClient(lpcs, pContext);
return TRUE;
}
使視圖大小隨窗口大小改變
在MainFrm.h
中聲明變量
BOOL m_bSplitter;
在MainFrm.cpp
構造函數中初始化m_bSplitter
CMainFrame::CMainFrame() noexcept :
m_bSplitter(FALSE)
{
}
在MainFrm.cpp
虛函數OnCreateClient
窗口分割之后添加對m_bSplitter
的賦值
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: 在此添加專用代碼和/或調用基類
CRect rectClient;
GetClientRect(&rectClient);
if (!m_wndSplitter.CreateStatic(this, 2, 2) ||
!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CListView), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext) ||
!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CListView), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext) ||
!m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CListView), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext) ||
!m_wndSplitter.CreateView(1, 1, RUNTIME_CLASS(CListView), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext))
return FALSE;
m_bSplitter = TRUE; // 窗口已完成分割,視圖已經動態創建
// return CFrameWnd::OnCreateClient(lpcs, pContext);
return TRUE;
}
在MainFrm.cpp
中添加WM_SIZE
消息映射,添加如下代碼
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
// TODO: 在此處添加消息處理程序代碼
if (m_bSplitter == TRUE)
{
m_wndSplitter.SetColumnInfo(0, cx / 2, 0);
// 另外一列將自適應寬度
m_wndSplitter.SetRowInfo(0, cy / 2, 0);
// 另外一行將自適應高度
// 重新計算
m_wndSplitter.RecalcLayout();
}
}
效果圖
多個分割器
聲明
聲明兩個分割器
CSplitterWnd m_wndSplitter1; // 主分割器
CSplitterWnd m_wndSplitter2; // 子分割器
靜態分割窗口&添加視圖
在MainFrm.cpp
中修改虛函數OnCreateClient
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: 在此添加專用代碼和/或調用基類
CRect rectClient;
GetClientRect(&rectClient);
if (!m_wndSplitter1.CreateStatic(this, 2, 1) ||
!m_wndSplitter1.CreateView(0, 0, RUNTIME_CLASS(CListView), CSize(rectClient.Width(), rectClient.Height() / 2), pContext))
return FALSE;
if (!m_wndSplitter2.CreateStatic(&m_wndSplitter1, 1, 2, WS_CHILD | WS_VISIBLE, m_wndSplitter1.IdFromRowCol(1, 0)) ||
!m_wndSplitter2.CreateView(0, 0, RUNTIME_CLASS(CListView), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext) ||
!m_wndSplitter2.CreateView(0, 1, RUNTIME_CLASS(CListView), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext))
return FALSE;
m_bSplitter = TRUE; // 窗口已完成分割,視圖已經動態創建
// return CFrameWnd::OnCreateClient(lpcs, pContext);
return TRUE;
}
使視圖大小隨窗口大小改變
相應地修改OnSize
函數
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
// TODO: 在此處添加消息處理程序代碼
if (m_bSplitter == TRUE)
{
m_wndSplitter1.SetRowInfo(0, cy / 2, 0);
m_wndSplitter2.SetColumnInfo(0, cx / 2, 0);
// 重新計算
m_wndSplitter1.RecalcLayout();
m_wndSplitter2.RecalcLayout();
}
}
效果圖
視圖切換
在CMainFrame
添加切換視圖的函數BOOL CMainFrame::Switch(int nIndex)
,添加如下代碼建立框架
BOOL CMainFrame::Switch(int nIndex)
{
switch (nIndex)
{
case 0:
break;
case 1:
break;
default:
return FALSE;
}
return TRUE;
}
視圖之間的切換
聲明
CSplitterWnd m_wndSplitter;
修改相應函數
添加CMyView2和CMyView3的繪圖代碼
CMyView2
void CMyView2::OnDraw(CDC* pDC)
{
CRect rectClient;
GetClientRect(rectClient);
pDC->FillSolidRect(rectClient, RGB(255, 255, 255));
}
CMyView3
void CMyView3::OnDraw(CDC* pDC)
{
CRect rectClient;
GetClientRect(rectClient);
pDC->FillSolidRect(rectClient, RGB(0, 0, 0));
}
修改OnCreateClient函數
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: 在此添加專用代碼和/或調用基類
CRect rectClient;
GetClientRect(&rectClient);
if (!m_wndSplitter.CreateStatic(this, 1, 2) ||
!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CMyView1), CSize(rectClient.Width() / 2, rectClient.Height()), pContext) ||
!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CMyView2), CSize(rectClient.Width() / 2, rectClient.Height()), pContext))
return FALSE;
m_bSplitter = TRUE; // 窗口已完成分割,視圖已經動態創建
Switch(0); // 更改數值以獲得切換效果
// return CFrameWnd::OnCreateClient(lpcs, pContext);
return TRUE;
}
修改視圖切換函數
BOOL CMainFrame::Switch(int nIndex)
{
CRect rectClient;
GetClientRect(rectClient);
switch (nIndex)
{
case 0:
m_wndSplitter.DeleteView(0, 1);
m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CMyView2), CSize(rectClient.Width() / 2, rectClient.Height()), NULL);
m_wndSplitter.RecalcLayout();
break;
case 1:
m_wndSplitter.DeleteView(0, 1);
m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CMyView3), CSize(rectClient.Width() / 2, rectClient.Height()), NULL);
m_wndSplitter.RecalcLayout();
break;
default:
return FALSE;
}
return TRUE;
}
代碼中是通過刪除原有視圖重新建立要切換視圖的方式來實現視圖切換,如果因為數據量大,可以通過隱藏和顯示視圖來實現,這是我后來發現的方法,具體請參考我的另一篇隨筆:MFC分割窗口(CSplitterWnd)與選項卡視圖(CTabView)的混合使用
子分割器之間的切換
聲明
CSplitterWnd m_wndSplitter; // 主分割器
CSplitterWnd m_wndSplitter1; // 子分割器1
CSplitterWnd m_wndSplitter2; // 子分割器2
准備視圖
從CView
或其派生類中派生第五個類:CMyView5
修改相應函數
修改OnCreateClient函數
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: 在此添加專用代碼和/或調用基類
CRect rectClient;
GetClientRect(&rectClient);
if (!m_wndSplitter.CreateStatic(this, 1, 2) ||
!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CMyView1),CSize(rectClient.Width() / 2, rectClient.Height()),pContext))
return FALSE;
if (!m_wndSplitter1.CreateStatic(&m_wndSplitter, 2, 1, WS_CHILD) ||
!m_wndSplitter1.CreateView(0, 0, RUNTIME_CLASS(CMyView2), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext) ||
!m_wndSplitter1.CreateView(1, 0, RUNTIME_CLASS(CMyView3), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext))
return FALSE;
if (!m_wndSplitter2.CreateStatic(&m_wndSplitter, 2, 1, WS_CHILD) ||
!m_wndSplitter2.CreateView(0, 0, RUNTIME_CLASS(CMyView4), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext) ||
!m_wndSplitter2.CreateView(1, 0, RUNTIME_CLASS(CMyView5), CSize(rectClient.Width() / 2, rectClient.Height() / 2), pContext))
return FALSE;
m_bSplitter = TRUE; // 窗口已完成分割,視圖已經動態創建
Switch(0); // 更改數值以獲得切換效果
// return CFrameWnd::OnCreateClient(lpcs, pContext);
return TRUE;
}
修改視圖切換函數
BOOL CMainFrame::Switch(int nIndex)
{
CRect rectClient;
GetClientRect(rectClient);
switch (nIndex)
{
case 0:
::SetWindowLong(m_wndSplitter1, GWL_ID, m_wndSplitter.IdFromRowCol(0, 1));
m_wndSplitter1.ShowWindow(SW_SHOW);
::SetWindowLong(m_wndSplitter2, GWL_ID, AFX_IDW_PANE_FIRST);
m_wndSplitter2.ShowWindow(SW_HIDE);
break;
case 1:
::SetWindowLong(m_wndSplitter1, GWL_ID, AFX_IDW_PANE_FIRST);
m_wndSplitter1.ShowWindow(SW_HIDE);
::SetWindowLong(m_wndSplitter2, GWL_ID, m_wndSplitter.IdFromRowCol(0, 1));
m_wndSplitter2.ShowWindow(SW_SHOW);
break;
default:
return FALSE;
}
return TRUE;
}