VC窗口的分割(锁定分割条与定制切分条)



想具有自己风格的分割窗口,可以新建一个类,该类继承CSplitterWnd,然后设计自己的切分条风格(如锁定切分条、定制切分条的分割颜色等)。

1 分割窗体风格(Splitter Styles)
CSplitterWnd
类支持2种不同风格的分割窗口

1.1 静态分割(static splitter)

1.2 动态分割(dynamic splitter)

CSplitterWnd 成员

基类的成员

CObject Members

CCmdTarget Members

CWnd Members

Create

创建一个动态的分隔器窗口并将它与一个CSplitterWnd对象连接。

CreateStatic

创建一个静态的分隔器窗口并将它与一个CSplitterWnd对象连接。

CreateView

调用它创建一个窗格到一个切分窗口。

CSplitterWnd

调用构造一个CSplitterWnd对象。

GetColumnCount

返回当前窗格列的计数值。

GetColumnInfo

返回指定列的信息。

GetPane

返回位于指定行和列处的窗格。

GetRowCount

返回当前窗格的行列举。

GetRowInfo

返回指定行的信息。

GetScrollStyle

返回被共享的滚动条的风格。

IdFromRowCol

返回位于指定行和列处的窗格的子窗口ID

IsTracking

定位,如果切分条目前是正在移动的话。

IsChildPane

调用确定这个窗口是否是目前切分窗口的一个子窗格。

RecalcLayout

在校准行和列尺寸之后重新显示切分窗口。

SetColumnInfo

调用设置指定列的信息。

SetRowInfo

调用设置指定行的信息。

SetScrollStyle

为切分窗口(分隔器窗口)的共享滚动条指定新的滚动条风格。

 

ActivateNext

执行Next PanePrevious Pane命令。

CanActivateNext

检查看 Next Pane Previous Pane 命令当前是否可用。

CreateScrollBarCtrl

创建共享滚动条控件(control)

DeleteColumn

从切分窗口中删除一列。

DeleteRow

从切分窗口中删除一行。

DeleteView

从切分窗口中删除一个视图。

DoKeyboardSplit

执行键盘滚动命令,通常是"Window Split."

DoScroll

执行切分窗口同步滚动。

DoScrollBy

通过给定的像素数,滚动切分窗口。

GetActivePane

确定活动窗格,根据焦点或者框架中的视图。

OnDrawSplitter

描绘一个图像到一个切分窗口。

OnInvertTracker

描绘一个图像到一个切分窗口,与框架窗口一样的大小和外形。

SetActivePane

设定一个在框架里活动的窗格。

SplitColumn

表明一个框架窗口是否是垂直切分的。

SplitRow

表明一个框架窗口是否是水平切分的

 

分割窗体中使用的术语(Terminology Used By Implement)
CsplitterWnd(分割窗体):
负责提供窗格切分空间和滚动条(同行(row)共享竖直滚动条(Vertical ScrollBar),同列(column)共享水平滚动条(Horizontal ScrollBar) );同时行列的下标从0 0开始,言即第一个窗格为第00列的窗格

Pane(窗格)
CSplitterWnd管理的应用程序显示数据的窗体,一般而言窗格是一个视图的派生类对象,实际上窗格可以是任意的从CWnd中派生的对象;

Splitter Bar(分割控制条)
在窗格行列间的控件,用于控制行列上窗格的大小

Spliiter Box(分割格)
动态分割窗体位于竖直滚动条最上的或水平滚动条最左位置的按键,用于创建新的分割窗格

Splitter Intersection(分割交叉点)
竖直或水平分割控制条的交叉点,可用于同步控制水平,竖直窗格的大小

4 共享滚动条(Shared Scroll Bars)

 

我们在使用OutLook或者NetAnt等工具的时候,一般都会被其复杂的界面所吸引,在这些界面中窗口被分割为若干的区域,真正做到了窗口的任意分割。那么我们自己如何创建类似的界面,也实现窗口的任意的分割呢?要解决这个问题,在Visual C++6.0编程中就需要使用到MFC提供的CSplitterWnd类。CSplitterWnd看上去像是一种特殊的框架窗口,每个窗口都被相同的或者不同的视图所填充。当窗口被切分后用户可以使用鼠标移动切分条来调整窗口的相对尺寸。虽然VC6.0支持从AppWizard中创建分割窗口,但是自动加入的分割条总是不能让我们满意,因此我们还是通过手工增加代码来熟悉这个类。本实例采用多模板模式,即实现了窗口的任意分割,又介绍了各个视图如何相互通信。程序编译运行后的界面效果如图一所示:
  一、实现方法

  Visual C++MFC提供了CSplitterWnd类来实现窗口的分割,它的构造函数主要包括下面三个:

BOOL Create(CWnd* pParentWnd,int nMaxRows,int nMaxCols,SIZE sizeMin,
CCreateContext* pContext,DWORD dwStyle,UINT nID);

  该函数用来创建动态切分窗口,参数pParentWnd表示切分窗口的父框架窗口;参数nMaxRows,nMaxCols是创建切分窗口的最大列数和行数;sizeMin是窗格的最小尺寸;参数pContext 大多数情况下传给父窗口;nID是切分窗口的ID号。例如下面的代码将创建2x2的窗格。

m_wndSplitter.Create(this,2,2,CSize(100,100),pContext);

  动态创建的分割窗口的窗格数目不能超过2x2,而且对于所有的窗格,都必须共享同一个视图,所受的限制也比较多,因此我们不将动态创建作为重点。我们的主要精力放在静态分割窗口的创建上。

BOOL CreateStatic(CWnd* pParentWnd,int nRows,int nCols,DWORD dwStyle,UINT nID)


  该函数用来用来创建切静态分窗口,参数含义同上。


BOOL CreateView (int row,int col,CruntimeClass* pViewClass,SIZE
sizeinit,CcreateContext* pContext);

  此函数向静态切分的窗口的网格填充视图。在将视图于切分窗口联系在一起的时候必须先将切分窗口创建好。参数含义同上。与动态创建相比,静态创建的代码要简单许多,而且可以最多创建16x16的窗格。不同的窗格我们可以使用CreateView()函数来填充不同的视图。如果我们要创建类似CuteFtp程序的窗口分割,CuteFtp的分割情况如下:

CCuteFTPView
CView2 CView3
CView4

  那么在创建之前我们必须先用AppWizard生成单文档CuteFTP,生成的视类为 CCuteFTPView。同时在增加三个视类或者从视类继承而来的派生类CView2,CView3 CView4,然后在CMainfrm.h中增加下面的代码:

CSplitterWnd wndSplitter1;
CSplitterWnd wndSplitter2;

  为了实现拆分窗口,需要重载CMainFrame::OnCreateClient()函数,具体代码如下:

BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
{
 //创建一个静态分栏窗口,分为三行一列
 if(m_wndSplitter1.CreateStatic(this,3,1)==NULL)
  
return FALSE;
 //CCuteFTPView连接到00列窗格上

 m_wndSplitter1.CreateView(0,0,RUNTIME_CLASS(CCuteFTPView),CSize(100,100), pContext);
 
m_wndSplitter1.CreateView(2,0,RUNTIME_CLASS(CView4),CSize(100,100),pContext);
 //CView4连接到20

 if(m_wndSplitter2.CreateStatic(&m_wndSplitter,1,2,WS_CHILD|WS_VISIBLE, m_wndSplitter.IdFromRowCol(1, 0))==NULL)
  return FALSE; //将第10列再分开12

 //CView2类连接到第二个分栏对象的00
 m_wndSplitter2.CreateView(0,0,RUNTIME_CLASS(CView2),CSize(400,300),pContext);
 //CView3类连接到第二个分栏对象的01

 m_wndSplitter2.CreateView(0,1,RUNTIME_CLASS(CView3),CSize(400,300),pContext);
 return TRUE;

}

  在应用程序中拆分窗口后,还有一个重要的工作就是实现各个视图之间的数据通信,有两种方法解决这个问题:一是利用公用的文档;二是利用程序的主框架。为了说明问题,我们让CCuteFTPViewCView2通过文档来实现通信,CView3CView4通过主框架来通信。对于第一种方法,由AppWizard生成的CCuteFTPView是与文档相连的,同时我们也让CView2与文档相连,因此我们需要修改CCuteFTPAppInitInstance()函数,增加下面的代码:

