程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 窗口分割,mfc窗口分割

窗口分割,mfc窗口分割

編輯:C++入門知識

窗口分割,mfc窗口分割


 我們在使用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
}
/* 何問起 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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved