CSplitterWnd Ŭ·¡½º º¯È­½ÃÅ°±â

 

ÀÌ ³»¿ëÀº ¸¶ÀÌÅ©·Î¼ÒÇÁÆ®¿þ¾î 1999³â 6¿ù ³»¿ëÁß "¿ø¸®±¸Çö, UI¸¦ °­È­Çϸé ÄÄÇ»ÅÍ°¡ Áñ°Ì´Ù[1], Ư¼öÇÑ UI¸¦ Àû¿ëÇÑ ½ºÇø®ÅÍ ¸¸µé±â"ÀÇ ³»¿ëÀ» Âü°íÇÑ °ÍÀÔ´Ï´Ù.

 ÀÌ ±Û¿¡¼­ ¼Ò°³ÇÑ ¿¹Á¦ÀÇ ¼Ò½º         ¿øº» ±ÛÀÇ ¿¹Á¦¼Ò½º

1. CSplitterWnd Ŭ·¡½º¶õ?

 CSplitterWnd Ŭ·¡½º´Â SDI¿¡¼­ Çѹø¿¡ µÑ ÀÌ»óÀÇ ºä¸¦ º¸¿©ÁÖ´Â °ÍÀ» °¡´ÉÇÏ°Ô Çϴ Ŭ·¡½ºÀÔ´Ï´Ù. MDIÀÇ °æ¿ì child À©µµ¿ì¸¦ ¿©·¯°³ ¸¸µé¾î¼­ µÑ ÀÌ»óÀÇ ºä¸¦ º¸¿©ÁÖÁö¸¸, CSplitterWnd Ŭ·¡½º¸¦ »ç¿ëÇϸé ÇÑ È­¸éÀ» µÎ °³ ³»Áö´Â ±× ÀÌ»ó ºÐÇÒÇؼ­ ÇѲ¨¹ø¿¡ º¸¿©ÁÝ´Ï´Ù.

 

2. CSplitterWnd ÀÇ ÆÄ»ýŬ·¡½º ¸¸µé±â

 CSplitterWnd¸¦ º¯È­½ÃÅ°·Á¸é ±× Ŭ·¡½º¿¡¼­ »ó¼Ó¹ÞÀº »õ·Î¿î Ŭ·¡½º¸¦ ¸¸µé¾î¾ß ÇÕ´Ï´Ù. ÀÌ°Ç ºä³ª µµÅ¥¸ÕÆ®, ¸ÞÀÎ ÇÁ·¹ÀÓ Å¬·¡½ºµµ ¸¶Âù°¡ÁöÁÒ.

 Å¬·¡½ººä¿¡¼­ »ý¼ºÇÏ¸é µÇ´Âµ¥, Á¶±Ý ¹®Á¦°¡ ÀÖ½À´Ï´Ù. ¹Ù·Î Ŭ·¡½º À§Àúµå¿¡¼­ Áö¿øÇÏ´Â º£À̽º Ŭ·¡½º¿¡´Â CSplitterWnd ´Â ºüÁ®Àֱ⠶§¹®ÀÔ´Ï´Ù.

 ¹°·Ð ÀÌ °æ¿ì¿¡µµ ¹æ¹ýÀº ÀÖ½À´Ï´Ù. ¸î°¡Áö°¡ Àִµ¥¿ä. Çϳª¾¿ Àå´ÜÁ¡°ú ÇÔ²² ¼Ò°³Çϱâ·Î ÇÏÁÒ.

 

3. Á¤Àû ½ºÇø®Æ® ¸¸µé±â

¿©±â¼­´Â µ¿Àû ½ºÇø®Æ®¸¦ Á¤Àû ½ºÇø®Æ®·Î ¹Ù²Ù¾î º¸°Ú½À´Ï´Ù.

 

4. CSplitterWnd Ŭ·¡½ºÀÇ Çì´õÆÄÀÏ ³»¿ë

  CSplitterWnd Ŭ·¡½ºÀÇ Çì´õÆÄÀÏÀÇ ³»¿ëÀº AfxExt.h ÆÄÀÏ¿¡, cpp ÀÇ ³»¿ëÀº WinSplit.cpp ÆÄÀÏ¿¡ ÀÖ½À´Ï´Ù.

 ´ÙÀ½Àº AfxExt.h ÆÄÀÏ¿¡¼­ CSplitterWnd Ŭ·¡½ºÀÇ Çì´õÆÄÀÏ ³»¿ë¸¸ »Ì¾Æ³õÀº °Ì´Ï´Ù.

/////////////////////////////////////////////////////////////////////////////
// Splitter Window

#define SPLS_DYNAMIC_SPLIT  0x0001
#define SPLS_INVERT_TRACKER 0x0002  // obsolete (now ignored)

class CSplitterWnd : public CWnd
{
        DECLARE_DYNAMIC(CSplitterWnd)

// Construction
public:
        CSplitterWnd();
        // Create a single view type splitter with multiple splits
        BOOL Create(CWnd* pParentWnd,
                                int nMaxRows, int nMaxCols, SIZE sizeMin,
                                CCreateContext* pContext,
                                DWORD dwStyle = WS_CHILD | WS_VISIBLE |
                                        WS_HSCROLL | WS_VSCROLL | SPLS_DYNAMIC_SPLIT,
                                UINT nID = AFX_IDW_PANE_FIRST);

        // Create a multiple view type splitter with static layout
        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);

// Attributes
public:
        int GetRowCount() const;
        int GetColumnCount() const;

        // information about a specific row or column
        void GetRowInfo(int row, int& cyCur, int& cyMin) const;
        void SetRowInfo(int row, int cyIdeal, int cyMin);
        void GetColumnInfo(int col, int& cxCur, int& cxMin) const;
        void SetColumnInfo(int col, int cxIdeal, int cxMin);

        // for setting and getting shared scroll bar style
        DWORD GetScrollStyle() const;
        void SetScrollStyle(DWORD dwStyle);

        // views inside the splitter
        CWnd* GetPane(int row, int col) const;
        BOOL IsChildPane(CWnd* pWnd, int* pRow, int* pCol);
        BOOL IsChildPane(CWnd* pWnd, int& row, int& col); // obsolete
        int IdFromRowCol(int row, int col) const;

        BOOL IsTracking();  // TRUE during split operation

// Operations
public:
        virtual void RecalcLayout();    // call after changing sizes

// Overridables
protected:
        // to customize the drawing
        enum ESplitType { splitBox, splitBar, splitIntersection, splitBorder };
        virtual void OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rect);
        virtual void OnInvertTracker(const CRect& rect);

public:
        // for customizing scrollbar regions
        virtual BOOL CreateScrollBarCtrl(DWORD dwStyle, UINT nID);

        // for customizing DYNAMIC_SPLIT behavior
        virtual void DeleteView(int row, int col);
        virtual BOOL SplitRow(int cyBefore);
        virtual BOOL SplitColumn(int cxBefore);
        virtual void DeleteRow(int rowDelete);
        virtual void DeleteColumn(int colDelete);

        // determining active pane from focus or active view in frame
        virtual CWnd* GetActivePane(int* pRow = NULL, int* pCol = NULL);
        virtual void SetActivePane(int row, int col, CWnd* pWnd = NULL);

protected:
        CWnd* GetActivePane(int& row, int& col); // obsolete

public:
        // high level command operations - called by default view implementation
        virtual BOOL CanActivateNext(BOOL bPrev = FALSE);
        virtual void ActivateNext(BOOL bPrev = FALSE);
        virtual BOOL DoKeyboardSplit();

        // synchronized scrolling
        virtual BOOL DoScroll(CView* pViewFrom, UINT nScrollCode,
                BOOL bDoScroll = TRUE);
        virtual BOOL DoScrollBy(CView* pViewFrom, CSize sizeScroll,
                BOOL bDoScroll = TRUE);

// Implementation
public:
        virtual ~CSplitterWnd();
#ifdef _DEBUG
        virtual void AssertValid() const;
        virtual void Dump(CDumpContext& dc) const;
#endif

        // implementation structure
        struct CRowColInfo
        {
                int nMinSize;       // below that try not to show
                int nIdealSize;     // user set size
                // variable depending on the available size layout
                int nCurSize;       // 0 => invisible, -1 => nonexistant
        };

