Click here to Skip to main content
Click here to Skip to main content

CHistogramCtrl, a windows 2000 like histogram control

, 12 Apr 2001 CPOL
Rate this:
Please Sign up or sign in to vote.
A histogram control that is used to plot specified values within the defined range (limits)
<!-- Download Links --> <!-- Add the rest of your HTML here -->

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:

// Declaring a local variable
CRect rect;
// Get the rectangular coordinates of the rectangle 
// we already placed on dialog
GetDlgItem(IDC_STATIC_HISTOGRAM)->GetWindowRect(rect);
// Convert to the client coordinates
ScreenToClient(rect);
// Create and place the histogram control on screen
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:

//Change the color of grids to red
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:

  1. LOW_SPEED (3000 ms)
  2. NORMAL_SPEED (1000 ms; default value)
  3. HIGH_SPEED (500 ms)
  4. IDLE (0 ms)

To use this function, all you've to do is as follows:

// Change the speed of scrolling
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:

//Set the current position of the histogram to 26
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 to "mehdi_mousavi@hotmail.com", the author of many popular articles on the net; and the latest one, MODEMMANIA. - Aloha!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mehdi Mousavi
Architect
United States United States
Mehdi Mousavi is a professional computer programmer. He has written many programs using C, C++, MFC, Win32, COM, DCOM, JavaScript, ASP, HTML, DHTML, SQL, C# and MC++.

Comments and Discussions

 
GeneralThanks a lot Pinmemberchao88282768-Nov-12 14:48 
GeneralQuestion Pinmembermycareer3-Mar-11 19:30 
GeneralMy vote of 5 Pinmemberhpghy2-Dec-10 21:12 
GeneralMy vote of 5 Pinmemberliushiyao25-Jul-10 23:21 
Generalgood Pinmembermayasu8-Jan-10 1:26 
QuestionMaking Invisible Pinmemberfranzcatch29-Jul-06 16:32 
Questioncannot find Pinmemberfranzcatch29-Jul-06 5:43 
AnswerRe: cannot find Pinmemberfranzcatch29-Jul-06 16:27 
GeneralClearing the control PinmemberNeta77722-Feb-04 0:51 
GeneralRe: Clearing the control Pinmemberjinglebell1-Jan-06 4:43 
GeneralRe: Clearing the control Pinmemberflagmaxiden16-Feb-11 17:09 
GeneralOnSize problem Pinmemberchito28-Sep-03 14:33 
GeneralRe: OnSize problem Pinmemberjinglebell1-Jan-06 4:56 
GeneralGDI Resource Leaks on Win9x Pinmember=[ Abin ]=23-Sep-03 17:01 
GeneralRe: GDI Resource Leaks on Win9x PinsitebuilderMichael Dunn23-Sep-03 18:23 
GeneralRe: GDI Resource Leaks on Win9x Pinmember=[ Abin ]=24-Sep-03 0:29 
GeneralRe: GDI Resource Leaks on Win9x PinmemberGlyn16-Feb-04 4:59 
Generaltimer Pinmembermaniuch29-May-03 3:31 
It should have parameter for timer ID and appropriate checking in OnTimer (otherwise it doesn't work correclty if you have another timer). Besides, quite nice Smile | :)
 
mk
GeneralRe: timer Pinmemberbli@copepod.de12-Mar-07 6:00 
Generalto .Net platform Pinmemberpocalypse18-Jan-03 20:08 
Generaldear mmehdi Pinmembermohammadsh5-Oct-02 18:06 
GeneralRe: dear mmehdi PinmemberPeter Moonen23-Nov-02 4:08 
GeneralRe: dear peter Pinmembermohammadsh6-Dec-02 6:57 
GeneralThis is what I had been looking for! PinsussAnonymous29-Sep-02 16:10 
Generalhistogram.h PinmemberTaylorLee15-Jul-02 8:47 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.141029.1 | Last Updated 13 Apr 2001
Article Copyright 2001 by Mehdi Mousavi
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid