본문 바로가기
C & C++/MFC 컨트롤

분할 윈도우(Splitter)

by izen8 2012. 9. 3.
반응형

하나의 View 영역을 분할하여 사용할 수 있는 윈도우를 의미합니다.

여기서 분할이라는 의미는 화면 영역을 나누어 사용한다는 의미로 각 영역은 동일한 데이터를 공유할 수 있으며 화면에 표시되는 방식에만 차이가 있는 것을 의미합니다.

분할윈도우를 컨트롤하는 윈도우 클래스는 CSplitterWnd입니다.

이 클래스가 프레임윈도우에 설정되고 이 윈도우위에 여러 개의 View윈도우들이 설정될 수 있는 것 입니다.

분할윈도우를 설정하고자 할 때는 AppWizard Step4에서 Advance항목을 선택하고 분할윈도우 스타일을 설정해 주어야 합니다.

1) 분할 윈도우의 종류

 

정적 분할 윈도우 프로그램이 실행 될 때 영역이 분할된 상태로 실행되며 영역의 크기를 조절할 수는 있지만 분할된 영역을 제거할 수는 없는 분할 윈도우
동적 분할 윈도우 분할된 영역의 크기를 조절할 수 있을 뿐 아니라 분할된 영역을 제거할 수 있는 윈도우

 

 

2) CSplitterWnd 클래스의 멤버함수

 

Create() 동적 분할 윈도우 생성
CreateStatic() 정적 분할 윈도우 생성
CreateView() 정적 분할 윈도우의 영역 생성
GetColumnCount() 가로로 분할 된 영역의 수를 구함
GetColumnInfo() 지정된 분할 영역의 정보(가로길이, 최소길이)를 구함
GetRowCount() 세로로 분할 된 영역의 수를 구함
GetRowInfo() 지정된 분할 영역의 정보(세로길이, 최소길이)를 구함
RecalcLayout() 분할 윈도우를 다시 표시
DeleteColumn() 지정된 가로 영역을 제거
DeleteRow() 지정된 세로 영역을 제거
 

 

 

4.1. 다중 분할 윈도우 만들기 

 

상/하, 좌/우가 복합적으로 분할된 다중 분할 윈도우를 생성하는 소스 코드 (아래의 그림과 같이 분할하는 코드).

  • // 분할 윈도우 객체 선언{protected:      CSplitterWnd    m_wndSplitterSub;       // 상/하 분할};// 분할 윈도우 생성 코드 구현        CCreateContext* pContext)    // 윈도우 클라이언트 영역 크기 얻기    GetClientRect( &rect );    // STEP 1: 메인 윈도우의 좌/우 분할
         // m_wndSplitterMain.SetColumnInfo( 0, 250, 10 );
         m_wndSplitterMain.CreateView( 0, 0, RUNTIME_CLASS( CViewA ),
         m_wndSplitterSub.CreateStatic( &m_wndSplitterMain, 2, 1,             m_wndSplitterMain.IdFromRowCol( 0, 1 ) );     // 참고 2 : 상/하 윈도우 크기 지정     // m_wndSplitterSub.SetRowInfo( 1, 250, 10 );     // SETP 2-1: 상/하 분할 윈도우의 View 생성     m_wndSplitterSub.CreateView( 0, 0, RUNTIME_CLASS( CViewB ),     m_wndSplitterSub.CreateView( 1, 0, RUNTIME_CLASS( CViewC ),
    }// 분할 윈도우의 스크롤바 없애기BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/,{                2, 1,                   // 행 및 열의 개수를 지정                pContext,}// 분할 윈도우의 크기 조절하기{
        {            m_wndSplitter.GetClientRect( &rect );             m_wndSplitter.SetRowInfo( 0, rect.Height() / 2, 10 );   // 첫번째 행의 크기를 지정

         } 
    분할 윈도우의 Client Edge 는 CWnd 클래스를 상속 받은 다른 클래스와 달리 윈도우 스타일을 사용하지 않고 CSplitterWnd 클래스에서 직접 그린다. 따라서 CSplitterWnd 클래스를 상속 받아서 Client Edge 를 그리는 함수(가상 함수)를 재정의해야 한다.DrawAllSplitBars() 함수참고> 두 함수의 자세한 코드는 아래의 파일을 참고한다.$(VCInstallDir)atlmfc\include\afxext.h
    //#pragma once
    class CSplitterWndEx : public CSplitterWnd     DECLARE_DYNAMIC( CSplitterWndEx )public:     virtual ~CSplitterWndEx();     // 가상함수 재정의     virtual void OnDrawSplitter( CDC* pDC, ESplitType nType, const CRect& rect );     // 특정 View 의 Client Edge 를 지워야 될 경우 재정의 한다.
         DECLARE_MESSAGE_MAP()public://      afx_msg void OnPaint();
    //#include "StdAfx.h"
    #define CX_BORDER                               (1)


    {
    {
    END_MESSAGE_MAP()void CSplitterWndEx::OnDrawSplitter( CDC* pDC, ESplitType nType, const CRect& rectArg )     if( ( 0 == rectArg.left ) && ( 0 == rectArg.top ) )             // 좌상단(0,0) 에서 시작하는 View 에 대하여 Client Edge 를 지운다.
                 {                     return;             ASSERT_VALID(pDC);             //--------------------------------------------------------------             CRect rect = rectArg;             pDC->Draw3dRect( rect, ::GetSysColor( COLOR_BTNFACE ), ::GetSysColor( COLOR_BTNFACE ) );             pDC->Draw3dRect( rect, ::GetSysColor( COLOR_BTNFACE ), ::GetSysColor( COLOR_BTNFACE ) );             return;
         CSplitterWnd::OnDrawSplitter( pDC, nType, rectArg );
  • }
  •      // 다른 View 는 동일하게 동작하도록 OnDrawSplitter() 함수를 호출한다.
  •      }
  •  
  •              rect.InflateRect( -CX_BORDER, -CY_BORDER );
  •  
  •  
  •  
  •              }
  •                      RedrawWindow( rectArg, NULL, RDW_INVALIDATE | RDW_NOCHILDREN );
  •              if( NULL == pDC )
  •              // - 원리: 창의 기본색과 동일한게 Client Edge 를 그린다.
  •      {
  • {
  •  
  • BEGIN_MESSAGE_MAP( CSplitterWndEx, CSplitterWnd )
  • }
  • CSplitterWndEx::~CSplitterWndEx()
  • }
  • CSplitterWndEx::CSplitterWndEx()
  • IMPLEMENT_DYNAMIC( CSplitterWndEx, CSplitterWnd )
  • // CSplitterWndEx 클래스
  • #define CY_BORDER                               (1)
  • // 상수 선언
  • #include "SplitterWndEx.h"
  •  
  • // SplitterWndEx.cpp : CSplitterWndEx 클래스 구현
  • };
  •      // 특정 View 의 Client Edge 를 지워야 될 경우 재정의 한다.
  •  
  • protected:
  • //      virtual void DrawAllSplitBars(CDC* pDC, int cxInside, int cyInside);
  •  
  • protected:
  •  
  •      CSplitterWndEx();
  •  
  • {
  • // CSplitterWndEx 클래스
  •  
  •  
  • // SplitterWndEx.h : CSplitterWndEx 클래스 선언
  • */
  • $(VCInstallDir)atlmfc\src\mfc\winsplit.cpp
  • OnPaint() 함수 (WM_PAINT 메시지 재정의)
  • 특정 Pane (View) 의 Client Edge 를 지워야 될 경우, 다음의 두 함수를 재정의 한다.
  • /*
  • // 분할 윈도우의 Client Edge 지우기
  • }
  •              m_wndSplitter.RecalcLayout();
  •              // 열의 크기를 지정할 경우 SetColumnInfo() 함수 사용
  •              m_wndSplitter.SetRowInfo( 1, rect.Height() / 2, 10 );   // 두번째 행의 크기를 지정
  •  
  •             CRect rect;
  •     if( m_bSplitterCreated )        // 주의> 창이 열린 경우에만 적용 가능하다.
  •     CFrameWnd::OnSize( nType, cx, cy );
  • void CMainFrame::OnSize( UINT nType, int cx, int cy )
  •  
  •                 WS_CHILD | WS_VISIBLE | SPLS_DYNAMIC_SPLIT );   // 기본 스타일 중에서 WS_HSCROLL 와 WS_VSCROLL 를 제거
  •                 CSize(100, 100),        // 최소 창 크기를 지정
  •         return m_wndSplitter.Create( this,
  •         CCreateContext* pContext )
  •  
  •  
  •      return TRUE;
  •              CSize( 0, nHeight ), pContext );
  •              CSize( 0, nHeight ), pContext );
  •      int nHeight = rect.Height() / 2;
  •  
  •      // m_wndSplitterSub.SetRowInfo( 0, 250, 10 );
  •  
  •              WS_CHILD | WS_VISIBLE,
  •      // STEP 2: 우측 분할 윈도우의 상/하 분할
  •              CSize( 200, 0 ), pContext )
  •      // STEP 1-1: 좌측 분할 윈도우의 View 생성
  •      // m_wndSplitterMain.SetColumnInfo( 1, 250, 10 );
  •      // 참고 1: 좌/우 윈도우 크기 지정
  •     m_wndSplitterMain.CreateStatic( this, 1, 2 );
  •  
  •     CRect rect;
  • {
  • BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,
  •  
  •  
  •       CSplitterWnd    m_wndSplitterMain;      // 좌/우 분할
  • // 특성입니다.
  • class CMainFrame : public CFrameWnd
  •  


  • [Dialog / Splitter Bar] Splitter Bar 를 고정시킬 수 있는 CSplitterWnd 클래스 C & C++/MFC Dialog Splitter Bar 를 고정시킬 수 있는 방법이 MFC 의 CSplitterWnd 클래스에는 존재하는지 찾아 보았지만 존재하지 않더군요. 그래서, CSplitterWnd 를 상속받아서 Splitter Bar 를 고정시킬 수 있는 클래스를 작성해 보았습니다. 아래는 Splitter Bar 를 고정시킬 수 있는 CMySplitterWnd 클래스 소스 코드입니다. // Header File class CMySplitterWnd : public CSplitterWnd { DECLARE_DYNAMIC(CMySplitterWnd) public: CMySplitterWnd(); virtual ~CMySplitterWnd(); void LockBar( ); void UnlockBar( ); protected: DECLARE_MESSAGE_MAP() bool m_bLockBar; public: afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); afx_msg void OnMouseMove(UINT nFlags, CPoint point); }; // Source File IMPLEMENT_DYNAMIC(CMySplitterWnd, CSplitterWnd) CMySplitterWnd::CMySplitterWnd() : m_bLockBar(false) { } CMySplitterWnd::~CMySplitterWnd() { } BEGIN_MESSAGE_MAP(CMySplitterWnd, CSplitterWnd) ON_WM_LBUTTONDOWN() ON_WM_SETCURSOR() ON_WM_MOUSEMOVE() END_MESSAGE_MAP() /** * @brief Splitter Bar 를 고정시킨다. */ void CMySplitterWnd::LockBar( ) { m_bLockBar = true; } /** * @brief Splitter Bar 를 움직일 수 있게 한다. */ void CMySplitterWnd::UnlockBar( ) { m_bLockBar = false; } void CMySplitterWnd::OnLButtonDown(UINT nFlags, CPoint point) { if( m_bLockBar == false ) { CSplitterWnd::OnLButtonDown(nFlags, point); } } BOOL CMySplitterWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { if( m_bLockBar ) { return CWnd::OnSetCursor(pWnd, nHitTest, message); } return CSplitterWnd::OnSetCursor(pWnd, nHitTest, message); } void CMySplitterWnd::OnMouseMove(UINT nFlags, CPoint point) { if( m_bLockBar ) { CWnd::OnMouseMove(nFlags, point); } else { CSplitterWnd::OnMouseMove(nFlags, point); } }

 

반응형

댓글