Click here to Skip to main content
15,886,137 members
Articles / Desktop Programming / MFC
Article

CRangeSlider - a Ctrl for Selecting a Range or Interval

Rate me:
Please Sign up or sign in to vote.
5.00/5 (16 votes)
8 Apr 2002CC (ASA 3U)4 min read 203.6K   5.3K   72   46
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-05Feedback and visual range mode are now enabled as default in demo.
2002-03-18Drag at point of first LButtonDown. (Thanks to AnthonyJ). Changed algorithm for keyboard interaction (now reaches Min or Max).
2002-03-11Bug in Keyboard handling removed. 3D Buttons are now depressed. There is a feedback loop demonstrating the VisualRange.
2002-03-08Added Vertical Mode. Arrow width is calculated. You can invert left and right. Arrows are now 3D.
2002-03-07Support for "custom control" in resource editor. Keyboard interaction.
2002-03-06Removed (?) resource allocation problem in OnPaint.
2002-02-28Initial 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, along with any associated source code and files, is licensed under The Creative Commons Attribution-Share Alike 3.0 Unported License


Written By
Architect
Germany Germany
Jens Scheidtmann
is a Developer in Germany.

Comments and Discussions

 
GeneralRe: Suggestion... ;) Pin
Jason Troitsky (was Hattingh)7-Mar-02 5:36
Jason Troitsky (was Hattingh)7-Mar-02 5:36 
GeneralRe: Suggestion... ;) Pin
Jens Scheidtmann7-Mar-02 20:31
Jens Scheidtmann7-Mar-02 20:31 
GeneralRe: Suggestion... ;) Pin
Jason Troitsky (was Hattingh)7-Mar-02 21:08
Jason Troitsky (was Hattingh)7-Mar-02 21:08 
QuestionLicense? Pin
28-Feb-02 9:03
suss28-Feb-02 9:03 
AnswerRe: License? Pin
Nish Nishant28-Feb-02 16:23
sitebuilderNish Nishant28-Feb-02 16:23 
GeneralRe: License? Pin
Tim Smith1-Mar-02 6:43
Tim Smith1-Mar-02 6:43 
AnswerRe: License? Pin
Jens Scheidtmann28-Feb-02 21:58
Jens Scheidtmann28-Feb-02 21:58 
GeneralRe: License? Pin
1-Mar-02 6:35
suss1-Mar-02 6:35 
GeneralRe: License? Pin
Chris Losinger1-Mar-02 7:00
professionalChris Losinger1-Mar-02 7:00 
GeneralRe: License? Pin
13-Mar-02 3:00
suss13-Mar-02 3:00 
GeneralRe: License? Pin
Chris Losinger13-Mar-02 3:23
professionalChris Losinger13-Mar-02 3:23 
Generalresource leak Pin
PJ Arends28-Feb-02 8:17
professionalPJ Arends28-Feb-02 8:17 
GeneralRe: resource leak Pin
Mustafa Demirhan28-Feb-02 9:54
Mustafa Demirhan28-Feb-02 9:54 
GeneralRe: resource leak Pin
PJ Arends28-Feb-02 12:07
professionalPJ Arends28-Feb-02 12:07 
GeneralRe: resource leak Pin
Jens Scheidtmann28-Feb-02 22:16
Jens Scheidtmann28-Feb-02 22:16 
GeneralLooks nice Pin
Thomas Freudenberg28-Feb-02 8:19
Thomas Freudenberg28-Feb-02 8:19 
GeneralRe: Looks nice Pin
Jens Scheidtmann28-Feb-02 22:11
Jens Scheidtmann28-Feb-02 22:11 
GeneralRe: Looks nice Pin
Thomas Freudenberg6-Mar-02 12:14
Thomas Freudenberg6-Mar-02 12:14 
GeneralGreat! Pin
Davide Calabro28-Feb-02 5:46
Davide Calabro28-Feb-02 5:46 
GeneralRe: Great! Pin
Jason Troitsky (was Hattingh)1-Mar-02 0:23
Jason Troitsky (was Hattingh)1-Mar-02 0:23 
GeneralRe: Great! Pin
User 66581-Mar-02 2:34
User 66581-Mar-02 2:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.