안녕하세요. 저번 글까지는 스크롤을 만드는 것까지 했는데, 이번 글에서는 약간의 설명과 코드를 바로 첨부해 드리겠습니다.
코드를 하기 앞서 dc와 dcTemp, 그리고 스크롤로 표현 하는 방법을 설명해드리겠습니다.
최종적으로 사용자가 보는 dc화면이 있습니다.
이 dc에서 CRect rect를 이용하여 크기를 구합니다.
그리고 가로 크기는 10000, 세로는 dc 와 같은 dcTemp를 생성해줍니다.
그리고 dcTemp에 0, 100, 200, … , 9900 같이, 100 위치마다 해당 값을 표시해줍니다.
어제 코드에 보면 스크롤을 설정할 때 10000이라는 크기를 줬습니다. dcTemp크기와 같은 값으로 설정해야 계산하기 편합니다.
SCROLLINFO scrInfo;
// ...
scrInfo.nMax = 10000; // 스크롤 최대값
// ...
m_ctlHScroll.SetScrollInfo( &scrInfo ); // 스크롤바 정보 설정
스크롤도 0~10000의 값을 가지고 있고 화면 크기도 0~10000이니까 스크롤의 위치에 따라 dcTemp에서 dc로 BitBlt 하시면 됩니다.
이제 OnPaint에 코딩해보도록 하겠습니다. 아래와 같이 입력해주세요.
void CDisplay::OnPaint()
{
CPaintDC dc( this ); // device context for painting
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
// 그리기 메시지에 대해서는 CWnd::OnPaint()을(를) 호출하지 마십시오.
// 크기 구하기
CRect rect;
GetClientRect( &rect );
// 화면 그리기
CDC dcTemp;
dcTemp.CreateCompatibleDC( &dc );
HBITMAP hbmp = ::CreateCompatibleBitmap( dc, 10000, rect.Height() - 20 ); // 가로 10000 크기로 생성
HBITMAP hbmpOld = (HBITMAP)dcTemp.SelectObject( hbmp );
// 100마다 텍스트 출력
dcTemp.PatBlt( 0, 0, 10000, rect.Height(), WHITENESS );
for ( int iX = 0 ; iX < 10000 ; iX += 100 )
{
CString sX;
sX.Format( _T( "%d" ), iX );
dcTemp.TextOut( iX, (rect.Height() / 2), sX );
}
SCROLLINFO scrInfo;
int iSrcX = 0;
if ( NULL == m_ctlHScroll.GetSafeHwnd() )
{
CRect rectHScroll;
rectHScroll.SetRect( rect.left, rect.top, rect.right, rect.bottom );
m_ctlHScroll.Create(
WS_CHILD | WS_VISIBLE | SBS_HORZ | SBS_BOTTOMALIGN // 속성
, rectHScroll // 위치
, this // 부모 윈도우
, 0 // 스크롤 막대의 컨트롤 ID입니다
);
m_ctlHScroll.ShowScrollBar( TRUE );
scrInfo.cbSize = sizeof( scrInfo );
scrInfo.fMask = SIF_ALL;
scrInfo.nMin = 0; // 스크롤 최소값
scrInfo.nMax = 10000; // 스크롤 최대값
scrInfo.nPage = rect.Width(); // 페이지 번호
scrInfo.nTrackPos = 0; // 드래깅 상태의 트랙바 위치
scrInfo.nPos = 0; // 트랙바 위치
m_ctlHScroll.SetScrollRange( scrInfo.nMin, scrInfo.nMax ); // 범위 설정
m_ctlHScroll.SetScrollPos( scrInfo.nPos ); // 위치 설정
m_ctlHScroll.SetScrollInfo( &scrInfo ); // 스크롤바 정보 설정
}
else
{
if ( FALSE != m_ctlHScroll.GetScrollInfo( &scrInfo ) )
{
iSrcX = scrInfo.nPos; // 현재 스크롤 위치 받아옴
}
}
dc.BitBlt( 0, 0, rect.Width(), rect.Height(), &dcTemp, iSrcX, 0, SRCCOPY ); // 더블 버퍼링
dcTemp.SelectObject( hbmpOld );
::DeleteObject( hbmp );
dcTemp.DeleteDC();
}
OnEraseBkgnd에 아래와 같이 코딩해주세요. return TRUE;는 덮어씌우기를 하는겁니다.
BOOL CDisplay::OnEraseBkgnd( CDC* pDC )
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
return TRUE;
}
HScroll 함수 OnHScroll에 아래와 같이 코딩합니다.
void CDisplay::OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
SCROLLINFO scrInfo;
memset( &scrInfo, 0, sizeof(scrInfo) );
if ( FALSE != m_ctlHScroll.GetScrollInfo( &scrInfo ) )
{
switch ( nSBCode )
{
case SB_LINERIGHT:
scrInfo.nPos+=100;
break;
case SB_LINELEFT:
scrInfo.nPos-=100;
break;
case SB_THUMBTRACK:
case SB_PAGEDOWN:
scrInfo.nPos = nPos;
break;
}
m_ctlHScroll.SetScrollInfo( &scrInfo );
this->Invalidate();
}
CWnd::OnHScroll( nSBCode, nPos, pScrollBar );
}
마우스 휠 이벤트가 발생했을 때 처리하는 함수 OnMouseWheel에 아래와 같이 코딩합니다.
BOOL CDisplay::OnMouseWheel( UINT nFlags, short zDelta, CPoint pt )
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if ( zDelta > 0 )
{
SendMessage( WM_HSCROLL, SB_LINELEFT, NULL );
}
else
{
SendMessage( WM_HSCROLL, SB_LINERIGHT, NULL );
}
return CWnd::OnMouseWheel( nFlags, zDelta, pt );
}
간혹 마우스에 아래와 같이 횡스크롤이 있는데, 이 스크롤에 대한 처리 함수 OnMouseHWheel에 아래와 같이 코딩합니다.
void CDisplay::OnMouseHWheel( UINT nFlags, short zDelta, CPoint pt )
{
// 이 기능을 사용하려면 Windows Vista 이상이 있어야 합니다.
// _WIN32_WINNT 기호는 0x0600보다 크거나 같아야 합니다.
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if ( zDelta > 0 )
{
SendMessage( WM_HSCROLL, SB_LINERIGHT, NULL );
}
else
{
SendMessage( WM_HSCROLL, SB_LINELEFT, NULL );
}
CWnd::OnMouseHWheel( nFlags, zDelta, pt );
}
실행 시켜 확인해 봅니다.
이상으로 CScrollbar를 이용하여 사용자 정의 클래스를 만들어봤습니다.