窗口分割

我们在使用OutLook或者NetAnt等工具的时候,一般都会被其复杂的界面所吸引,在这些界面中窗口被分割为若干的区域,真正做到了窗口的任意分割。那么我们自己如何创建类似的界面,也实现窗口的任意的分

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

 我们在使用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号。例如下面的代码将创建2×2的窗格。

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

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

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

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

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

  此函数向静态切分的窗口的网格填充视图。在将视图于切分窗口联系在一起的时候必须先将切分窗口创建好。参数含义同上。与动态创建相比,静态创建的代码要简单许多,而且可以最多创建16×16的窗格。不同的窗格我们可以使用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
}
/* 何问起 hovertree.com */

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()
};/* 何问起 hovertree.com */
/////////////////////////////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;
} /* 何问起 hovertree.com */

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

 

 

推荐:http://www.cnblogs.com/roucheng/p/cpptimu.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/120351.html原文链接:https://javaforall.net

(0)
上一篇 2021年12月27日 上午6:00
下一篇 2021年12月27日 上午7:00


相关推荐

  • 微信授权网页扫码登录php,PHP实现微信开放平台扫码登录源码

    微信授权网页扫码登录php,PHP实现微信开放平台扫码登录源码1、首先到微信开放平台申请https://open.weixin.qq.com/获取到appid和APPSECRET,前台显示页面如下html>varobj=newWxLogin({id:”login_container”,appid:”wxed782be999f86e0e”,scope:”snsapi_login”,redirect_uri:encodeURICompon…

    2022年6月3日
    34
  • matlab如何读取路径下所有图片_matlab保存到指定文件夹

    matlab如何读取路径下所有图片_matlab保存到指定文件夹之前的matlab学习中接触了各种图片的处理方式和算法函数,现在考虑的是如何保存和输出图片matlab中的图片保存方式imwrite函数imwrite函数是和imread函数配套的图片读取输出函数,写法和imread函数一样imwrite(I,‘lena.jpg’)需要注意的是在保存之前需要保存一个句柄I=getimage(gcf)但是问题在于imwrite函数保存的图片是已经定义过的图片在以下代…

    2025年11月2日
    6
  • 多层感知器的基本特征

    多层感知器的基本特征多层感知器的基本特征 Rosenblatt 感知器本质上是一个单层神经网络 这一网络局限于线性可分模式的分类问题 自适应滤波采用了 Widrow 和 Hoff 的 LMS 算法 这一算法也是基于权值可调的单个线性神经元 这也限制了这一算法的计算能力 为了克服感知器和 LMS 算法的实际局限 我们考虑所熟知的多层感知器这一神经网络结构 下面的三点揭示了多层感知器的基本特征 1 网络中每个神经元模型包含一个可微的非线性激活函数 2 网络中包括一个或多个隐藏在输人和输出神

    2026年3月26日
    2
  • 海康SDK接口调用的主要流程

    海康SDK接口调用的主要流程SDK 接口调用的主要流程 初始化 SDK 功能 对整个网络 SDK 系统的初始化 内存预分派等操作 声明 BOOLNET DVR Init 返回值 TRUE 表示成功 FALSE 表示失败 接口返回失败请调用 NET DVR GetLastError 获取错误码 通过错误码判断出错原因 设置连接超时时间功能这部分为可选 用于设置 SDK 中的网络连接超时时间 用户可以根据

    2026年3月17日
    2
  • 补码的加减法运算_简述补码减法运算的规则

    补码的加减法运算_简述补码减法运算的规则补码的加减法运算本文内容参考自王达老师的《深入理解计算机网络》一书<中国水利水电出版社>一、补码加法:1、补码的加法运算两个机器数相加的补码可以先通过分别对两个机器数求补码,然后再相加得到,在采用补码形式表示时,进行加法运算可以把符号位和数值位一起进行运算(若符号位有进位,导致了益出,则直接舍弃),结果为两数之和的补码形式。示例1:求两个十进制数的和35+18。首先,规…

    2025年11月12日
    5
  • 40OutputStreamWriter

    40OutputStreamWriter写的转换流,写我们相要写的编码文件java.io.OutputStreamWriteretendsWriterInputStreamReader是字节流通向字符流的桥梁,它使用指定的Charset将要写入流中的字符编码成字节。(编码:把能看懂的变成看不懂的)继承父类,共性成员方法:voidwrite(intc)写入单个字符voidwrite(char[])写入字符数组abstractvoidwriter(char[]cbuf,intoff,intlen)…

    2025年10月31日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号