Download demo project - 40 Kb
Download source files - 6 Kb
<!-- Article Starts -->
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
- 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:
- 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 ;
- Initialize the meter properties.
This is best accomodated in meter-owner's constructor.
m_meterLeft.SetRange (-5.0, 5.0) ;
m_meterLeft.SetTitle("Channel A") ;
m_meterRight.SetRange (-10.0, 10.0) ;
m_meterRight.SetTitle("Channel B") ;
- Determine the meter's location (a square rectangle) and
This is best accomodated in meter-owner's OnDraw function.
void CAnalogMeterTestView::OnDraw(CDC* pDC)
m_meterLeft.ShowMeter (pDC, m_rectLeftMeter) ;
m_meterRight.ShowMeter (pDC, m_rectRightMeter) ;
- 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, dRightValue ;
CClientDC dcClient(this) ;
m_meterLeft.UpdateNeedle (&dcClient, dLeftValue) ;
m_meterRight.UpdateNeedle (&dcClient, dRightValue) ;
- 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"
"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.