CSplitterWnd m_wndSplitter;// split the view into left and right
CSplitterWnd m_wndSplitterRight; //split the right view into top and bottom
//先把窗口分割为1>2的形式,即分割为两列
m_wndSplitter.CreateStatic(this, 1, 2 , WS_CHILD | WS_VISIBLE| WS_BORDER);
//然后把窗口第2列再分割为 2>1的形式
// m_wndSplitterRight.CreateStatic(&m_wndSplitter, 2, 1, WS_CHILD|WS_VISIBLE,m_wndSplitter.IdFromRowCol(0, 1) );
//下面为分割后的窗口对应的视图类
m_wndSplitter.CreateView(0, 0,RUNTIME_CLASS(CSplitWndView),
CSize(600, 100), pContext);
m_wndSplitterRight.CreateView(0, 0,RUNTIME_CLASS(CLeftTopView),
CSize(10, 500), pContext);
m_wndSplitterRight.CreateView(1, 0,RUNTIME_CLASS(CLeftBttmView),
CSize(10, 10), pContext);
return true;
类似的,,写了一个窗口分割的例子。。是在单文档中,分割为一个视图,一个对话框,还有一个Edit。
地址为:窗口分割
为了在窗口改变大小时,拆分的两个窗口如终大小一样,重载CMainFrame::OnSize函数
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
CRect rect;
GetClientRect(&rect);
if (m_bSplitterCreated)
{
m_wndSplitter.SetColumnInfo(0, rect.Width()/2, 10);//这是只有一行两列的改变方式。。为了简单起见。。
m_wndSplitter.SetColumnInfo(1, rect.Width()/2, 10);
m_wndSplitter.RecalcLayout();
}
}
变量m_bSplitterCreated是用来判断是否切分窗口的,不加这个的话,第一次运行的时候会出错!
在MainFrm.h中定义变量BOOL m_bSplitterCreated;
在CMainFrame的构造函数中初始化m_bSplitterCreated=FALSE;
也可以使用MoveWindow函数进行。。
CRect m_rect;
GetClientRect(&m_rect);
if(true == m_bSplitterCreated)
{
CmfctestView* paneView = (CmfctestView*)m_wndSplitter.GetPane(0,0);
paneView->MoveWindow(m_rect.left,m_rect.top,int(m_rect.right*4.3/6),m_rect.bottom);
CRightView* paneView1 = (CRightView*)m_wndSplitter.GetPane(0,1);
paneView1->MoveWindow(int(m_rect.right*4.3/6+5),m_rect.top,m_rect.right,m_rect.bottom);
}
以下为网络搜。。留待以后用。。未验证
AddDocTemplate (new CMultiDocTemplate(IDR_VIEW2TYPE, RUNTIME_CLASS(CMainDoc), RUNTIME_CLASS(CMDIChildWnd), RUNTIME_CLASS(CView2)));我们现在来实现CCuteFTPView与CView2之间的通信。由于跟文档类相连的视图类 是不能安全的与除文档类之外的其余的视图类通信的。因此我们只能让他们都与文档 类通信。在文档中我们设置相应的指针以用来获的各个视图。我们重载 CCuteFTPView::OnOpenDocument()函数;
CCuteFTPView* pCuteFTPView; CView2* pView2; POSITION pos; CView* pView; while(pos!=NULL) { pView=GetNextView(pos); if(pView->IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL) pCuteFTPView=(CCuteFTPView*)pView; else(pView->IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL) pView2=(CView2*)pView; }这样我们在文档类中就获的了跟它相连的所有的视图的指针。
CCuteFTPDoc* pDoc=GetDocument(); CView2* pView2=pDoc->pView3; pView3.DoIt();
CMainFrame* MainFrame=(CMainFrame*)this->GetParent()->GetParent(); CCuteFTPDoc* Doc=(CCuteFTPDoc*)MainFrame->GetActiveDocument(); if(Doc!=NULL) Doc->DoIt(); CCuteFTPDoc中的相应的处理函数DoIt()代码如下: CView2* pView2; POSITION pos; CView* pView; while(pos!=NULL) { pView=GetNextView(pos); if(pView->IsKindOf(RUNTIME_CLASS(CView2))==NULL) pView2=(CView2*)pView; } pView2->DoIt();■ 无文档关联视图之间的通信
CMainFrame* MainFrame=(CMainFrame*)this->GetParent()->GetParent(); CView4* View4=(CView4*)MainFrame->m_wndSplitter1.GetPane(2,0); View4->DoIt();
virtual void StartTracking(int ht); virtual CWnd* GetActivePane(int* pRow = NULL, int* pCol = NULL); virtual void SetActivePane( int row, int col, CWnd* pWnd = NULL ); virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); virtual BOOL OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult ); virtual BOOL OnWndMsg( UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult );具体实现如下,实现中我将给出原有代码的主要部分以及修改后的代码以作对比。
enum HitTestValue { noHit = 0,//表示没有选中任何对象 vSplitterBox = 1, hSplitterBox = 2, bothSplitterBox = 3, vSplitterBar1 = 101,//代表各个方向的水平分割条 vSplitterBar15 = 115, hSplitterBar1 = 201,//代表垂直方向的各个分割条 hSplitterBar15 = 215, splitterIntersection1 = 301,//代表各个交叉点 splitterIntersection225 = 525 }; CWnd* CxSplitterWnd::GetActivePane(int* pRow, int* pCol) { ASSERT_VALID(this); //获得当前的获得焦点的窗口 //下面注释粗体的是原有的代码的主要部分。 // CWnd* pView = NULL; //CFrameWnd* pFrameWnd = GetParentFrame(); //ASSERT_VALID(pFrameWnd); //pView = pFrameWnd->GetActiveView(); //if (pView == NULL) // pView = GetFocus(); CWnd* pView = GetFocus(); if (pView != NULL && !IsChildPane(pView, pRow, pCol)) pView = NULL; return pView; } void CxSplitterWnd::SetActivePane( int row, int col, CWnd* pWnd) { CWnd* pPane = pWnd == NULL ? GetPane(row, col) : pWnd; //下面加注释粗体的是原有代码的主要部分。 //FrameWnd* pFrameWnd = GetParentFrame(); //ASSERT_VALID(pFrameWnd); //pFrameWnd->SetActiveView((CView*)pPane); pPane->SetFocus();//修改后的语句 } void CxSplitterWnd::StartTracking(int ht) { ASSERT_VALID(this); if (ht == noHit) return; // GetHitRect will restrict ''''m_rectLimit'''' as appropriate GetInsideRect(m_rectLimit); if (ht >= splitterIntersection1 && ht <= splitterIntersection225) { // split two directions (two tracking rectangles) int row = (ht - splitterIntersection1) / 15; int col = (ht - splitterIntersection1) % 15; GetHitRect(row + vSplitterBar1, m_rectTracker); int yTrackOffset = m_ptTrackOffset.y; m_bTracking2 = TRUE; GetHitRect(col + hSplitterBar1, m_rectTracker2); m_ptTrackOffset.y = yTrackOffset; } else if (ht == bothSplitterBox) { // hit on splitter boxes (for keyboard) GetHitRect(vSplitterBox, m_rectTracker); int yTrackOffset = m_ptTrackOffset.y; m_bTracking2 = TRUE; GetHitRect(hSplitterBox, m_rectTracker2); m_ptTrackOffset.y = yTrackOffset; // center it m_rectTracker.OffsetRect(0, m_rectLimit.Height()/2); m_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 0); } else { // only hit one bar GetHitRect(ht, m_rectTracker); } //下面加注释的将从程序中删去。 //CView* pView = (CView*)GetActivePane(); //if (pView != NULL && pView->IsKindOf(RUNTIME_CLASS(CView))) //{ // ASSERT_VALID(pView); // CFrameWnd* pFrameWnd = GetParentFrame(); //ASSERT_VALID(pFrameWnd); //pView->OnActivateFrame(WA_INACTIVE, pFrameWnd); // } // steal focus and capture SetCapture(); SetFocus(); // make sure no updates are pending RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); // set tracking state and appropriate cursor m_bTracking = TRUE; OnInvertTracker(m_rectTracker); if (m_bTracking2) OnInvertTracker(m_rectTracker2); m_htTrack = ht; SetSplitCursor(ht); } BOOL CxSplitterWnd::OnCommand(WPARAM wParam, LPARAM lParam) { if (CWnd::OnCommand(wParam, lParam)) return TRUE; //下面粗体的是原程序的语句 //return GetParentFrame()->SendMessage(WM_COMMAND, wParam, lParam); return GetParent()->SendMessage(WM_COMMAND, wParam, lParam); } BOOL CxSplitterWnd::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult ) { if (CWnd::OnNotify(wParam, lParam, pResult)) return TRUE; //下面粗体的是源程序的语句 //*pResult = GetParentFrame()->SendMessage(WM_NOTIFY, wParam, lParam); *pResult = GetParent()->SendMessage(WM_NOTIFY, wParam, lParam); return TRUE; } BOOL CxSplitterWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { // The code line below is necessary if using CxSplitterWnd in a regular dll // AFX_MANAGE_STATE(AfxGetStaticModuleState()); return CWnd::OnWndMsg(message, wParam, lParam, pResult); }这样我们就可以在对话框中使用CxSplitterWnd类了。
void CXXSplitterWnd::OnLButtonDown(UINT nFlags,CPoint point) { CWnd::OnLButtonDown(nFlags,point); }其余的处理方法类似。
void CSplitterWndEx::OnDrawSplitter(CDC *pDC, ESplitType nType, const CRect &rectArg) { if(pDC==NULL) { RedrawWindow(rectArg,NULL,RDW_INVALIDATE|RDW_NOCHILDREN); return; } ASSERT_VALID(pDC); CRect rc=rectArg; switch(nType) { case splitBorder: //重画分割窗口边界,使之为红色 pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0)); rc.InflateRect(-CX_BORDER,-CY_BORDER); pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0)); return; case splitBox: pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0)); rc.InflateRect(-CX_BORDER,-CY_BORDER); pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0)); rc.InflateRect(-CX_BORDER,-CY_BORDER); pDC->FillSolidRect(rc,RGB(0,0,0)); pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0)); return; case splitBar: //重画分割条,使之为绿色 pDC->FillSolidRect(rc,RGB(255,255,255)); rc.InflateRect(-5,-5); pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0)); return; default: ASSERT(FALSE); } pDC->FillSolidRect(rc,RGB(0,0,255)); } void CSplitterWndEx::OnInvertTracker(CRect &rect) { ASSERT_VALID(this); ASSERT(!rect.IsRectEmpty()); ASSERT((GetStyle()&WS_CLIPCHILDREN)==0); CRect rc=rect; rc.InflateRect(2,2); CDC* pDC=GetDC(); CBrush* pBrush=CDC::GetHalftoneBrush(); HBRUSH hOldBrush=NULL; if(pBrush!=NULL) hOldBrush=(HBRUSH)SelectObject(pDC->m_hDC,pBrush->m_hObject); pDC->PatBlt(rc.left,rc.top,rc.Width(),rc.Height(),BLACKNESS); if(hOldBrush!=NULL) SelectObject(pDC->m_hDC,hOldBrush); ReleaseDC(pDC); }同样我们只要继承CSplitterWnd中的其余的一些虚拟方法就可以生成具有自己个性的分割窗口了。