CSplitterWnd Ŭ·¡½º º¯È½ÃÅ°±â
ÀÌ ³»¿ëÀº ¸¶ÀÌÅ©·Î¼ÒÇÁÆ®¿þ¾î 1999³â 6¿ù ³»¿ëÁß "¿ø¸®±¸Çö, UI¸¦ °ÈÇϸé ÄÄÇ»ÅÍ°¡ Áñ°Ì´Ù[1], Ư¼öÇÑ UI¸¦ Àû¿ëÇÑ ½ºÇø®ÅÍ ¸¸µé±â"ÀÇ ³»¿ëÀ» Âü°íÇÑ °ÍÀÔ´Ï´Ù.
ÀÌ ±Û¿¡¼ ¼Ò°³ÇÑ ¿¹Á¦ÀÇ ¼Ò½º ¿øº» ±ÛÀÇ ¿¹Á¦¼Ò½º
1. CSplitterWnd Ŭ·¡½º¶õ?
CSplitterWnd Ŭ·¡½º´Â SDI¿¡¼ Çѹø¿¡ µÑ ÀÌ»óÀÇ ºä¸¦ º¸¿©ÁÖ´Â °ÍÀ» °¡´ÉÇÏ°Ô Çϴ Ŭ·¡½ºÀÔ´Ï´Ù. MDIÀÇ °æ¿ì child À©µµ¿ì¸¦ ¿©·¯°³ ¸¸µé¾î¼ µÑ ÀÌ»óÀÇ ºä¸¦ º¸¿©ÁÖÁö¸¸, CSplitterWnd Ŭ·¡½º¸¦ »ç¿ëÇϸé ÇÑ È¸éÀ» µÎ °³ ³»Áö´Â ±× ÀÌ»ó ºÐÇÒÇؼ ÇѲ¨¹ø¿¡ º¸¿©ÁÝ´Ï´Ù.
2. CSplitterWnd ÀÇ ÆÄ»ýŬ·¡½º ¸¸µé±â
CSplitterWnd¸¦ º¯È½ÃÅ°·Á¸é ±× Ŭ·¡½º¿¡¼ »ó¼Ó¹ÞÀº »õ·Î¿î Ŭ·¡½º¸¦ ¸¸µé¾î¾ß ÇÕ´Ï´Ù. ÀÌ°Ç ºä³ª µµÅ¥¸ÕÆ®, ¸ÞÀÎ ÇÁ·¹ÀÓ Å¬·¡½ºµµ ¸¶Âù°¡ÁöÁÒ.
Ŭ·¡½ººä¿¡¼ »ý¼ºÇÏ¸é µÇ´Âµ¥, Á¶±Ý ¹®Á¦°¡ ÀÖ½À´Ï´Ù. ¹Ù·Î Ŭ·¡½º À§Àúµå¿¡¼ Áö¿øÇÏ´Â º£À̽º Ŭ·¡½º¿¡´Â CSplitterWnd ´Â ºüÁ®Àֱ⠶§¹®ÀÔ´Ï´Ù.
¹°·Ð ÀÌ °æ¿ì¿¡µµ ¹æ¹ýÀº ÀÖ½À´Ï´Ù. ¸î°¡Áö°¡ Àִµ¥¿ä. Çϳª¾¿ Àå´ÜÁ¡°ú ÇÔ²² ¼Ò°³Çϱâ·Î ÇÏÁÒ.
1) ClassViewÀÇ °¡Àå À§ÂÊ Ç׸ñ¿¡¼ ¸¶¿ì½º ¿ÞÂʹöÆ°À» Ŭ¸¯ÇÏ¿© ³ª¿À´Â New Class¿¡¼ Class typeÀ» Generic Class·Î ¼±ÅÃÇÕ´Ï´Ù. ±×¸®°í, ¾Æ·¡ÂÊ¿¡ ÀÖ´Â Base class(es) ºÎºÐ¿¡ Á÷Á¢ CSplitterWnd¸¦ ½á³Ö½À´Ï´Ù.
ÀÌ·¸°Ô ¸¸µç Ŭ·¡½º´Â Ŭ·¡½º À§Àúµå¿¡¼ Áö¿øµÇÁö ¾Ê½À´Ï´Ù. ½ÇÁ¦ ÄÚµå ³»¿ëÀ» º¸¸é Ŭ·¡½º À§Àúµå¿¡¼ Áö¿øµÇ´Â Çü½ÄÀÇ ÄÚµå´Â ÀüÇô Æ÷ÇԵǾî ÀÖÁö ¾ÊÀº °ÍÀ» ¾Ë ¼ö ÀÖ½À´Ï´Ù. ½ÇÁ¦·Î ÀÌ ¹æ½ÄÀ¸·Î ´ÙÁß»ó¼ÓÀ» ±¸ÇöÇÒ ¼ö ÀÖ½À´Ï´Ù.
Ŭ·¡½º À§Àúµå¿¡¼ Áö¿øµÇÁö ¾Ê±â ¶§¹®¿¡ »õ·Î¿î ÇÔ¼ö¸¦ Ãß°¡ÇÒ ¶§ Á¶±Ý ¹®Á¦°¡ ÀÖ½À´Ï´Ù. ¹°·Ð ¼ÕÀ¸·Î Á÷Á¢ Ãß°¡ÇÏ¸é µÇÁö¸¸, ÄݹéÇÔ¼öÀÇ °æ¿ì ÀÌ°ÍÀú°Í Ãß°¡ÇÒ °ÍÀÌ ¸¹±â ¶§¹®¿¡ ¼ÕÀÌ ¸¹ÀÌ °¡ÁÒ. Çϳª¸¸ »©¸Ô¾îµµ Á¦´ë·Î µ¹¾Æ°¡Áö ¾Ê±¸¿ä.
2) À§¿Í °°Àº ¹æ¹ý ¸»°í, ´Ù¸¥ ¹æ¹ýÀ» »ç¿ëÇØ º¸ÁÒ. À§¿Í °°Àº À§Ä¡¿¡¼ Class typeÀ» MFC Class·Î ¼±ÅÃÇÕ´Ï´Ù. Base class¸¦ generic CWnd·Î ¼±ÅÃÇÏ°í, Class À̸§À» ÀÔ·ÂÇÑ ´ÙÀ½¿¡ OK ¹öÆ°À» ´©¸¨´Ï´Ù. Ŭ·¡½º À̸§Àº CMySplitterWnd ¶ó°í ÇÏ´Â°Ô ¹«³ÇÏ°ÚÁÒ.
±×·± ´ÙÀ½¿¡ »ý¼ºµÈ Çì´õÆÄÀÏ°ú cpp ÆÄÀÏ¿¡¼ CWnd¸¦ CSplitterWnd·Î ¸ðµÎ ¹Ù²ß´Ï´Ù. Edit ¸Þ´ºÀÇ Replace ±â´ÉÀ» ÀÌ¿ëÇϸé Æí¸®ÇÒ °Ì´Ï´Ù. ÀÌ·¸°Ô Çϸé Ŭ·¡½º À§Àúµå¿¡¼µµ ¹®Á¦¾øÀÌ Áö¿øÀÌ µË´Ï´Ù.
ÀÌ·¸°Ô Çؼ CSplitterWnd ÀÇ ÆÄ»ýŬ·¡½º ÆÄÀÏÀ» ¸¸µé¾ú½À´Ï´Ù.
3) ±×¸®°í MainFrm.h ÆÄÀÏ¿¡¼ ´ÙÀ½ºÎºÐÀ» ¹Ù²ß´Ï´Ù. ÀÌ·¸°Ô Çؼ CSplitterWnd ´ë½Å¿¡ ¿ì¸®°¡ ¸¸µç CMySplitterWnd Ŭ·¡½º·Î ´ëüÇÏ´Â °ÍÀÌÁÒ. ÀÌ CMySplitterWnd Ŭ·¡½ºÀÇ ³»¿ëÀ» Á¶±Ý¾¿ ¹Ù²Ù¾î°¡¸é¼ ¿ì¸®°¡ ¿øÇÏ´Â ºÎºÐÀ» ¸¸µé¾î°¡´Â °ÅÁÒ.
#include "MySplitterWnd.h"
..............................
//
Attributes
protected:
CMySplitterWnd
m_wndSplitter;
3. Á¤Àû ½ºÇø®Æ® ¸¸µé±â
¿©±â¼´Â µ¿Àû ½ºÇø®Æ®¸¦ Á¤Àû ½ºÇø®Æ®·Î ¹Ù²Ù¾î º¸°Ú½À´Ï´Ù.
1) »õ·Î¿î SDI ÇÁ·ÎÁ§Æ®¸¦ ¸¸µì´Ï´Ù. "step 4 of 6" ¿¡¼ ¾Æ·¡ÂÊÀÇ Advanced ¹öÆ°À» ´·¯ ³ª¿À´Â ´ÙÀ̾ó·Î±×¿¡¼ Window Styles ÅÇÀ» ¼±ÅÃÇÏ°í "Use split window" Ç׸ñ¿¡ üũǥ½Ã¸¦ ÇØÁÝ´Ï´Ù.
2) ÀÌ´ë·Î °è¼Ó ÁøÇàÇؼ ÄÄÆÄÀÏÀ» ÇÏ¸é µ¿Àû ½ºÇø®Æ® À©µµ¿ì°¡ ¸¸µé¾îÁý´Ï´Ù. ÀÌ°ÍÀ» Á¶±Ý °íÃļ Á¤Àû ½ºÇø®Æ® À©µµ¿ì¸¦ ¸¸µé °Ì´Ï´Ù. ±×¸®°í °Å±â¼ ¾²ÀÎ CSplitterWndÇüÀÇ º¯¼ö¸¦ »õ·Î ¸¸µé ÆÄ»ýŬ·¡½ºÀÇ º¯¼ö·Î ¹Ù²Ù¾î¼ ¿øÇÏ´Â ÇüÅ·Π¹Ù²Ü °èȹÀÔ´Ï´Ù.
3) ClassView¿¡¼ CMainFrame Ŭ·¡½º¿¡¼ ´ÙÀ½ ÇÔ¼ö¸¦ º¾½Ã´Ù.
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT
/*lpcs*/,
CCreateContext*
pContext)
{
return m_wndSplitter.Create(this,
2,
2, //
TODO: adjust the number of rows, columns
CSize(10,
10), // TODO: adjust the minimum pane size
pContext);
}
ÀÌ ÇÔ¼ö¿¡¼ m_wndWndSplitter º¯¼ö´Â CSplitterWnd Ŭ·¡½ºÀÇ ¸â¹öº¯¼öÀÔ´Ï´Ù. ÀÌ Å¬·¡½ºÀÇ Create ¸â¹öº¯¼ö´Â µ¿Àû ½ºÇø®Æ®¸¦ ¸¸µé¾îÁÖ´Â ÇÔ¼öÀε¥, Á¤Àû ½ºÇø®Æ®¸¦ ¸¸µé±â À§Çؼ´Â CreateStatic ÇÔ¼ö¸¦ »ç¿ëÇÕ´Ï´Ù. À§ÀÇ ³»¿ëÀ» ´ÙÀ½Ã³·³ °íÃÄÁÖ¸é µÇÁÒ.
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT
/*lpcs*/,
CCreateContext*
pContext)
{
if(!m_wndSplitter.CreateStatic(this,
1, 2))
{
TRACE0("Failed
to CreateStatic Splitter\n");
return
FALSE;
}
if(!m_wndSplitter.CreateView(0,
0,
RUNTIME_CLASS(CMySplitView),
CSize(200, 50), pContext))
{
TRACE0("Failed
to Crate First Pane\n");
return
FALSE;
}
if(!m_wndSplitter.CreateView(0,
1,
RUNTIME_CLASS(CMySplitView),
CSize(0, 0), pContext))
{
TRACE0("Failed
to Crate Second Pane\n");
return
FALSE;
}
return
TRUE;
}
ÀÌ·¸°Ô ÇÏ°í ÄÄÆÄÀÏÀ» ÇÏ¸é µ¿Àû ½ºÇø®Æ®¿¡¼ Á¤Àû ½ºÇø®Æ®·Î ¹Ù²ï °ÍÀ» º¼ ¼ö ÀÖÀ» °Ì´Ï´Ù. ¿©±â¼´Â ¾çÂÊ pane¿¡ ÆíÀÇ»ó °°Àº ºä¸¦ º¸¿©ÁÖµµ·Ï ÇßÁö¸¸, º¸Åë »õ·Î¿î ºä¸¦ Ãß°¡Çؼ ¾çÂÊ¿¡ ¼·Î ´Ù¸¥ ºä¸¦ º¸¿©ÁÖ´Â °æ¿ì°¡ ´ëºÎºÐÀÔ´Ï´Ù.
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 -