protected:
        // customizable implementation attributes (set by constructor or Create)
        CRuntimeClass* m_pDynamicViewClass;
        int m_nMaxRows, m_nMaxCols;

        // implementation attributes which control layout of the splitter
        int m_cxSplitter, m_cySplitter;         // size of splitter bar
        int m_cxBorderShare, m_cyBorderShare;   // space on either side of splitter
        int m_cxSplitterGap, m_cySplitterGap;   // amount of space between panes
        int m_cxBorder, m_cyBorder;             // borders in client area

        // current state information
        int m_nRows, m_nCols;
        BOOL m_bHasHScroll, m_bHasVScroll;
        CRowColInfo* m_pColInfo;
        CRowColInfo* m_pRowInfo;

        // Tracking info - only valid when 'm_bTracking' is set
        BOOL m_bTracking, m_bTracking2;
        CPoint m_ptTrackOffset;
        CRect m_rectLimit;
        CRect m_rectTracker, m_rectTracker2;
        int m_htTrack;

        // implementation routines
        BOOL CreateCommon(CWnd* pParentWnd, SIZE sizeMin, DWORD dwStyle, UINT nID);
        virtual int HitTest(CPoint pt) const;
        virtual void GetInsideRect(CRect& rect) const;
        virtual void GetHitRect(int ht, CRect& rect);
        virtual void TrackRowSize(int y, int row);
        virtual void TrackColumnSize(int x, int col);
        virtual void DrawAllSplitBars(CDC* pDC, int cxInside, int cyInside);
        virtual void SetSplitCursor(int ht);
        CWnd* GetSizingParent();

        // starting and stopping tracking
        virtual void StartTracking(int ht);
        virtual void StopTracking(BOOL bAccept);

        // special command routing to frame
        virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
        virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);

        //{{AFX_MSG(CSplitterWnd)
        afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
        afx_msg void OnMouseMove(UINT nFlags, CPoint pt);
        afx_msg void OnPaint();
        afx_msg void OnLButtonDown(UINT nFlags, CPoint pt);
        afx_msg void OnLButtonDblClk(UINT nFlags, CPoint pt);
        afx_msg void OnLButtonUp(UINT nFlags, CPoint pt);
        afx_msg void OnCancelMode();
        afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
        afx_msg void OnSize(UINT nType, int cx, int cy);
        afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
        afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
        afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
        afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpcs);
        afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
        afx_msg void OnDisplayChange();
        //}}AFX_MSG
        DECLARE_MESSAGE_MAP()
};

 

5. ½ºÇø´¹ÙÀÇ Å©±âº¯°æ

CSplitterWnd¸¦ º¸¸é ½ºÇø´¹ÙÀÇ Æø °è»ê°ú ÆгÎÀÇ ¹èÄ¡¸¦ À§ÇÑ ¸î °³ÀÇ ¸â¹öº¯¼ö¸¦ °¡Áö°í Àִµ¥, ±× ³»¿ëÀº ´ÙÀ½°ú °°½À´Ï´Ù. 

protected:
        ............................

        // implementation attributes which control layout of the splitter
        int m_cxSplitter, m_cySplitter;         // size of splitter bar
        int m_cxBorderShare, m_cyBorderShare;   // space on either side of splitter
        int m_cxSplitterGap, m_cySplitterGap;   // amount of space between panes
        int m_cxBorder, m_cyBorder;             // borders in client area

º¯¼ö¸í

º¯¼ö ŸÀÔ

»ç¿ë ¿ëµµ

m_cxSplitter

Á¤¼öÇü

¼öÁ÷,¼öÆò ºÐÇÒ ¹ÙÀÇ µÎ²²¸¦ Á¤ÇÑ´Ù.

m_cySplitter

m_cxBorderShare

Á¤¼öÇü

ºÐÇÒ ¹ÙÀÇ ¾ç³¡ÀÌ Å׵θ®(Border)¿Í °ãÃÄÁö´Â Á¤µµ

m_cyBorderShare

m_cxSplitterGap

Á¤¼öÇü

ºÐÇÒ ¹Ù¸¦ »çÀÌ¿¡ µÐ ¾çÂÊ ºä »çÀÌÀÇ °ø°£

m_cySplitterGap

m_cxBorder

Á¤¼öÇü

ºÐÇÒ Ã¢ÀÇ Å׵θ®°ª, ÀÌ °ª¸¸Å­ ºä°¡ ¾ÈÂÊ¿¡ À§Ä¡ÇÑ´Ù.

m_cyBorder

 

 ½ÇÁ¦ CSplitterWndÀÇ »ý¼ºÀÚ¿¡¼± Windows 95 ÀÌ»óÀÏ °æ¿ì, À§ÀÇ °ªµéÀº ´ÙÀ½°ú °°ÀÌ Á¤ÇØÁý´Ï´Ù.

                m_cxSplitter = m_cySplitter = 4;
                m_cxBorderShare = m_cyBorderShare = 1;
                m_cxSplitterGap = m_cySplitterGap = 4 + 1 + 1;
                ASSERT(m_cxBorder == 0 && m_cyBorder == 0);

À§ÀÇ °ªµéÀ» Á¶Á¤ÇÏ¸é ½ºÇø´¹ÙÀÇ µÎ²²¸¦ Á¶ÀýÇÒ ¼ö ÀÖ½À´Ï´Ù.

±×·±µ¥ ½ÇÁ¦ÀÇ °æ¿ì m_cxSplitter ¿Í m_cxSplitterGap ÀÌ °°Áö ¾ÊÀ¸¸é ¹®Á¦°¡ »ý±âÁÒ.

  ±×·± Çö»óÀÌ »ý±â´Â ¿øÀÎÀº ÀÌ µÎ °³ÀÇ ¼­·Î ´Ù¸¥ º¯¼ö°¡ °íÀ¯ÀÇ ¸ñÀû¾øÀÌ È¥¿ëµÇ¾î »ç¿ëµÇ¾ú±â ¶§¹®ÀÔ´Ï´Ù.