AddDocTemplate (new CMultiDocTemplate(IDR_VIEW2TYPE, RUNTIME_CLASS(CMainDoc),
RUNTIME_CLASS(CMDIChildWnd), RUNTIME_CLASS(CView2)));

  然后我们重载 CDocument::OnOpenDocument()函数;在该函数中定义如下变量:CCuteFTPView* pCuteFTPViewCView2* pView2POSITION pos,并添加如下代码:

pos=GetFirstViewPosition( )
while(pos!=NULL)
{
 pView=GetNextView(pos);
 
if(pView->IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL)
  
pCuteFTPView=(CCuteFTPView*)pView;
 
else
  
pView2=(CView2*)pView;
}

  这样我们在文档类中就获的了跟它相连的所有的视图的指针。如果需要在 CCuteFTPView中调用CView2中的一个方法DoIt()则代码如下:


CCuteFTPDoc* pDoc=GetDocument();
CView2* pView2=pDoc->pView2;
pView3.DoIt();

  CView3CView4都是不与文档相关联的。如何实现他们之间的通信呢。正如我们在上面所说的那样,由于在主框架中我们可以访问任意的视图,因此我们的主要任务还是在程序中获得主框架的指针。例如下面的代码实现在CView3中访问CView4中的方法DoIt()


CMainFrame* MainFrame=(CMainFrame*)this->GetParent()->GetParent();
CView4* View4=(CView4*)MainFrame->m_wndSplitter1.GetPane(2,0);
View4->DoIt();


  为了更好地加深读者朋友对上述内容的理解,本实例通过灵活运用上述拆分窗口的方法,在多文档视图模板的基础上,实现了窗口的任意拆分,例如当用户在左边视图InPutView中输入字符串、选择颜色后,能立即反映到右边的CCorlorViewCtextView窗口中。
  二、编程步骤


  1、启动Visual C++6.0生成一个多文档应用程序Viewex,并添加支持分割的各个视图类;

  2、修改CViewExApp::InitInstance()函数,为应用程序添加多文档视图结构模板的支持;

  3、添加代码,编译运行程序。

  三、编程步骤


BOOL CViewExApp::InitInstance()
{
 ……………………………
 
// simple text output view
 
AddDocTemplate(new CMultiDocTemplate(IDR_TEXTTYPE,
  
RUNTIME_CLASS(CMainDoc),
  
RUNTIME_CLASS(CMDIChildWnd),
  
RUNTIME_CLASS(CTextView)));
 
// simple color output view
 
AddDocTemplate(new CMultiDocTemplate(IDR_COLORTYPE,
  
RUNTIME_CLASS(CMainDoc),
  
RUNTIME_CLASS(CMDIChildWnd),
  
RUNTIME_CLASS(CColorView)));
 
// form view with input
 
AddDocTemplate(new CMultiDocTemplate(IDR_INPUTTYPE,
  
RUNTIME_CLASS(CMainDoc),
  
RUNTIME_CLASS(CMDIChildWnd),
  
RUNTIME_CLASS(CInputView)));
 
// splitter frame with both simple text output and form input view
 
AddDocTemplate(new CMultiDocTemplate(IDR_SPLIT2TYPE,
  
RUNTIME_CLASS(CMainDoc),
  
RUNTIME_CLASS(CSplitterFrame),
  
RUNTIME_CLASS(CTextView)));
 
// 3-way splitter frame with form input, text output and color output views
 
AddDocTemplate(new CMultiDocTemplate(IDR_SPLIT3TYPE,
  
RUNTIME_CLASS(CMainDoc),
  
RUNTIME_CLASS(C3WaySplitterFrame),
  
RUNTIME_CLASS(CInputView)));
 
CMDIFrameWnd* pMainFrame = new CMDIFrameWnd;
 
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
  
return FALSE;
 
// Now finally show the main menu
 
pMainFrame->ShowWindow(m_nCmdShow);
 
pMainFrame->UpdateWindow();
 
m_pMainWnd = pMainFrame;
 
OnFileNew();
 
return TRUE;
}

//CinputView
类的头文件

class CInputView : public CFormView
{
 DECLARE_DYNCREATE(CInputView)
 
protected:
  
CInputView(); // protected constructor used by dynamic creation
  
// Form Data
 
public:
  
//{{AFX_DATA(CInputView)
   
enum { IDD = IDD_INPUTFORM };
   
CString m_strData;
   
int m_iColor;
  
//}}AFX_DATA
  
// Attributes
 
public:
  
CMainDoc* GetDocument()
  
{
   
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMainDoc)));
   
return (CMainDoc*) m_pDocument;
  
}
  
// Operations
 
public:
  
// Implementation
 
protected:
  
virtual ~CInputView();
  
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
  
virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
  
// Generated message map functions
  
//{{AFX_MSG(CInputView)
   
afx_msg void OnDataChange();
  
//}}AFX_MSG
  
DECLARE_MESSAGE_MAP()
};
/// CInputView
类实现文件

#include "stdafx.h"
#include "viewex.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CInputView, CFormView)
CInputView::CInputView()
: CFormView(CInputView::IDD)
{
 //{{AFX_DATA_INIT(CInputView)
  
m_strData = "";
  
m_iColor = -1;
 
//}}AFX_DATA_INIT
}

CInputView::~CInputView()
{}

void CInputView::OnUpdate(CView*, LPARAM, CObject*)
{
 
CMainDoc* pDoc = GetDocument();
 
m_strData = pDoc->m_strData;
 
if (pDoc->m_colorData == RGB(255, 0, 0))
  
m_iColor = 0;
 
else if (pDoc->m_colorData == RGB(0, 255, 0))
  
m_iColor = 1;
 
else if (pDoc->m_colorData == RGB(0, 0, 255))
  
m_iColor = 2;
 
else
  
m_iColor = -1;
 
TRACE2("OnUpdate: m_iColor = %d ($%lx)\n", m_iColor, pDoc->m_colorData);
 
UpdateData(FALSE); // set the data into the controls
}

void CInputView::DoDataExchange(CDataExchange* pDX)
{
 
CFormView::DoDataExchange(pDX);
 
//{{AFX_DATA_MAP(CInputView)
   
DDX_Text(pDX, IDC_EDIT1, m_strData);
   
DDX_Radio(pDX, IDC_RADIO1, m_iColor);
 
//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CInputView, CFormView)
 
//{{AFX_MSG_MAP(CInputView)
  
ON_EN_CHANGE(IDC_EDIT1, OnDataChange)
  
ON_BN_CLICKED(IDC_RADIO1, OnDataChange)
  
ON_BN_CLICKED(IDC_RADIO2, OnDataChange)
  
ON_BN_CLICKED(IDC_RADIO3, OnDataChange)
 
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CInputView::OnDataChange()// CInputView message handlers
{
 
if (!UpdateData())
  
return;
 
CMainDoc* pDoc = GetDocument();
 
COLORREF color = RGB(255 * (m_iColor == 0),
 
255 * (m_iColor == 1),
 
255 * (m_iColor == 2));
 
BOOL bUpdate = FALSE;
 
if (m_strData != pDoc->m_strData)
 
{
  
pDoc->m_strData = m_strData;
  
bUpdate = TRUE;
 
}
 
if (color != pDoc->m_colorData)
 
{
  
pDoc->m_colorData = color;
  
bUpdate = TRUE;
 
}
 
if (bUpdate)
 
{
  
// if the document stored data then we would call SetModifiedFlag here
  
pDoc->UpdateAllViews(this);
 
}
}
/simpvw.h
文件

class CTextView : public CView
{
 protected: // create from serialization only
  
CTextView();
  
DECLARE_DYNCREATE(CTextView)
  
// Attributes
 
public:
  
CMainDoc* GetDocument()
  
{
   
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMainDoc)));
   
return (CMainDoc*) m_pDocument;
  
}
  
// Operations
 
public:
  
// Implementation
 
public:
  
virtual ~CTextView();
  
virtual void OnDraw(CDC* pDC); // overridden to draw this view
  
// Generated message map functions
 
protected:
  
//{{AFX_MSG(CTextView)
   
afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message);
  
//}}AFX_MSG
  
DECLARE_MESSAGE_MAP()
};
class CColorView : public CView
{
 
protected: // create from serialization only
  
CColorView();
  
DECLARE_DYNCREATE(CColorView)
  
// Attributes
 
public:
  
CMainDoc* GetDocument()
  
{
   
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMainDoc)));
   
return (CMainDoc*) m_pDocument;
  
}

  
// Operations
 
public:
  
// Implementation
 
public:
  
virtual ~CColorView();
  
virtual void OnDraw(CDC* pDC); // overridden to draw this view
  
virtual void OnActivateView(BOOL bActivate, CView* pActivateView,
  
CView* pDeactiveView);
  
// Generated message map functions
 
protected:
  
//{{AFX_MSG(CColorView)
   
afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message);
  
//}}AFX_MSG
 
DECLARE_MESSAGE_MAP()
};
simpvw.cpp
文件;

#include "stdafx.h"
#include "viewex.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
/CTextView
IMPLEMENT_DYNCREATE(CTextView, CView)
BEGIN_MESSAGE_MAP(CTextView, CView)
 //{{AFX_MSG_MAP(CTextView)
  
ON_WM_MOUSEACTIVATE()
 
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// CTextView construction/destruction
CTextView::CTextView()
{}

CTextView::~CTextView()
{}

void CTextView::OnDraw(CDC* pDC)
{
 
CMainDoc* pDoc = GetDocument();
 
CRect rect;
 
GetClientRect(rect);
 
pDC->SetTextAlign(TA_BASELINE | TA_CENTER);
 
pDC->SetTextColor(pDoc->m_colorData);
 
pDC->SetBkMode(TRANSPARENT);
 
// center in the window
 
pDC->TextOut(rect.Width() / 2, rect.Height() / 2,
 
pDoc->m_strData, pDoc->m_strData.GetLength());
}

int CTextView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
{
 
// side-step CView's implementation since we don't want to activate
 
// this view
 
return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message);
}
// CColorView
IMPLEMENT_DYNCREATE(CColorView, CView)
BEGIN_MESSAGE_MAP(CColorView, CView)
 
//{{AFX_MSG_MAP(CColorView)
  
ON_WM_MOUSEACTIVATE()
 
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// CColorView construction/destruction
CColorView::CColorView()
{}
CColorView::~CColorView()
{}

void CColorView::OnDraw(CDC* pDC)
{
 
CMainDoc* pDoc = GetDocument();
 
CRect rect;
 
GetClientRect(rect);
 
// fill the view with the specified color
 
CBrush br(pDoc->m_colorData);
 
pDC->FillRect(rect, &br);
}

int CColorView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
{
 
// side-step CView's implementation since we don't want to activate
 
// this view
 
return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message);
}

void CColorView::OnActivateView(BOOL, CView*, CView*)
{
 
ASSERT(FALSE); // output only view - should never be active
}
/ splitter.h
文件;

