您的位置:首页 > 其它

窗口分割

2016-03-14 15:56 176 查看
我们在使用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;

}

MFC中使用CSplitterWnd分割窗口后设置视图大小的问题(无效设置)

  1.在对框架窗口进行分割之后需要根据需求设置每个分割窗口的大小,但是在通过createView(...)设置大小时,往往起不到想要的结果,如下代码并不能将框架的窗口按照预设的大小来进行分割:

  2.这时候,需要在设置了在CreateView后,使用m_wndSplitter.SetRowInfo(....)设置水平分割条的位置,通常可以onSize()函数中进行设置,以达到分割窗口能够根据父窗口的大小自动调整,代码如下:

CSplitterWnd可以很方便地创建分割器窗口。要隐藏分割器窗口中的某个视图,只需调用GetPane函数得到视图指针,然后调用ShowWindow函数隐藏窗口。但是这样做只隐藏了视图窗口,没有隐藏分割条;当程序框架尺寸变化后,程序会自动调用RecalcLayout函数,从而使得显示效果不正常。CSplitterWnd没有提供设置分割条尺寸的public函数,通过分析CSplitterWnd的源码得知,它里面有几个没有公开的受保护的成员变量:

m_cxSplitter, m_cySplitter, m_cxBorderShare, m_cyBorderShare, m_cxSplitterGap, m_cySplitterGap, m_cxBorlder, m_cyBorlder

通过重新构造m_cxSplitterGap,m_cySplitterGap变量的值,就可以实现改变分割条尺寸的功能。

解决方案:

1.从CSplitterWnd派生一个新类CMySplitterWnd;

2.在.h文件中添加成员变量和函数如下:

int m_cx;

int m_cy;

void HideSplitter();

void ShowSplitter();

3.在.cpp文件中添加实现代码如下:

void CMySplitterWnd::HideSplitter()

{

m_cx=m_cxSplitterGap;//save previous cx

m_cy=m_cxSplitterGap;//save previous cy

m_cxSplitterGap=0;

m_cySplitterGap=0;

}

void CMySplitterWnd::ShowSplitter()

{

m_cxSplitterGap=m_cx;

m_cySplitterGap=m_cy;

}

4.使用新类CMySplitterWnd生成分割器窗口,在需要的时候调用HideSplitter、ShowSplitter函数即可。

解决方案2:

//保存分割条的位置

m_wndSplitter1.GetColumnInfo(0,scx,smcx);

//设置分割条在最左边

m_wndSplitter1.SetColumnInfo(0,0,0);

LeftView->ShowWindow(SW_HIDE);

RightView->ShowWindow(SW_MAXIMIZE);

m_wndSplitter1.HideSplitter();

m_wndSplitter1.RecalcLayout();

3.

virtual BOOL CreateStatic( CWnd* pParentWnd, int nRows, int nCols, DWORD dwStyle = WS_CHILD | WS_VISIBLE, UINT nID = AFX_IDW_PANE_FIRST );

virtual BOOL CreateStatic( CWnd* pParentWnd, int nRows, int nCols, DWORD dwStyle = WS_CHILD | WS_VISIBLE, UINT nID = AFX_IDW_PANE_FIRST );

virtual BOOL CreateView( int row, int col, CRuntimeClass* pViewClass, SIZE sizeInit, CCreateContext* pContext );

AFX_IDW_PANE_FIRST 是默认nID,用于一层分割时。多层分割需要父窗口调用int IdFromRowCol( int row, int col ) const;函数得到row行col列的窗口id号。



0

  四、小结

  本实例通过灵活运用CsplitterWnd类,实现了窗口的任意拆分。另外,需要补充的内容是,在具体应用中可以通过对CSplitterWnd原有方法的覆盖或者增加新的方法来扩展CSplitterWnd。我们在此仅举两个方面的例子,一是锁定切分条;二是定制自己的切分条。对于锁定切分条,不希望用户通过拖动切分条来调节窗口的大小这个问题,最简单的解决方法莫过于不让CSplitterWnd来处理WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_SETCURSOR消息,而是将这些消息交给CWnd窗口进行处理,从而屏蔽掉这些消息。那么如何定制自己的切分条呢?通过重载CSplitterWnd的虚方法OnDrawSplitter()和OnInvertTracker()可以达到这样的目的。下面的代码生成的效果是分割窗口的边界颜色为红色,分割条的颜色为绿色代码如下:

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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: