www.pudn.com > QuXian.rar > OScopeCtrl.cpp


// OScopeCtrl.cpp : implementation file// 
 
#include "stdafx.h" 
#include "math.h" 
 
#include "OScopeCtrl.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__ ; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// COScopeCtrl 
COScopeCtrl::COScopeCtrl() 
{ 
  // since plotting is based on a LineTo for each new point 
  // we need a starting point (i.e. a "previous" point) 
  // use 0.0 as the default first point. 
  // these are public member variables, and can be changed outside 
  // (after construction).  Therefore m_perviousPosition could be set to 
  // a more appropriate value prior to the first call to SetPosition. 
  m_dPreviousPosition =   0.0 ; 
 
  // public variable for the number of decimal places on the y axis 
  m_nYDecimals = 3 ; 
 
  // set some initial values for the scaling until "SetRange" is called. 
  // these are protected varaibles and must be set with SetRange 
  // in order to ensure that m_dRange is updated accordingly 
  m_dLowerLimit = -10.0 ; 
  m_dUpperLimit =  10.0 ; 
  m_dRange      =  m_dUpperLimit - m_dLowerLimit ;   // protected member variable 
 
  // m_nShiftPixels determines how much the plot shifts (in terms of pixels)  
  // with the addition of a new data point 
  m_nShiftPixels     = 4 ; 
  m_nHalfShiftPixels = m_nShiftPixels/2 ;                     // protected 
  m_nPlotShiftPixels = m_nShiftPixels + m_nHalfShiftPixels ;  // protected 
 
  // background, grid and data colors 
  // these are public variables and can be set directly 
  m_crBackColor  = RGB(  0,   0,   0) ;  // see also SetBackgroundColor 
  m_crGridColor  = RGB(  0, 255, 255) ;  // see also SetGridColor 
  m_crPlotColor  = RGB(255, 255, 255) ;  // see also SetPlotColor 
 
  // protected variables 
  m_penPlot.CreatePen(PS_SOLID, 0, m_crPlotColor) ; 
  m_brushBack.CreateSolidBrush(m_crBackColor) ; 
 
  // public member variables, can be set directly  
  m_strXUnitsString.Format("Samples") ;  // can also be set with SetXUnits 
  m_strYUnitsString.Format("Y units") ;  // can also be set with SetYUnits 
 
  // protected bitmaps to restore the memory DC's 
  m_pbitmapOldGrid = NULL ; 
  m_pbitmapOldPlot = NULL ; 
 
}  // COScopeCtrl 
 
///////////////////////////////////////////////////////////////////////////// 
COScopeCtrl::~COScopeCtrl() 
{ 
  // just to be picky restore the bitmaps for the two memory dc's 
  // (these dc's are being destroyed so there shouldn't be any leaks) 
  if (m_pbitmapOldGrid != NULL) 
    m_dcGrid.SelectObject(m_pbitmapOldGrid) ;   
  if (m_pbitmapOldPlot != NULL) 
    m_dcPlot.SelectObject(m_pbitmapOldPlot) ;   
 
} // ~COScopeCtrl 
 
 
BEGIN_MESSAGE_MAP(COScopeCtrl, CWnd) 
  //{{AFX_MSG_MAP(COScopeCtrl) 
  ON_WM_PAINT() 
  ON_WM_SIZE() 
  //}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// COScopeCtrl message handlers 
 
///////////////////////////////////////////////////////////////////////////// 
BOOL COScopeCtrl::Create(DWORD dwStyle, const RECT& rect,  
                         CWnd* pParentWnd, UINT nID)  
{ 
  BOOL result ; 
  static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW) ; 
 
  result = CWnd::CreateEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE,  
                          className, NULL, dwStyle,  
                          rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 
                          pParentWnd->GetSafeHwnd(), (HMENU)nID) ; 
  if (result != 0) 
    InvalidateCtrl() ; 
 
  return result ; 
 
} // Create 
 
///////////////////////////////////////////////////////////////////////////// 
void COScopeCtrl::SetRange(double dLower, double dUpper, int nDecimalPlaces) 
{ 
  ASSERT(dUpper > dLower) ; 
 
  m_dLowerLimit     = dLower ; 
  m_dUpperLimit     = dUpper ; 
  m_nYDecimals      = nDecimalPlaces ; 
  m_dRange          = m_dUpperLimit - m_dLowerLimit ; 
  m_dVerticalFactor = (double)m_nPlotHeight / m_dRange ;  
   
  // clear out the existing garbage, re-start with a clean plot 
  InvalidateCtrl() ; 
 
}  // SetRange 
 
 
///////////////////////////////////////////////////////////////////////////// 
void COScopeCtrl::SetXUnits(CString string) 
{ 
  m_strXUnitsString = string ; 
 
  // clear out the existing garbage, re-start with a clean plot 
  InvalidateCtrl() ; 
 
}  // SetXUnits 
 
///////////////////////////////////////////////////////////////////////////// 
void COScopeCtrl::SetYUnits(CString string) 
{ 
  m_strYUnitsString = string ; 
 
  // clear out the existing garbage, re-start with a clean plot 
  InvalidateCtrl() ; 
 
}  // SetYUnits 
 
