Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CRangeSlider - a Ctrl for Selecting a Range or Interval

0.00/5 (No votes)
8 Apr 2002 1  
Have you ever searched for a nice way to select a subrange from an interval? This may be the solution for you.

Sample Image - CRangeSlider.gif

Introduction

Have you ever searched for a nice way to select a subrange from an interval? Yes? Have you read Ben Shneiderman's "Designing the user Interface" or seen Spotfire? No? Well, that doesn't matter, because this control is just like the one described and used there.

The user can restrict a range in the interval [Min, Max] by sliding the right and left arrow or choose an interval by clicking and dragging the interval itself.

In addition the control can display yet another range, inside the interval painted in yellow, which for example shows the range of values you really have displayed elsewhere.

You can either use the control in a horizontal or vertical direction and for more flexibility you can exchange the meaning of left and right.

General Usage

0. Add Sources

As Step 0 add the necessary source files to your project:
  • RangeSlider.h
  • RangeSlider.cpp
  • MemDC.h

1. Create Member

Then create a member variable
  CRangeSlider c_RangeSlider;
in one of your projects classes.

2. Initialize and Create

Add a "Custom Control" to your dialog or formview template. Use "MFCRangeSlider" as window class (without quotes). You have to add a line to DoDataExchange of your class:
DDX_Control(pDX, IDC_YOURID, c_RangeSlider);

In OnInitialUpdate or OnInitDialog add code to initialize the control:

    // Set Minimum and Maximum.

  c_RangeSlider.SetMinMax(m_Min,m_Max);
    // Set Left and Right Arrows

  c_RangeSlider.SetRange(m_Left,m_Right);
    // Set "Visual" range.

  c_RangeSlider.SetVisualMinMax(m_VisualMin, m_VisualMax);

Alternatively you can create and position the control in OnInitDialog or OnInitialUpdate:

  CRect rc (10,10,300,30);
  c_RangeSlider.Create(WS_CHILD |WS_VISIBLE|PBS_SMOOTH| WS_TABSTOP , 
                       rc, this, IDC_YOURID);

3. React on Changes

If the user then changes the arrow' positions, the parent window will be sent a registered window message RANGE_CHANGED, so add to the parents message map:
  ON_REGISTERED_MESSAGE(RANGE_CHANGED, OnRangeChange)
and in the message handler read the new positions out:
LRESULT CRangeCtrlDlg::OnRangeChange(WPARAM /* wParam */, LPARAM /* lParam */) {
  c_RangeSlider.GetRange(m_Left, m_Right);
  //

  // Do what you have to do.

  // ...

  // 

  return static_cast<LRESULT>(0);
}

CRangeSlider API

void Create(DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, 
            UINT nID, CCreateContext *pContext = NULL);

Create the Window at the given Position, with the given parent window, etc. (that's all CWnd::Create-stuff).

// Intervall [Min, Max] of Slider.

void SetMinMax(double min, double max);      // Set Interval

void GetMinMax(double &min, double &max);    // Get Interval

double GetMin(void);                         // Read out Min

double GetMax(void);                         // Read out Max

Set or read the values for the left and right edge of the control, that is the interval within which the arrow-positions will be. Note that if you give them in the wrong order, the control will exchange them (so min should be < max). The arrow positions (left and right) will change, if they do not fit into the given interval.
// Intervall [Left, Right] of Slider

void SetRange(double left, double right);     // Set selected Range in [min, max] 

double GetLeft(void);                         // Get Position of Left arrow

double GetRight(void);                        // Get Position of Right arrow

void GetRange(double &left, double &right);   // Get Left and Right 

Set the position of the arrows. After the call the position will be valid, i.e. if you give values left > right, the positions are set to a valid position or if you give values outside of [min, max] the values will be restricted to the interval.

Read out the positions of the left and right arrow.

// Intervall [VisualMin, VisualMax]

void SetVisualMinMax(double VisualMin, double VisualMax);      // Set Intervall

double GetVisualMinMax(double &VisualMin, double &VisualMax);  // Read Intervall

double GetVisualMin(void);  // Read VisualMin

double GetVisualMax(void);  // Read VisualMax

Set the values for the "visual" range. If you give an interval not inside [min, max] the "visual" range will be adjusted. Note that you have to enable display by a call to SetVisualMode

Read out the values of the "visual" range. Note that you have to enable display of the "visual" range by a call to SetVisualMode

Modes

// Visual Mode

void SetVisualMode(BOOL bVisualMinMax = TRUE);
BOOL GetVisualMode(void) { return m_bVisualMinMax; };
Set and read the status of the "VisualMode". Toggles display of the visual range.
// Vertical Mode

void SetVerticalMode(BOOL bVerticalMode = TRUE);
BOOL GetVerticalMode(void);
Set Vertical Mode if the slider should display vertical (like a horizontal or vertical ProgressCtrl). You have to take care of the windows position and orientation for yourself.
// Inverted Mode

void SetInvertedMode(BOOL bInvertedMode = TRUE);
BOOL GetInvertedMode(void);

If you set InvertedMode, Left and Right of the Control will be exchanged. 
So the Left button then controls the value of "right" and vice versa. 

The RANGE_CHANGED Message

The lParam is not used. In wParam you get one of the enum values:

enum _RangeMessages {
	RS_LEFTCHANGED,
	RS_RIGHTCHANGED,
	RS_BOTHCHANGED,
};
Indicating which position has been changed. If you call SetMinMax in the message handler, a new RANGE_CHANGED messages might be sent to the parent, so beware of an endless loop and a stack overflow. This message will not be sent, if you call SetRange. Typically you should update your display and set a new "visual" range.

TO DO

  • Make all colors configuration options.
  • At the moment the whole window is filled by the control. It should restrict itself to a reasonable depth.

License

You can choose whether you want to use the BSD License (without advertising clause) or GPL V2 or above (see CRangeSlider.cpp).

History

Date

Change

2002-04-05 Feedback and visual range mode are now enabled as default in demo.
2002-03-18 Drag at point of first LButtonDown. (Thanks to AnthonyJ). Changed algorithm for keyboard interaction (now reaches Min or Max).
2002-03-11 Bug in Keyboard handling removed. 3D Buttons are now depressed. There is a feedback loop demonstrating the VisualRange.
2002-03-08 Added Vertical Mode. Arrow width is calculated. You can invert left and right. Arrows are now 3D.
2002-03-07 Support for "custom control" in resource editor. Keyboard interaction.
2002-03-06 Removed (?) resource allocation problem in OnPaint.
2002-02-28 Initial release to codeproject

Acknowledgement

This code uses the CMemDC class from Keith Rule for flicker free drawing (it is in CMemDC.h).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here