Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Analog Meter Class

0.00/5 (No votes)
18 Jan 2000 1  
A control that displays a numerical value as an analog meter
  • Download demo project - 40 Kb
  • Download source files - 6 Kb
  • Sample Image - analog_meter.gif

    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).
    2. It may also be useful to establish CRect member variables to keep track of the location of your meters.

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

    3. Initialize the meter properties.
    4. This is best accomodated in meter-owner's constructor.

      CAnalogMeterTestView::CAnalogMeterTestView()
      {
        // 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
      
      

    5. Determine the meter's location (a square rectangle) and display it.
    6. 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
      
      

    7. Update the needle position as needed.
    8. 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
      
        CView::OnTimer(nIDEvent);
      } // end OnTimer 
      
      

    9. Other Considerations
    10. Customization

      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.

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here