Working with a Trackbar

My trackbar sample programs allow a user to change or view a trackbar's range, tick frequency, page size, and line size through dialog boxes activated from the Options menu. You create these dialog boxes in the view class. For each dialog box, I wrote a class derived from CDialog and created a member variable for each value I needed from the controls.

For example, the Set Trackbar Range dialog box uses edit controls to let the user enter minimum and maximum values for the range and specify the trackbar to be set, as shown in Figure 2-4. For the trackbar, ClassWizard let me set up a member variable that is an integer between 0 and 2. (How nice that MFC provides this range checking!)

Figure 2-4.

The Set Trackbar Range dialog box.

I did not place restrictions on the actual minimum and maximum range values because you can in fact set the range's minimum value to be greater than the maximum (for instance, a minimum of 10 and a maximum of -1). If you do this, however, your trackbar will track backward (that is, the slider in a vertical trackbar will start at the bottom and move upward). When I run the Set Trackbar Range dialog box, the program simply sets the range on the specified trackbar by using the SetRange member function, as shown here:

CRange::CRange (CWnd *pParent /*=NULL*/)
: CDialog (CRange::IDD, pParent)
{
// {{AFX_DATA_INIT (CRange)
m_Min = 0;
m_Max = 0;
m_Slider = 1;
// }}AFX_DATA_INIT
}

void CRange::DoDataExchange (CDataExchange *pDX)
{
CDialog::DoDataExchange (pDX);
// {{AFX_DATA_MAP (CRange)
DDX_Text (pDX, IDE_MIN, m_Min);
DDX_Text (pDX, IDE_MAX, m_Max);
DDX_Text (pDX, IDE_SLIDER, m_Slider);
DDV_MinMaxInt (pDX, m_Slider, 1, 2);
// }}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP (CRange, CDialog)
// {{AFX_MSG_MAP (CRange)
// }}AFX_MSG_MAP
END_MESSAGE_MAP ()

void CMfctrackView::OnRange ()
{
CRange rangeDlg;

if (rangeDlg.DoModal () == IDOK)
{
switch (rangeDlg.m_Slider)
{
case 1:
m_Slider1.SetRange (rangeDlg.m_Min, rangeDlg.m_Max, TRUE);
break;

case 2:
m_Slider2.SetRange (rangeDlg.m_Min, rangeDlg.m_Max, TRUE);
break;

case 3:
m_Slider3.SetRange (rangeDlg.m_Min, rangeDlg.m_Max, TRUE);
break;

default:
break;
}
}
}

Finally, you can update the status bar to show which trackbar notification is being sent to each trackbar. In C, all of this code is in SLIDER.C, and the handles to the trackbars and the status bar are all within the scope of the window procedure. When using MFC, you need to find a different method because the pointer to the status bar object is not in scope when you need to set its text. You can create a message map entry for the WM_HSCROLL and WM_VSCROLL messages and copy the notification to a character buffer. Then you get a pointer to the status bar and set the text accordingly:

void CMfctrackView::OnHScroll (UINT nSBCode, UINT nPos, 
CScrollBar *pScrollBar)
{
TrackScrolling (nSBCode);

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

void CMfctrackView::OnVScroll (UINT nSBCode, UINT nPos,
CScrollBar *pScrollBar)
{
TrackScrolling (nSBCode);

CView::OnVScroll (nSBCode, nPos, pScrollBar);
}

VOID CMfctrackView::TrackScrolling (UINT nSBCode)
{
BOOL bMsg = TRUE;
char *pMsg = NULL;

switch (nSBCode)
{
case TB_BOTTOM:
pMsg = "TB_BOTTOM";
break;

case TB_ENDTRACK:
pMsg = "TB_ENDTRACK";
break;

case TB_LINEDOWN:
pMsg = "TB_LINEDOWN";
break;

case TB_LINEUP:
pMsg = "TB_LINEUP";
break;

case TB_PAGEDOWN:
pMsg = "TB_PAGEDOWN";
break;

case TB_PAGEUP:
pMsg = "TB_PAGEUP";
break;

case TB_THUMBPOSITION:
pMsg = "TB_THUMBPOSITION";
break;

case TB_THUMBTRACK:
pMsg = "TB_THUMBTRACK";
break;

default:
bMsg = FALSE;
break;
}

if (bMsg == TRUE)
{
CStatusBar* pStatus = (CStatusBar*) GetParentFrame()->
GetDescendantWindow (ID_VIEW_STATUS_BAR);
char szBuf [256];
sprintf (szBuf, "Trackbar message: %s", pMsg);
pStatus->SetPaneText (0, szBuf);
pStatus->UpdateWindow ();
}
}