Initial Idea
The initial idea for doing this code was put into my mind when my love asked me to go to a clinic in order to check out my heart. You know, doctors have got some sort of plotters that plot the information obtained from the heart on a piece of paper as a histogram. The idea came into my mind from there! This control is sincerely dedicated to my love, Cindy.
How to Use
To use the control, you import the header file as well as the .cpp file attached to this article. Then you simply open the dialog editor and place a rectangle on your dialog. We call this static control IDC_STATIC_HISTOGRAM
. Thereafter, you instantiate an object of the CHistogramCtrl
class, say m_ctrlHistogram
, as a data member of your dialog
class.
In the message handler of the WM_INITDIALOG
message, you get the area of the static rectangle you already placed on your dialog
box and you simply create the Histogram Control as follows:
CRect rect;
GetDlgItem(IDC_STATIC_HISTOGRAM)->GetWindowRect(rect);
ScreenToClient(rect);
m_ctrlHistogram.Create(WS_VISIBLE | WS_CHILD
| WS_TABSTOP, rect, this, IDC_STATIC_HISTOGRAM);
After doing this, the histogram's window is shown on screen in the default colors assigned to the control within the constructor of the class. For example, the background color of the control is held in the m_crBackGround
member variable of the class and is assigned to the color black in the constructor of the CHistogramCtrl
. The other member variable, m_crGrids
holds the grid color and is assigned to RGB(0, 130, 66)
in the constructor of the class.
What if we would like to change the grid color to red? Shall we alter the mentioned variables within the constructor? Of course, not! To do so, I've created a method, SetGridsColor
, prototyped as follows:
BOOL CHistogramCtrl::SetGridsColor(COLORREF cr);
Where cr
is the grids' color reference. For example, you can change the color of grids to red this way:
m_ctrlHistogram.SetGridsColor(RGB(255, 0, 0));
Here are the other methods of the class that can be used to change the default behavior of the control:
BOOL CHistogramCtrl::SetBkColor(COLORREFcr);
void CHistogramCtrl::SetPen(int nWidth, COLORREF crColor);
void CHistogramCtrl::SetRange(UINT uLower, UINT uUpper);
CHistogramCtrl::SPEED SetSpeed(CHistogramCtrl::SPEED uSpeed);
void CHistogramCtrl::SetPos(UINT uPos);</td>
Although the method names clarifies their purposes, it makes sense if we have a quick look at what each one is useful for.
The first above-mentioned method, SetBkColor
, is used to set the background color of the control. The default value is black, i.e., RGB(0, 0, 0)
, declared in the constructor of the class.
The second method is used to set the control's pen, the one that's used to draw the histogram. The first parameter, nWidth
, is used to set the width of the line. The second parameter, crColor
, is a COLORREF
that sets the color of the pen. If you don't use this function, the default values are used, 1
as the pen width, and RGB(0, 255, 0)
as the pen's color.
The third method, SetRange
, is used to set the upper and lower limits (range) of the control. The valid range for these arguments is as follows:
uLower > 0
uUpper > 0
uLower < uUpper
Please note that the range will be set to 1-100 if you don't specify a range - i.e., you can plot numbers between 1 to 100.
Now let's move from SetRange
to the next method, SetSpeed
. This is used to control the refresh speed of CHistogramCtrl
. Let me say that the window contents are shifted 3 pixels to the left within the specified intervals. There are 4 predefined intervals declared as an enum
as follows:
LOW_SPEED
(3000 ms) NORMAL_SPEED
(1000 ms; default value) HIGH_SPEED
(500 ms) IDLE
(0 ms)
To use this function, all you've to do is as follows:
m_ctrlHistogram.SetSpeed(CHistogramCtrl::HIGH_SPEED);</td>
This way, the contents of the control is shifted 3 pixels to the left at 500ms intervals.
Now it is time to turn our attention to the last public
method of the class, SetPos
, declared as follows:
void CHistogramCtrl::SetPos(UINT uPos);
This member function does the actual plotting. For example, to set the current position of the histogram to 26
, you can easily write the following statement:
m_ctrlHistogram.SetPos(26);
Now imagine what happens if you set the position of the histogram to 87 ten seconds later. You'll see a histogram as follows:
In other words, there will be no change in the line if we don't feed the control with new values. But what happens if we feed the control more than it can show? For example, imagine that we've set the speed of the control to HIGH_SPEED
(500ms) and we feed the control 20 times within the 500ms. Which value is shown at the end of the first 500ms?
To solve this problem, I created a CList
as a private
data member of CHistogramCtrl
. Whenever you call SetPos
, I append the value you provide to the mentioned list. Whenever I want to refresh the control (at the end of each 500ms in our example), I process the list and obtain the average value of the current values within the list. To clarify what I'm talking about, imagine that we set the current position of the control to the following values within the first 500ms:
10, 87, 19, 54, 63, 74
When this time elapses, I process the current values within the list and calculate the average of the list members:
10 + 87 + 19 + 54 +63 + 74 = 307
307 / 6 = 51.1
And I show 51.1
as the current value... Got it?
This is done via one of the private
methods of the class called, GetAverage
, that returns the average of numbers within the mentioned list. In some cases, you have to change the mechanism of calculating the current position of the control within the refresh intervals with your desired one. For example, I've used the variance of the numbers instead of their average in my latest project. Please note that the function is called within the DrawLine
method to obtain a value to show at the end of each period.
Since the source code is straight forward and easy to understand this article is finished now. Please feel free to send your comments, questions and/or suggestions about this control by leaving a comment below. Aloha!
History
- 13th April, 2001: Initial version