///////////////////////////////////////////////////////////////////////////// 
void COScopeCtrl::SetGridColor(COLORREF color) 
{ 
  m_crGridColor = color ; 
 
  // clear out the existing garbage, re-start with a clean plot 
  InvalidateCtrl() ; 
 
}  // SetGridColor 
 
 
///////////////////////////////////////////////////////////////////////////// 
void COScopeCtrl::SetPlotColor(COLORREF color) 
{ 
  m_crPlotColor = color ; 
 
  m_penPlot.DeleteObject() ; 
  m_penPlot.CreatePen(PS_SOLID, 0, m_crPlotColor) ; 
 
  // clear out the existing garbage, re-start with a clean plot 
  InvalidateCtrl() ; 
 
}  // SetPlotColor 
 
 
///////////////////////////////////////////////////////////////////////////// 
void COScopeCtrl::SetBackgroundColor(COLORREF color) 
{ 
  m_crBackColor = color ; 
 
  m_brushBack.DeleteObject() ; 
  m_brushBack.CreateSolidBrush(m_crBackColor) ; 
 
  // clear out the existing garbage, re-start with a clean plot 
  InvalidateCtrl() ; 
 
}  // SetBackgroundColor 
 
///////////////////////////////////////////////////////////////////////////// 
void COScopeCtrl::InvalidateCtrl() 
{ 
  // There is a lot of drawing going on here - particularly in terms of  
  // drawing the grid.  Don't panic, this is all being drawn (only once) 
  // to a bitmap.  The result is then BitBlt'd to the control whenever needed. 
  int i ; 
  int nCharacters ; 
  int nTopGridPix, nMidGridPix, nBottomGridPix ; 
 
  CPen *oldPen ; 
  CPen solidPen(PS_SOLID, 0, m_crGridColor) ; 
  CFont axisFont, yUnitFont, *oldFont ; 
  CString strTemp ; 
 
  // in case we haven't established the memory dc's 
  CClientDC dc(this) ;   
 
  // if we don't have one yet, set up a memory dc for the grid 
  if (m_dcGrid.GetSafeHdc() == NULL) 
  { 
    m_dcGrid.CreateCompatibleDC(&dc) ; 
    m_bitmapGrid.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight) ; 
    m_pbitmapOldGrid = m_dcGrid.SelectObject(&m_bitmapGrid) ; 
  } 
   
  m_dcGrid.SetBkColor (m_crBackColor) ; 
 
  // fill the grid background 
  m_dcGrid.FillRect(m_rectClient, &m_brushBack) ; 
 
  // draw the plot rectangle: 
  // determine how wide the y axis scaling values are 
  nCharacters = abs((int)log10(fabs(m_dUpperLimit))) ; 
  nCharacters = max(nCharacters, abs((int)log10(fabs(m_dLowerLimit)))) ; 
 
  // add the units digit, decimal point and a minus sign, and an extra space 
  // as well as the number of decimal places to display 
  nCharacters = nCharacters + 4 + m_nYDecimals ;   
 
  // adjust the plot rectangle dimensions 
  // assume 6 pixels per character (this may need to be adjusted) 
  m_rectPlot.left = m_rectClient.left + 6*(nCharacters) ; 
  m_nPlotWidth    = m_rectPlot.Width() ; 
 
  // draw the plot rectangle 
  oldPen = m_dcGrid.SelectObject (&solidPen) ;  
  m_dcGrid.MoveTo (m_rectPlot.left, m_rectPlot.top) ; 
  m_dcGrid.LineTo (m_rectPlot.right+1, m_rectPlot.top) ; 
  m_dcGrid.LineTo (m_rectPlot.right+1, m_rectPlot.bottom+1) ; 
  m_dcGrid.LineTo (m_rectPlot.left, m_rectPlot.bottom+1) ; 
  m_dcGrid.LineTo (m_rectPlot.left, m_rectPlot.top) ; 
  m_dcGrid.SelectObject (oldPen) ;  
 
  // draw the dotted lines,  
  // use SetPixel instead of a dotted pen - this allows for a  
  // finer dotted line and a more "technical" look 
  nMidGridPix    = (m_rectPlot.top + m_rectPlot.bottom)/2 ; 
  nTopGridPix    = nMidGridPix - m_nPlotHeight/4 ; 
  nBottomGridPix = nMidGridPix + m_nPlotHeight/4 ; 
 
  for (i=m_rectPlot.left; i= m_rectPlot.bottom) || (currY >= m_rectPlot.bottom)) 
      m_dcPlot.FillRect(CRect(prevX, m_rectPlot.bottom+1, currX+1, m_rectClient.bottom+1), &m_brushBack) ; 
 
    // store the current point for connection to the next point 
    m_dPreviousPosition = m_dCurrentPosition ; 
 
  } 
 
} // end DrawPoint 
 
///////////////////////////////////////////////////////////////////////////// 
void COScopeCtrl::OnSize(UINT nType, int cx, int cy)  
{ 
  CWnd::OnSize(nType, cx, cy) ; 
 
  // NOTE: OnSize automatically gets called during the setup of the control 
   
  GetClientRect(m_rectClient) ; 
 
  // set some member variables to avoid multiple function calls 
  m_nClientHeight = m_rectClient.Height() ; 
  m_nClientWidth  = m_rectClient.Width() ; 
 
  // the "left" coordinate and "width" will be modified in  
  // InvalidateCtrl to be based on the width of the y axis scaling 
  m_rectPlot.left   = 20 ;   
  m_rectPlot.top    = 10 ; 
  m_rectPlot.right  = m_rectClient.right-10 ; 
  m_rectPlot.bottom = m_rectClient.bottom-25 ; 
 
  // set some member variables to avoid multiple function calls 
  m_nPlotHeight = m_rectPlot.Height() ; 
  m_nPlotWidth  = m_rectPlot.Width() ; 
 
  // set the scaling factor for now, this can be adjusted  
  // in the SetRange functions 
  m_dVerticalFactor = (double)m_nPlotHeight / m_dRange ;  
 
} // OnSize 
 
 
///////////////////////////////////////////////////////////////////////////// 
void COScopeCtrl::Reset() 
{ 
  // to clear the existing data (in the form of a bitmap) 
  // simply invalidate the entire control 
  InvalidateCtrl() ; 
}