Click here to Skip to main content
15,867,756 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 202.7K   5.2K   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

 
QuestionPerfect! Pin
.dan.g.20-Sep-18 21:35
professional.dan.g.20-Sep-18 21:35 
I'm going to use it to specify a date range in ToDoCtrl's[^] Gantt Chart plugin.

ps. I'm going to heavily customise the drawing so that I can derive from it and add theming support and a bunch of other stuff like labels.
pps. I'm happy to add your name to the list of contributors unless you instruct me otherwise

Many thanks!
.dan.g.

AbstractSpoon Software
email: abstractspoon(dot)todolist(at)gmail(dot)com

QuestionIf there are two, how to receive the message Pin
Jeff cat25-Dec-14 20:00
Jeff cat25-Dec-14 20:00 
GeneralUsing your code in a professional program Pin
Jumbo14-Sep-10 23:25
Jumbo14-Sep-10 23:25 
GeneralRe: Using your code in a professional program Pin
Jens Scheidtmann26-Sep-10 8:41
Jens Scheidtmann26-Sep-10 8:41 
Generalit helps me a lot and just a minor imperfection Pin
chen.zd29-Jul-10 0:27
chen.zd29-Jul-10 0:27 
GeneralRe: it helps me a lot and just a minor imperfection Pin
Jens Scheidtmann26-Sep-10 8:44
Jens Scheidtmann26-Sep-10 8:44 
QuestionEnhancements Pin
Martin Cooke9-Mar-09 23:48
Martin Cooke9-Mar-09 23:48 
GeneralI found two bugs, :) Pin
Kindy Chen3-Jul-06 15:42
Kindy Chen3-Jul-06 15:42 
GeneralRe: I found two bugs, :) Pin
bbinn20-Dec-06 22:00
bbinn20-Dec-06 22:00 
GeneralError on RegisterWindowClass Pin
oriol.esteve25-Oct-05 4:48
oriol.esteve25-Oct-05 4:48 
GeneralSlider control(direction) Pin
Member 195600517-Jun-05 8:57
Member 195600517-Jun-05 8:57 
GeneralSlider control(direction) Pin
Member 195600517-Jun-05 8:54
Member 195600517-Jun-05 8:54 
GeneralThree suggestions for you Pin
caocao2-Apr-03 17:44
caocao2-Apr-03 17:44 
GeneralMessageBox doesn't show Yes/No Buttons on specifying the style as MB_YESNO Pin
JyotiChugh25-Nov-02 0:29
sussJyotiChugh25-Nov-02 0:29 
GeneralRe: MessageBox doesn't show Yes/No Buttons on specifying the style as MB_YESNO Pin
Jens Scheidtmann25-Nov-02 2:15
Jens Scheidtmann25-Nov-02 2:15 
Generalvertical mode Pin
Sonar3-Apr-02 6:15
Sonar3-Apr-02 6:15 
GeneralRe: vertical mode Pin
Jens Scheidtmann3-Apr-02 9:56
Jens Scheidtmann3-Apr-02 9:56 
GeneralRe: vertical mode Pin
Sonar3-Apr-02 10:00
Sonar3-Apr-02 10:00 
GeneralRe: vertical mode Pin
Jens Scheidtmann4-Apr-02 22:02
Jens Scheidtmann4-Apr-02 22:02 
GeneralGrab anywhere without recentre Pin
AnthonyJ18-Mar-02 1:56
AnthonyJ18-Mar-02 1:56 
GeneralRe: Grab anywhere without recentre Pin
Jens Scheidtmann19-Mar-02 8:52
Jens Scheidtmann19-Mar-02 8:52 
GeneralSuggestion... Pin
Jason Troitsky (was Hattingh)1-Mar-02 0:26
Jason Troitsky (was Hattingh)1-Mar-02 0:26 
GeneralRe: Suggestion... Pin
Jens Scheidtmann6-Mar-02 20:32
Jens Scheidtmann6-Mar-02 20:32 
GeneralRe: Suggestion... ;) Pin
Jason Troitsky (was Hattingh)6-Mar-02 21:12
Jason Troitsky (was Hattingh)6-Mar-02 21:12 
GeneralRe: Suggestion... ;) Pin
Jens Scheidtmann7-Mar-02 5:10
Jens Scheidtmann7-Mar-02 5:10 

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.