m_cxSplitter´Â ºÐÇÒâ À̵¿½Ã ¹ÝÀüµÇ´Â ºÎºÐÀÇ Æø °è»ê°ú À̵¿ÈÄ ´Ù½Ã ¹«È¿È­µÇ´Â(±×·ÁÁö´Â) ¿µ¿ªÀÇ °è»ê¿¡¸¸ »ç¿ëµÉ »Ó ½ÇÁ¦ ºÐÇÒ Ã¢ÀÇ Æø °è»ê¿¡´Â »ç¿ëµÇÁö ¾ÊÁö¿ä. ±×¸®°í m_cxSplitterGap Àº ºÐÇÒ¹ÙÀÇ Æø °è»ê°ú ¾çÂÊâÀÇ À§Ä¡°è»ê¿¡´Â »ç¿ëµÇÁö¸¸ ½ÇÁ¦ ºÐÇÒ Ã¢À» ±×¸®´Â µ¥´Â »ç¿ëµÇÁö ¾Ê½À´Ï´Ù. Áï, À§ÀÇ Ç¥¿¡¼­ ¼³¸íÇÑ ³»¿ëÀÌ Á¦´ë·Î ÁöÄÑÁö°í ÀÖÁö ¾Ê´Ù´Â °ÍÀÌÁÒ.

ÇÏ¿©°£ ÀÌ µÎ °ªÀ» °°°Ô Á¤ÇØÁÖ¸é µË´Ï´Ù.

 Áö±Ý±îÁöÀÇ ³»¿ëÀ» Âü°íÇÏ¿©, CMySplitterWnd ÀÇ »ý¼ºÀÚ¸¦ ´ÙÀ½Ã³·³ °íÄ¡¸é ½ºÇø´¹ÙÀÇ ÆøÀ» Á¶ÀýÇÒ ¼ö ÀÖ½À´Ï´Ù. ¿©±â¼­´Â ÆøÀ» 24 pixel·Î Á¤Çß½À´Ï´Ù. ¹°·Ð ÇÊ¿ä¿¡ µû¶ó ÀÌ °ªÀ» ´Ù¸£°Ô º¯È­½ÃÅ°¸é µË´Ï´Ù. ¿©±â¼­ 24 pixel·Î Á¤ÇÑ ÀÌÀ¯´Â ½ºÇø®Å͸¦ ³ªÅ¸³»±â À§ÇÑ ¹ÙÀδõ ±×¸²ÀÇ ÆøÀÌ 24 pixel À̱⠶§¹®ÀÔ´Ï´Ù.

 

CMySplitterWnd::CMySplitterWnd()
{
        AFX_ZERO_INIT_OBJECT(CWnd);

        m_cxSplitter = m_cySplitter = 24;
        m_cxBorderShare = m_cyBorderShare = 0;
        m_cxSplitterGap = m_cySplitterGap = 24;
        // ASSERT(m_cxBorder == 0 && m_cyBorder == 0);
        m_cxBorder = m_cyBorder = 2;  
}

 

6. ½ºÇø´¹ÙÀÇ ¸ð¾çº¯°æ

 À©µµ¿ì¿¡ ¹«¾ð°¡¸¦ ±×¸®±â À§Çؼ­´Â WM_PAINT ¸Þ½ÃÁöÀÇ Çڵ鷯ÀÎ OnPaint() ÇÔ¼ö¸¦ ó¸®ÇÏ¸é µË´Ï´Ù. CSplitterWnd Ŭ·¡½ºµµ ¸¶Âù°¡Áö·Î OnPaint() ÇÔ¼ö¿¡¼­ OnDrawSplitter() ¶ó´Â °¡»óÇÔ¼ö¸¦ È£ÃâÇؼ­ ½ºÇø´¹Ù¸¦ ±×¸®°Ô µË´Ï´Ù. ÀÌ ÇÔ¼öÀÇ ¿øÇüÀº ´ÙÀ½°ú °°½À´Ï´Ù.

virtual void OnDrawSplitter( CDC* pDC, ESplitType nType, const CRect& rect );

>> ÆĶó¹ÌÅÍ :

¡ß pDC : µð¹ÙÀ̽º ÄÁÅؽºÆ®¿¡ ´ëÇÑ Æ÷ÀÎÅÍ, ¸¸¾à ÀÌ °ªÀÌ NULLÀÌ¸é ºÐÇÒâÀÌ ±×·ÁÁö±â Àü¿¡ Framework¿¡ ÀÇÇØ CWndÀÇ RedrawWindow ÇÔ¼ö°¡ ºÒ¸®¾îÁø °ÍÀÌ´Ù.

