Analog Meter Class

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

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
  • 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,
  • SetRangeDecimals
  • SetValueDecimals
  • 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.


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

More by Author

Must Read