您的位置:首页 > 其它

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

2012-10-02 23:38 148 查看
想具有自己风格的分割窗口,可以新建一个类,该类继承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 Pane或Previous 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开始,言即第一个窗格为第0行第0列的窗格
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连接到0行0列窗格上

 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连接到2行0列

 if(m_wndSplitter2.CreateStatic(&m_wndSplitter,1,2,WS_CHILD|WS_VISIBLE, m_wndSplitter.IdFromRowCol(1,
0))==NULL)

  return FALSE; //将第1行0列再分开1行2列

 //将CView2类连接到第二个分栏对象的0行0列

 m_wndSplitter2.CreateView(0,0,RUNTIME_CLASS(CView2),CSize(400,300),pContext);

 //将CView3类连接到第二个分栏对象的0行1列

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

 return TRUE;

}

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

AddDocTemplate (new CMultiDocTemplate(IDR_VIEW2TYPE, RUNTIME_CLASS(CMainDoc),

RUNTIME_CLASS(CMDIChildWnd), RUNTIME_CLASS(CView2)));

  然后我们重载 CDocument::OnOpenDocument()函数;在该函数中定义如下变量:CCuteFTPView*
pCuteFTPView、CView2* pView2、POSITION
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();

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

CMainFrame* MainFrame=(CMainFrame*)this->GetParent()->GetParent();

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

View4->DoIt();

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

  二、编程步骤

  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);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: