Analog Meter Class


Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame

Recently, I've been involved in a instrumentation project wherein one single display (a CView) is used to present measurement results as well as the status of some transducers. The desire was to have everything in one "window" that could be maximized and all of the relevant information could be seen without having to deal with overlapping windows or dialog boxes.

As a means of graphically displaying the transducer status, an "analog meter" class was developed which could be used in any square rectangle within any display context. Thus, a sqaure area (CRect) could be determined within an application's CView derived class and the meter could be displayed and updated as needed within this CRect.

The drawing a meter is somewhat trivial, however the smooth (and fast) animation of such a meter is a different matter. To this end I referred back to the "triple buffering" method I used in my Oscilloscope/Strip Chart control. In this approach, I create three bitmaps: one for the underlying "grid" (the pie shaped wedge, the title and numerical limit values), one for the "needle" and one which is used to temporarily store the "result" of the combination of the needle and grid prior to BitBlt'ing to the destination display context.

To improve the speed of animation, these bitmaps are only updated on an "as needed" basis. For example, the grid bitmap is only redrawn when the meter's rectangle has changed and the needle bitmap is only redrawn when the needle's position has changed. Furthermore, the combination of bitmaps is performed in a memory based result prior to display in order to provide faster performance.

The Analog Meter can be used based on the following:

  • Add a meter to your class
  • Initialize the properties of the meter for your particular needs.
  • Determine a square rectangle in the the desired display context.
  • Show the meter.
  • Update the meter as needed.

These steps are outlined in detail as folllows:

1. In the meter's owner (for example your CView-derived class) add your meter(s).

It may also be useful to establish CRect member variables to keep track of the location of your meters.

class CAnalogMeterTestView : public CView
    CRect m_rectLeftMeter ;
    CRect m_rectRightMeter ;
    CAnalogMeter m_meterLeft ;
    CAnalogMeter m_meterRight ;
} // end CAnalogMeterTestView

2. Initialize the meter properties.

This is best accomodated in meter-owner's constructor.

  // setup the Left meter properties
  m_meterLeft.SetRange (-5.0, 5.0) ;
  m_meterLeft.SetRangeDecimals(1) ;
  m_meterLeft.SetValueDecimals(3) ;
  m_meterLeft.SetTitle("Channel A") ;

  // setup the Right meter properties
  m_meterRight.SetRange (-10.0, 10.0) ;
  m_meterRight.SetRangeDecimals(1) ;
  m_meterRight.SetValueDecimals(3) ;
  m_meterRight.SetTitle("Channel B") ;

} // end CAnalogMeterTestView constructor

3. Determine the meter's location (a square rectangle) and display it.

This is best accomodated in meter-owner's OnDraw function.

void CAnalogMeterTestView::OnDraw(CDC* pDC)
  // determine the meter rectangle(s) - make sure they are square
  // fill in the member variable CRect's accordingly

  // show the meters in their respective rectangles
  m_meterLeft.ShowMeter (pDC, m_rectLeftMeter) ;
  m_meterRight.ShowMeter (pDC, m_rectRightMeter) ;
} // end OnDraw

4. Update the needle position as needed.

The approach I use is to periodically update the needle position based on a timer.

void CAnalogMeterTestView::OnTimer(UINT nIDEvent) 
  double dLeftValue,          // the new meter values to be shown
         dRightValue ;
  CClientDC dcClient(this) ;  // get a client dc for the updated meter
  // determine the new values // update the meters
  m_meterLeft.UpdateNeedle (&dcClient, dLeftValue) ;
  m_meterRight.UpdateNeedle (&dcClient, dRightValue) ; 

  // call the base class, as the Class Wizard says I should
} // end OnTimer 

Other Considerations


The meter range, the title and the number of decimal places on the numerical values can be easily modified as shown above in Step 2. However, it should be noted that you must call ShowMeter after making these changes in order to "see" the effects. These attributes can be changed (via "Set" functions) or retrieved (via "Get" functions). The public attribute modification/access functions are:

  • SetRange (GetMaxRange, GetMinRange)
  • SetRangeDecimals (GetRangeDecimals)
  • SetValueDecimals (GetValueDecimals)
  • SetTitle (GetTitle)
  • REMINDER: you must call ShowMeter in order to see the effects after a "Set" function call.

"Inside the Meter" Customizations

The CAnalogMeter constructor contains some areas which may provide some interesting customizations, particularly in terms of the colors. Try modifying the member variables: m_colorGrid, m_colorNeedle and m_colorValue.

Also, the width of the meter's "pie slice" is based on an angle specified CAnalogMeter::DrawGrid() function. This angle is set through the variable dLimitAngleDeg.


READ THIS BEFORE YOU SEND ME NASTY EMAIL... (You don't have to read this before sending nice email)

This meter was intended for use in a CView derived class and has been tested with my printer and clipboard functions. I have not experimented with using it in other areas (such as a control in a dialog). I'm sure these capabilities could be added or perhaps this approach could be applied in these other areas, but I don't have the time to do it at this point.

Download demo project - 40 KB

Download source - 5 KB


  • There are no comments yet. Be the first to comment!

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date