2009년 01월 03일
Slider Notification Messages

CSliderCtrl의 사용법을 알아보기 위해 MSDN을 확인해 보면 Using CSliderCtrl 이란 제목의 문서를 발견할 수 있습니다. 4개의 단원으로 나뉘어 CSliderCtrl을 사용하는 방법에 대해서 소개하고 있습니다. 


Using CSliderCtrl 


The CSliderCtrl class represents a slider control, which is also called a trackbar. A "slider control" is a window that contains a slider and optional tick marks. When the user moves the slider, using either the mouse or the arrow keys, the slider control sends notification messages to indicate the change.

Slider controls are useful when you want the user to select a discrete value or a set of consecutive values in a range. For example, you might use a slider control to allow the user to set the repeat rate of the keyboard by moving the slider to a given tick mark.

The slider in a slider control moves in increments that you specify when you create it. For example, if you specify that the slider control should have a range of five, the slider can only occupy six positions: a position at the left side of the slider control and one position for each increment in the range. Typically, each of these positions is identified by a tick mark.



이 중에서 Slider Notification Message에 대해서 알아 보도록 하겠습니다. 아래는 Slider Notification Message 에 대한 MSDN의 일부 내용입니다.


Slider Notification Messages 


A slider control notifies its parent window of user actions by sending the parent WM_HSCROLL or WM_VSCROLL messages, depending on the orientation of the slider control. To handle these messages, add handlers for the WM_HSCROLL and WM_VSCROLL messages to the parent window. The OnHScroll and OnVScroll member functions will be passed a notification code, the position of the slider, and a pointer to the CSliderCtrl object. Note that the pointer is of type CScrollBar * even though it points to a CSliderCtrl object. You may need to typecast this pointer if you need to manipulate the slider control.




slider control은 자신을 사용자가 동작 시키면 ( slider를 움직이거나 키보드의 방향키 또는 마우스로 클릭 등 .. ) 부모 윈도우 즉, 자기 자신을 붙인 다이얼 로그나 폼에게 WM_HSCROLL 또는 WM_VSCROLL 메시지를 전달한다고 합니다. 부모 윈도우에서는 이 메시지를 처리해서 slider control을 핸들링 할 수 있다고 합니다. WM_HSCROLL, WM_VSCROLL 메시지의 이벤트 핸들러인 OnHScroll과 OnVScroll의 인자로는 slider control의 동작 형식에 대한 통지 코드와 slider의 현재 위치, 그리고 CSliderCtrl의 객체 포인터가 넘겨진다고 합니다. 이때 CSliderCtrl의 객체 포인터는 CScrollBar* 데이터 형으로 넘어오지만 CSliderCtrl의 객체 포인터 이므로 typecast을 통해서 slider control을 핸들링 할 수 있다고 합니다.

※ 어설픈 영어 실력으로 인해 오역이 있을 수 있습니다.



그럼 위 MSDN의 내용을 바탕으로 간단한 예제 프로그램을 만들어 보겠습니다.

우선, 시나리오는 아래 그림 처럼 slider control을 각각 하나씩 만들고 이 slider가 움직일 때 각 slider의 위치를 보여 줄 edit control을 각각 하나씩 만듭니다. (이하, 상단의 slider control과 edit control은 각각 slider_1, edit_1이라고 부르며 하단의 것들은 slider_2, edit_2라고 하겠습니다.) slider_1을 동작시키면 slider_1의 position value를 edit_1에 출력하고 slider_2를 동작시키면 slider_2의 position value를 edit_2에 출력합니다.

그리고 각각 slider_1의 범위는 0 ~ 100, slider_2의 범위는 -100 ~ 0 그리고 초기값은 50 ~ -50으로 주겠습니다.

아래 코드는 OnInitDialog()의 초기화 작업을 하는 부분에 넣어 줍니다.


m_sldCtrl_1.SetRange(0, 100);
m_sldCtrl_1.SetPos(50);


m_strOutputSliderValue_1.Format(_T("%d"), m_sldCtrl_1.GetPos());


m_sldCtrl_2.SetRange(-100, 0);
m_sldCtrl_2.SetPos(-50);


m_strOutputSliderValue_2.Format(_T("%d"), m_sldCtrl_2.GetPos());


UpdateData(false);


OnHScroll 이벤트 핸들러에서 slider control의 동작에 대한 처리를 합니다.


void CSliderNotificationMessagesDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
 // TODO: Add your message handler code here and/or call default
 //
 // pScrollBar를 CliderCtrol* 로 typecast 합니다.
 //
 CSliderCtrl* pSlider = (CSliderCtrl*) pScrollBar;
 //
 // 현재 동작 된 slider control의 position value를 _nPos에 보관합니다.
 //
 int _nPos = pSlider->GetPos();
 //
 // pSlider는 현재 동작한 slider control의 객체 포인터이므로 포인터 값을 비교해서 현재 동작한
 //  컨트롤의 값을 출력 할 edit control에 현재 position value를 셋팅합니다.
 //
 if(&m_sldCtrl_1 == pSlider)
 {
  m_strOutputSliderValue_1 = _T("");
  m_strOutputSliderValue_1.Format(_T("%d"), _nPos);
 }
 else if(&m_sldCtrl_2 == pSlider)
 {
  m_strOutputSliderValue_2 = _T("");
  m_strOutputSliderValue_2.Format(_T("%d"), _nPos);
 }

 UpdateData(FALSE);

 CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}


* 실행 결과 ..


동작은 잘 하지만, 한가지 궁금증이 생겼습니다. Slider Notification Message 에 대한 MSDN의 내용을 보면 아래와 같은 내용이 있었습니다. 특히, 하늘색 상자의 글을 보시면 분명히 slider의 postion이 OnHScroll 이벤트 핸들러의 인자로 넘어온다고 되어있습니다.


The OnHScroll and OnVScroll member functions will be passed a notification code, the position of the slider, and a pointer to the CSliderCtrl object.


즉, 아래 OnHScroll 이벤트 핸들러의 원형에서 보면 nPos를 말합니다.


afx_msg void OnHScroll(
   UINT nSBCode,
   UINT nPos,
   CScrollBar* pScrollBar
);


그렇다면 위 에제 코드처럼 int _nPos = pSlider->GetPos(); 이렇게 직접 slider 컨트롤의 값을 얻어서 처리 하지 않고 nPos를 이용해서 처리할 수는 없을까요?? 제가 예제를 만들 때 OnHScroll의 인자로 넘어 온 nPos 값을 사용하려고 해 봤더니 slider를 동작 시킬때는 값이 잘 넘어 오다가 slider 동작을 멈췄을때 (마우스 드래그를 끝내고 마우스 좌버튼에서 손을 때었을때 ..) nPos의 값이 0으로 변하는 현상을 발견하였습니다. 이러한 동작을 감시하기 위해 아래와 같이 MSDN의 예제 코드를 이용해서 OnHScroll 이벤트 핸들러로 넘어오는 nSBCode( slider 동작에 대한 통지 코드 )와 nPos의 값을 TRACE 해 보았습니다.


void CSliderNotificationMessagesDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
 // TODO: Add your message handler code here and/or call default

 
// Get the minimum and maximum scroll-bar positions.
 int minpos;
 int maxpos;
 pScrollBar->GetScrollRange(&minpos, &maxpos);
 maxpos = pScrollBar->GetScrollLimit();

 // Get the current position of scroll box.
 int curpos = pScrollBar->GetScrollPos();

 // Determine the new position of scroll box.
 switch (nSBCode)
 {
 case SB_LEFT:      // Scroll to far left.
  curpos = minpos;
  TRACE(_T("SB_LEFT\t%d\n"), curpos);
  break;

 case SB_RIGHT:      // Scroll to far right.
  curpos = maxpos;
  TRACE(_T("SB_RIGHT\t%d\n"), curpos);
  break;

 case SB_ENDSCROLL:   // End scroll.
  TRACE(_T("SB_ENDSCROLL\t%d\n"), nPos);
  break;

  //////////////////////////////////////////////////////////////////////////
  //
  // Be pressing "left arrow" or "right arrow" key.
  //
 case SB_LINELEFT:      // Scroll left.
  if (curpos > minpos)
   curpos--;
  TRACE(_T("SB_LINELEFT\t%d\n"), curpos);
  break;

 case SB_LINERIGHT:   // Scroll right.
  if (curpos < maxpos)
   curpos++;
  TRACE(_T("SB_LINERIGHT\t%d\n"), curpos);
  break;

  //////////////////////////////////////////////////////////////////////////
  //
  // Be pressing "Page Up" or "Page Down" key.
  //
 case SB_PAGELEFT:    // Scroll one page left.
  {
   // Get the page size.
   SCROLLINFO   info;
   pScrollBar->GetScrollInfo(&info, SIF_ALL);

   if (curpos > minpos)
    curpos = max(minpos, curpos - (int) info.nPage);

   TRACE(_T("SB_PAGELEFT\t%d\n"), curpos);
  }
  break;

 case SB_PAGERIGHT:      // Scroll one page right.
  {
   // Get the page size.
   SCROLLINFO   info;
   pScrollBar->GetScrollInfo(&info, SIF_ALL);

   if (curpos < maxpos)
    curpos = min(maxpos, curpos + (int) info.nPage);

   TRACE(_T("SB_PAGERIGHT\t%d\n"), curpos);
  }
  break;

  //////////////////////////////////////////////////////////////////////////
  //
  //  Be moving wheel of mouse
  //
 case SB_THUMBPOSITION: // Scroll to absolute position. nPos is the position
  curpos = nPos;      // of the scroll box at the end of the drag operation.

  TRACE(_T("SB_THUMBPOSITION\t%d\n"), curpos);

  break;

  //////////////////////////////////////////////////////////////////////////
  //
  // Be moving cursor of slider
  //
 case SB_THUMBTRACK:   // Drag scroll box to specified position. nPos is the
  curpos = nPos;     // position that the scroll box has been dragged to.

  TRACE(_T("SB_THUMBTRACK\t%d\n"), curpos);
  break;
 }

 // Set the new position of the thumb (scroll box).
 pScrollBar->SetScrollPos(curpos);

 

 CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}


* 실행 결과 ..













실행 결과를 보시면 슬라이더 통지 메시지가 SB_ENDSCROLL 일때 즉, slider 동작을 마쳤을 때 nPos의 값이 0인 것을 알 수 있습니다. 그래서 nPos 를 사용하지 않고 int _nPos = pSlider->GetPos(); 이렇게 처리 했습니다.

* 예제 프로젝트

SliderNotificationMessages.zip
by greenfrog | 2009/01/03 10:51 | C++ / WIN32 / MFC | 트랙백 | 덧글(0)
트랙백 주소 : http://greenfrog7.egloos.com/tb/1286598
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]

:         :

:

비공개 덧글



<< 이전 페이지 | 다음 페이지 >>