視窗分割

来源:http://www.cnblogs.com/roucheng/archive/2016/06/11/fenge.html
-Advertisement-
Play Games

我們在使用OutLook或者NetAnt等工具的時候,一般都會被其複雜的界面所吸引,在這些界面中視窗被分割為若幹的區域,真正做到了視窗的任意分割。 那麼我們自己如何創建類似的界面,也實現視窗的任意的分割呢?要解決這個問題,在Visual C++6.0編程中就需要使用到MFC提供的CSplitterW ...


 我們在使用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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這是我登陸後設置cookie的方法,本來cookieValueName是用FormsAuthentication.FormsCookieName替代的,突然有一天發總是得到null值,(目前情況也不明,可能是多個cookie的問題[也不太像,之前好好的,突然就變了])之後,直接改名傳固定值"CQSP ...
  • java常量池技術 java中常量池技術說的通俗點就是java級別的緩存技術,方便快捷的創建一個對象。當需要一個對象時,從池中去獲取(如果池中沒有,就創建一個並放入池中),當下次需要相同變數的時候,不用重新創建,從而節省空間。 java八種基本類型的包裝類和對象池 java中的基本類型的包裝類、其中 ...
  • Java程式 --創建游標包 --存儲過程 推薦:http://www.cnblogs.com/roucheng/p/3504465.html ...
  • 作為一個經驗豐富的C/C++程式員, 肯定親手寫過各種功能的代碼, 比如封裝過資料庫訪問的類, 封裝過網路通信的類,封裝過日誌操作的類, 封裝過文件訪問的類, 封裝過UI界面庫等, 也在實際的項目中應用過, 但是回過頭仔細想想,其實以前自己寫過的這些代碼,只能是在特定的項目或者特定的環境中使用, 對 ...
  • 相關:http://www.cnblogs.com/roucheng/p/cfenge.html ...
  • 一、GCC簡介: The GNU Compiler Collection,通常簡稱GCC,是一套由GNU開發的編譯器集,為什麼是編輯器集而不是編譯器呢?那是因為它不僅支持C語言編譯,還支持C++, Ada, Objective C等許多語言。另外GCC對硬體平臺的支持,可以所無所不在,它不僅支持X8 ...
  • 很多的同學很少使用、或者乾脆不瞭解不可變類(Immutable Class)。直觀上很容易認為Immutable類效率不高,或者難以理解他的使用場景。其實不可變類是非常有用的,可以提高並行編程的效率和優化設計。讓我們跳過一些寬泛的介紹,從一個常見的並行編程場景說起: 假設系統需要實時地處理大量的訂單... ...
  • 在連sqlite資料庫時,用fetchall()查詢結果,是用row[0],row[1]這樣的方式來列印每列的結果 但是我想用row[“欄位名”]方式查詢怎麼辦? MySQLdb的實現方法是: conn=MySQLdb.connect(..., cursorclass=MySQLdb.cursors ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...