// CSplitterFrame frame with splitter/wiper
class CSplitterFrame : public CMDIChildWnd
{
 DECLARE_DYNCREATE(CSplitterFrame)
 
protected:
  
CSplitterFrame(); // protected constructor used by dynamic creation
  
// Attributes
 
protected:
  
CSplitterWnd m_wndSplitter;
  
// Implementation
 
public:
  
virtual ~CSplitterFrame();
  
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
  
// Generated message map functions
  
//{{AFX_MSG(CSplitterFrame)
  
//}}AFX_MSG
 
DECLARE_MESSAGE_MAP()
};

class CViewExSplitWnd : public CSplitterWnd
{
 
DECLARE_DYNAMIC(CViewExSplitWnd)
 
// Implementation
 
public:
  
CViewExSplitWnd();
  
~CViewExSplitWnd();
  
CWnd* GetActivePane(int* pRow = NULL, int* pCol = NULL);
};
class C3WaySplitterFrame : public CMDIChildWnd
{
 
DECLARE_DYNCREATE(C3WaySplitterFrame)
 
protected:
  
C3WaySplitterFrame(); // protected constructor used by dynamic creation
  
// Attributes
 
protected:
  
CViewExSplitWnd m_wndSplitter;
  
CViewExSplitWnd m_wndSplitter2; // embedded in the first
  
// Implementation
 
public:
  
virtual ~C3WaySplitterFrame();
  
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
  
// Generated message map functions
  
//{{AFX_MSG(C3WaySplitterFrame)
  
//}}AFX_MSG
 
DECLARE_MESSAGE_MAP()
};
/splitter.cpp
文件;

#include "stdafx.h"
#include "viewex.h"
#include "splitter.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
// CSplitterFrame
// Create a splitter window which splits an output text view and an input view
// |
// TEXT VIEW (CTextView) | INPUT VIEW (CInputView)
// |
IMPLEMENT_DYNCREATE(CSplitterFrame, CMDIChildWnd)
CSplitterFrame::CSplitterFrame()
{}

CSplitterFrame::~CSplitterFrame()
{}
BOOL CSplitterFrame::OnCreateClient(LPCREATESTRUCT,
CCreateContext* pContext)
{
 // create a splitter with 1 row, 2 columns
 
if (!m_wndSplitter.CreateStatic(this, 1, 2))
 
{
  
TRACE0("Failed to CreateStaticSplitter\n");
  
return FALSE;
 
}
 
// add the first splitter pane - the default view in column 0
 
if (!m_wndSplitter.CreateView(0, 0,pContext->m_pNewViewClass, CSize(130, 50), pContext))
 
{
  
TRACE0("Failed to create first pane\n");
  
return FALSE;
 
}
 
// add the second splitter pane - an input view in column 1
 
if (!m_wndSplitter.CreateView(0, 1,RUNTIME_CLASS(CInputView), CSize(0, 0), pContext))
 
{
  
TRACE0("Failed to create second pane\n");
  
return FALSE;
 
}
 
// activate the input view
 
SetActiveView((CView*)m_wndSplitter.GetPane(0,1));
 
return TRUE;
}
BEGIN_MESSAGE_MAP(CSplitterFrame, CMDIChildWnd)
 
//{{AFX_MSG_MAP(CSplitterFrame)
 
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// C3WaySplitterFrame - just like CSplitterFrame except the input view is
// the first pane, and there are two output views

// | Text View (CTextView)
// INPUT VIEW (CInputView) |------------------------
// | Color View (CColorView)
IMPLEMENT_DYNCREATE(C3WaySplitterFrame, CMDIChildWnd)
C3WaySplitterFrame::C3WaySplitterFrame()
{}

C3WaySplitterFrame::~C3WaySplitterFrame()
{}