¡ß nType : enum ŸÀÔÀÇ ESplitType¿¡ ´ëÇÑ °ª. ´ÙÀ½ÀÇ ¿¹ Áß ÇϳªÀÌ´Ù.

 splitBox

 ºÐÇÒ ²ø±â »óÀÚ

 splitBar

 µÎ °³ÀÇ ºÐÇÒ Ã¢ »çÀÌ¿¡ º¸¿©Áö´Â ¹Ù

 splitIntersection

 ºÐÇÒ Ã¢ÀÇ ±³Â÷Á¡. À§µµ¿ì95¿¡¼­ ½ÇÇàµÉ ¶§´Â »ç¿ëµÇÁö ¾Ê´Â´Ù

 splitBorder

 ºÐÇÒ Ã¢ÀÇ Å׵θ®

 ¡ß rect : ºÐÇÒ Ã¢ÀÇ Å©±â¿Í ¸ð¾çÀ» ÃæÁ·½ÃÅ°±â À§ÇÑ CRectÀÇ ·¹ÆÛ·±½º°ª

 

 CSplitterWnd Ŭ·¡½º¸¦ ¿À¹ö¶óÀ̵åÇصµ ½ºÇø´¹ÙÀÇ ¸ð¾çÀ» ¹Ù²Ù´Â °ÍÀÌ °¡´ÉÇÏÁö¸¸, ÀÌ ÇÔ¼ö´Â ½ºÇø´¹Ù »Ó¸¸ÀÌ ¾Æ´Ï¶ó Å׵θ®(Border)±îÁö ±×¸®±â ¶§¹®¿¡, ÀÌ ÇÔ¼ö¸¦ °íÃļ­ »ç¿ëÇϱ⿡´Â ºÒÆíÇÑ Á¡ÀÌ ÀÖ½À´Ï´Ù. ¿©±â¼­´Â °¡¿îµ¥ ½ºÇø´¹Ù Çϳª¸¦ »çÀÌ¿¡ µÐ ¾çÂÊ ÆäÀÎÀÌ ÀÖ´Â ÇüÅÂÀ̹ǷΠ±×³É OnPaint() ÇÔ¼ö¸¦ °íÃļ­ ÀÛ¾÷À» ÇÏ´Â °ÍÀÌ ´õ ³´°Ú³×¿ä.

´ÙÀ½°ú °°ÀÌ OnPaint() ÇÔ¼ö ¿Ü¿¡ µÎ °³ÀÇ ÇÔ¼ö¸¦ ´õ Ãß°¡ÇÕ´Ï´Ù.

 

 void CMySplitterWnd::OnPaint()
{
        ASSERT_VALID(this);
        CPaintDC dc(this); // device context for painting
        // TODO: Add your message handler code here
        CRect rcClient;
        GetClientRect(&rcClient);
        
        // Á¾ÀÌ ¸ð¾çÀÇ ¹è°æ È­¸éÀ» ±×¸°´Ù.
        OnDrawBackground(&dc, rcClient);

        // ¹ÙÀδõ ¸ð¾çÀÇ ½ºÇø´¹Ù¸¦ ±×¸°´Ù.
        OnDrawBindSplitter(&dc, rcClient);

        // CSplitterWnd¿¡ ÀÖ´Â ÇÔ¼ö¸¦ »ç¿ëÇØ Å׵θ®¸¦ ±×¸°´Ù.
        OnDrawSplitter(&dc, splitBorder, rcClient);
        // Do not call CSplitterWnd::OnPaint() for painting messages
}

void CMySplitterWnd::OnDrawBackground(CDC *pDC, const CRect &rectArg)
{
        pDC->FillSolidRect(rectArg, ::GetSysColor(COLOR_APPWORKSPACE));

        CRect rcPage = rectArg;
        rcPage.top += 10;
        rcPage.bottom -= 10;
        rcPage.left += 10;
        rcPage.right = rectArg.left + m_pColInfo[0].nCurSize + m_cxSplitterGap/2 - 2;
       
        // ¿ÞÂÊ ÆгΠ¿µ¿ªÀ» ±×¸°´Ù.
        pDC->FillSolidRect(rcPage, ::GetSysColor(COLOR_WINDOW));

        rcPage.left = rcPage.right + 4;
        rcPage.right = rectArg.right - 10;
       
        // ¿À¸¥ÂÊ ÆгΠ¿µ¿ªÀ» ±×¸°´Ù.
        pDC->FillSolidRect(rcPage, ::GetSysColor(COLOR_WINDOW));
}

void CMySplitterWnd::OnDrawBindSplitter(CDC *pDC, const CRect &rectArg)
{
        CBitmap splitBmp;
        splitBmp.LoadBitmap(IDB_BINDSPLIT);

        CDC dcBitmap;
        dcBitmap.CreateCompatibleDC(pDC);

        CBitmap *pOldBitmap = (CBitmap *)dcBitmap.SelectObject(&splitBmp);  

        CRect rcSplit = rectArg;
        rcSplit.left += m_pColInfo[0].nCurSize;
        rcSplit.right = rcSplit.left + m_cxSplitterGap;

        // ÀÏÁ¤ÇÑ °£°ÝÀ» À¯ÁöÇÏ¸ç ¹ÙÀδõ ¸ð¾çÀÇ ±×¸²À» ±×¸°´Ù.
        for(int y=rectArg.top+20; y<rectArg.bottom-20; y+=16) {
                rcSplit.top = y;
                rcSplit.bottom = rcSplit.top + 16;
                pDC->BitBlt(rcSplit.left, rcSplit.top, rcSplit.Width(), rcSplit.Height(),
                        &dcBitmap, 0, 0, SRCCOPY);
        }

        dcBitmap.SelectObject(pOldBitmap);
        dcBitmap.DeleteDC();

        splitBmp.DeleteObject();                
}

 

 ¿©±â±îÁö ÀÛ¾÷À» ÇÏ°í ÄÄÆÄÀÏÀ» Çؼ­ °á°ú¸¦ º¾´Ï´Ù. ÄÄÆÄÀÏµÇ°í ³ª¼­ óÀ½ º¸ÀÌ´Â °á°ú´Â Á¦´ë·Î µÈ °Íó·³ º¸À̴±º¿ä. ½ºÇø´¹Ù°¡ Á¦´ë·Î ³ªÅ¸³ª´Â °ÍÀ» º¸¸é Á¦´ë·Î µÈ °Í °°±âµµ ÇÕ´Ï´Ù. ÇÏÁö¸¸ ¿ì¼± °è¼Ó °¡º¸±â·Î ÇÏÁÒ.

¿©±â¼­ OnDrawBackground() ÇÔ¼ö¸¦ º¸¸é ´ÙÀ½°ú °°Àº Äڵ带 º¼ ¼ö ÀÖ½À´Ï´Ù. ÀÌ Äڵ尡 ÀǹÌÇÏ´Â ¹Ù¸¦ ÇÑ ÁÙ¾¿ Çؼ®Çغ¸¸é...

        // ¹è°æÀ» COLOR_APPWORKSPACE »öÀ¸·Î ±×¸°´Ù.
        pDC->FillSolidRect(rectArg, ::GetSysColor(COLOR_APPWORKSPACE));

        CRect rcPage = rectArg;     // À§, ¾Æ·¡, ¿ÞÂÊÀ» 10 Çȼ¿¾¿
        rcPage.top += 10;               // ¾ÈÂÊÀ¸·Î À§Ä¡½ÃŲ´Ù.
        rcPage.bottom -= 10;         
        rcPage.left += 10;
        rcPage.right = rectArg.left + m_pColInfo[0].nCurSize + m_cxSplitterGap/2 - 2;
       
        // ¿ÞÂÊ ÆгΠ¿µ¿ªÀ» ±×¸°´Ù.
        pDC->FillSolidRect(rcPage, ::GetSysColor(COLOR_WINDOW));

 

À§¿Í °°ÀÌ ¹è°æÀ» ±×¸®°Ô µË´Ï´Ù. ±×¸®°í, OnDrawBindSplitter() ÇÔ¼ö¿¡¼­ ½ºÇø´¹Ù¸¦ ±×¸®°Ô µË´Ï´Ù.

 ¿©±â±îÁö ¼³¸íÀ» µè°í ³ª¼­ ´Ù½Ã ÄÄÆÄÀÏµÇ¾î ½ÇÇàµÈ ÇÁ·Î±×·¥À» º¸¸é, ¹«¾ð°¡ Ʋ¸° °ÍÀ» ¾Ë ¼ö ÀÖÀ» °Ì´Ï´Ù. ºÐ¸í Äڵ忡¼­´Â 10 Çȼ¿¾¿ ¾ÈÂÊÀ¸·Î µé¾î°¡¼­ Á¾À̸ð¾çÀÇ ¹ÙÅÁÀÌ ±×·ÁÁöµµ·Ï ¸¸µé¾ú´Âµ¥, ½ÇÇàµÈ Äڵ忡¼­´Â ºä°¡ È­¸é¿¡ ²Ë Â÷ ÀÖ°í, ½ºÇø´¹Ù¸¸ÀÌ Á¦´ë·Î º¸ÀÏ »ÓÀÔ´Ï´Ù.

 ½ºÇø´¹Ù¸¦ Ŭ¸¯ÇØ º¸¸é 10 Çȼ¿¾¿ ¾ÈÀ¸·Î µé¾î°¡ º¸À̱ä ÇÕ´Ï´Ù¸¸, ½ºÇø´¹Ù¸¦ ¿òÁ÷ÀÌ¸é ´Ù½Ã ¿ø·¡´ë·Î ²Ë Âù È­¸éÀ¸·Î µ¹¾Æ°¡´Â °ÍÀ» ¾Ë ¼ö ÀÖ½À´Ï´Ù. ±× ¿øÀÎÀº CSplitterWnd Ŭ·¡½º°¡ ÀÚ½ÅÀÌ ¼ÒÀ¯ÇÑ ºä¸¦ ½ºÇø´¹Ù°¡ À̵¿µÈ ¸¸Å­¸¸ ´Ù½Ã ±×¸®°í, ÀÚ±âÀÚ½ÅÀ» ¶Ç ´Ù½Ã ±×¸®±â ¶§¹®¿¡ Àá½Ã ±×·¸°Ô º¸ÀÌ´Â °ÍÀÌÁÒ.

 °á±¹ ÇØ°áÃ¥Àº ³»ºÎ ºäÀÇ À§Ä¡¸¦ Á¶ÀýÇÏ´Â ¹æ¹ý»ÓÀÔ´Ï´Ù.

 

7. ºäÀÇ À§Ä¡ Á¶Á¤

 ³»ºÎÀÇ ºä À§Ä¡¸¦ Á¶ÀýÇϱâ À§Çؼ­, CSplitterWnd Ŭ·¡½ºÀÇ RecalcLayout() À̶ó´Â ÇÔ¼ö¸¦ ÀÌ¿ëÇÕ´Ï´Ù. ÀÌ ÇÔ¼ö´Â ºÐÇÒâ¿¡¼­ ³»ºÎÀÇ Ã¢ Å©±â°¡ º¯È­µÇ¾úÀ» ¶§ âÀ» ´Ù½Ã ¹è¿­Çϱâ À§ÇØ ºÒ·ÁÁö´Â ÇÔ¼öÀÔ´Ï´Ù. RecalcLayout() ÇÔ¼ö´Â À©µµ¿ì °ü¸®¸¦ À§ÇØ Á¸ÀçÇϴ Ŭ·¡½ºÀÎ CFrameWnd¿¡¼­ »ó¼Ó¹ÞÀº Ŭ·¡½º¿Í CSplitterWnd¿¡¸¸ Àִµ¥, ÀÚ½ÅÀÌ ¼ÒÀ¯ÇÑ À©µµ¿ì¸¦ Àç¹èÄ¡ÇÏ´Â ¿ªÇÒÀ» ÇÏÁÒ.

 ºÐÇÒ Ã¢À» À̵¿Çϰųª ÇÁ·¹ÀÓ »çÀÌÁî°¡ º¯°æµÈ °æ¿ì, µ¿Àû ºÐÇÒâ¿¡¼­Ã³·³ »õ·Î¿î ºä°¡ »ý¼ºµÇ´Â °æ¿ì µî¿¡ ºÒ·ÁÁö´Â CSplitterWnd::OnRecalcLayout() ÇÔ¼ö´Â ³»ºÎ¿¡ Á¸ÀçÇÏ´Â À©µµ¿ìµéÀÇ À§Ä¡¸¦ Àç¹èÄ¡ÇÏ°í À̵¿µÈ À©µµ¿ì¿Í ½ºÇø´¹Ù¸¦ ´Ù½Ã ±×¸³´Ï´Ù.

 

void CMySplitterWnd::RecalcLayout()
{
        ASSERT_VALID(this);

        CSplitterWnd::RecalcLayout();

        // ¸ðµç ÆгΠÀ§Ä¡¸¦ Àç¹èÄ¡ÇÑ´Ù.
        CRect rcClient;

        GetClientRect(&rcClient);

        CRect rcPage = rcClient;
        rcPage.top += 10;
        rcPage.bottom -= 10;
        for(int col=0; col<m_nCols; col++) {
                CWnd* pWnd = (CWnd *)GetPane(0, col);
                ASSERT_VALID(pWnd);

                if(col == 0) {
                        // ¿À¸¥ÂÊ ÆгΠÀ§Ä¡Á¶Á¤
                        rcPage.left += 10;
                        rcPage.right = rcClient.left + m_pColInfo[col].nCurSize +
                                m_cxSplitterGap/2 - 2;
                
                } else {
                        // ¿ÞÂÊ ÆгΠÀ§Ä¡ Á¶Á¤
                        rcPage.left = rcPage.right + 4;
                        rcPage.right = rcClient.right - 10;
                }

                CRect rect = rcPage;
                rect.DeflateRect(10, 10);

                if(col == 0)
                        rect.right -= 10;
                else
                        rect.left += 10;

                pWnd->SetWindowPos(NULL, rect.left, rect.top,
                        rect.Width(), rect.Height(), SWP_NOZORDER);
        }
}

 

 Áö±Ý±îÁö ÄÚµùÀ» ÇÏ°í ÄÄÆÄÀÏ Çؼ­ °á°ú¸¦ º¸¸é, ½ºÇø´¹Ù°¡ ¾à°£ ¿ÞÂÊÀ¸·Î Ä¡¿ìÄ£ °ÍÀ» ¾Ë ¼ö ÀÖ½À´Ï´Ù. ¿òÁ÷¿©º¸°Å³ª ½ºÇø´¹Ù¸¦ ´õºíŬ¸¯Çغ¸¸é ¿ÞÂÊÀ¸·Î ¿òÁ÷Àδٴ °É ¾Ë ¼ö ÀÖÁÒ. ÀÌ°ÍÀ» º¸Á¤Çϱâ À§ÇØ StopTracking() ÇÔ¼ö¸¦ Ãß°¡½Ãŵ´Ï´Ù.

 ¸¶¿ì½º ¹öÆ°À» ³õ´Â ¼ø°£ ºÒ·ÁÁö´Â ÀÌ ÇÔ¼ö´Â, °¢ âµéÀÇ º¯°æµÈ Å©±â¸¦ °è»êÇϱâ À§ÇØ TrackColumnSize() ¶ó´Â ÇÔ¼ö¿¡ À̵¿µÈ ½ºÇø´¹ÙÀÇ ¿ÞÂÊ ÁÂÇ¥¸¦ ÀÎÀÚ·Î ³Ö¾î È£ÃâÇÕ´Ï´Ù. ÀÌ ÇÔ¼ö´Â ÀÌ ÁÂÇ¥¸¦ ¹Þ¾Æ °¢°¢ÀÇ ºä¿¡ ´ëÇÑ ÀÌ»óÀûÀÎ Å©±â(½ºÇø´¹ÙÀÇ Å©±â¸¦ °í·ÁÇÏÁö ¾ÊÀº Å©±â)¸¦ °è»êÇϴµ¥, ÈÄ¿¡ RecalcLayout() ÇÔ¼ö¿¡¼­ ÀÌ ÀÌ»óÀûÀÎ Å©±â¿¡¼­ ½ÇÁ¦Å©±â¸¦ ±¸Çϱâ À§ÇØ ´Ù½Ã ½ºÇø´¹Ù¿Í ¾çÂÊ Å׵θ® Å©±â¸¸Å­ÀÇ °ªÀ» °¨¼Ò½ÃÅ°¹Ç·Î, °á±¹ ½ºÇø´¹ÙÀÇ Æø¸¸Å­ ¿ÞÂÊÀ¸·Î À̵¿µÈ À§Ä¡·Î ¸ðµç °ÍÀÌ Á¤·ÄµË´Ï´Ù. ÀÌ·¯ÇÑ ¿ÀÂ÷¸¦ º¸»óÇϱâ À§ÇØ °á±¹ °¡»óÇÔ¼öÀÎ StopTracking() ÇÔ¼ö¸¦ ¿À¹ö¶óÀ̵åÇؼ­ ¹Ì¸® ÀÌ °ª¸¸Å­À» Á¶Á¤ÇØ ±â¹Ý Ŭ·¡½ºÀÇ ÇÔ¼ö¸¦ ºÒ·¯ÁÖ¸é ¸ðµç °ÍÀÌ ÇØ°áµÇÁÒ.

 

void CMySplitterWnd::StopTracking(BOOL bAccept)
{
        ASSERT_VALID(this);

        // ½ºÇø´¹ÙÀÇ À§Ä¡¸¦ À̵¿ÇÏ´Â ÁßÀ̶ó¸é ´Ù½Ã µÇµ¹¸°´Ù.
        if(!m_bTracking)
                return;

        if(bAccept) {
                // m_htTrack´Â ¼öÁ÷ ½ºÇø´¹ÙÀÇ °æ¿ì 201°ú 215»çÀÌÀÇ °ªÀ» °¡Áü
                if(m_htTrack >= 201 && m_htTrack <= 215)
                        m_rectTracker.OffsetRect(m_cxSplitter - m_cxBorder * 2, 0);
        }

        CSplitterWnd::StopTracking(bAccept);
}

 

- the end of this article -