CRangeSlider - a Ctrl for Selecting a Range or Interval





5.00/5 (16 votes)
Have you ever searched for a nice way to select a subrange from an interval? This may be the solution for you.
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 variableCRangeSlider 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 toDoDataExchange
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 messageRANGE_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 MaxSet 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 theCMemDC
class from Keith
Rule for flicker free drawing (it is in CMemDC.h).