BOOL C3WaySplitterFrame::OnCreateClient(LPCREATESTRUCT lpcs,CCreateContext* pContext)
{
 
// create a splitter with 1 row, 2 columns
 
if (!m_wndSplitter.CreateStatic(this, 1, 2))
 
{
  
TRACE0("Failed to CreateStaticSplitter\n");
  
return FALSE;
 
}
 
// add the first splitter pane - the default view in column 0
 
if (!m_wndSplitter.CreateView(0, 0,pContext->m_pNewViewClass, CSize(200, 50), pContext))
 
{
  
TRACE0("Failed to create first pane\n");
  
return FALSE;
 
}
 
// add the second splitter pane - which is a nested splitter with 2 rows
 
if (!m_wndSplitter2.CreateStatic(&m_wndSplitter, // our parent window is the first splitter
2, 1, // the new splitter is 2 rows, 1 column
WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
m_wndSplitter.IdFromRowCol(0, 1) ))
// new splitter is in the first row, 2nd column of first splitter
{
 
TRACE0("Failed to create nested splitter\n");
 
return FALSE;
}
// now create the two views inside the nested splitter
int cyText = max(lpcs->cy - 70, 20); // height of text pane
if (!m_wndSplitter2.CreateView(0, 0,RUNTIME_CLASS(CTextView), CSize(0, cyText), pContext))
{
 
TRACE0("Failed to create second pane\n");
 
return FALSE;
}
if (!m_wndSplitter2.CreateView(1, 0,RUNTIME_CLASS(CColorView), CSize(0, 0), pContext))
{
 
TRACE0("Failed to create third pane\n");
 
return FALSE;
}
// it all worked, we now have two splitter windows which contain
// three different views
return TRUE;
}
BEGIN_MESSAGE_MAP(C3WaySplitterFrame, CMDIChildWnd)
//{{AFX_MSG_MAP(C3WaySplitterFrame)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
IMPLEMENT_DYNAMIC(CViewExSplitWnd, CSplitterWnd)
CViewExSplitWnd::CViewExSplitWnd()
{}

CViewExSplitWnd::~CViewExSplitWnd()
{}

CWnd* CViewExSplitWnd::GetActivePane(int* pRow, int* pCol)
{
 
ASSERT_VALID(this);
 
// attempt to use active view of frame window
 
CWnd* pView = NULL;
 
CFrameWnd* pFrameWnd = GetParentFrame();
 
ASSERT_VALID(pFrameWnd);
 
pView = pFrameWnd->GetActiveView();
 
// failing that, use the current focus
 
if (pView == NULL)
  
pView = GetFocus();
 
return pView;
}

  四、小结

本实例通过灵活运用CsplitterWnd类,实现了窗口的任意拆分。另外,需要补充的内容是,在具体应用中可以通过对CSplitterWnd原有方法的覆盖或者增加新的方法来扩展CSplitterWnd

我们在此仅举两个方面的例子,一是锁定切分条;二是定制自己的切分条。对于锁定切分条,不希望用户通过拖动切分条来调节窗口的大小这个问题,最简单的解决方法莫过于不让CSplitterWnd来处理WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_SETCURSOR消息,而是将这些消息交给CWnd窗口进行处理,从而屏蔽掉这些消息。那么如何定制自己的切分条呢?通过重载CSplitterWnd的虚方法OnDrawSplitter()和OnInvertTracker()可以达到这样的目的。下面的代码生成的效果是分割窗口的边界颜色为红色,分割条的颜色为绿色代码如下:

void CSplitterWndEx::OnDrawSplitter(CDC *pDC, ESplitType nType, const CRect &rectArg)

{

CSplitterWnd::OnDrawSplitter(pDC, nType, rectArg);

    int CX_BORDER=1,CY_BORDER=1;

    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) 
//
此函数在切割窗口大小变化时调用,在onlbuttonup()函数中添加invalidate()函数,刷屏

{

   CSplitterWnd::OnInvertTracker(rect);

    ASSERT_VALID(this);

    ASSERT(!rect.IsRectEmpty());

    ASSERT((GetStyle()&WS_CLIPCHILDREN)==0);

    CRect rc=rect;

    rc.InflateRect(1,1);

    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(),WHITENESS);

 

    if(hOldBrush!=NULL)

        SelectObject(pDC->m_hDC,hOldBrush);

    ReleaseDC(pDC);

}

 http://blog.csdn.net/p40614021/article/details/7397963

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值