📄 oscopectrl.cpp
字号:
m_dcGrid.SetPixel (i, nMidGridPix, m_crGridColor) ;
m_dcGrid.SetPixel (i, nBottomGridPix, m_crGridColor) ;
}
// create some fonts (horizontal and vertical)
// use a height of 14 pixels and 300 weight
// (these may need to be adjusted depending on the display)
axisFont.CreateFont (14, 0, 0, 0, 300,
FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH|FF_SWISS, "Arial") ;
yUnitFont.CreateFont (14, 0, 900, 0, 300,
FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH|FF_SWISS, "Arial") ;
// grab the horizontal font
oldFont = m_dcGrid.SelectObject(&axisFont) ;
// y max
m_dcGrid.SetTextColor (m_crGridColor) ;
m_dcGrid.SetTextAlign (TA_RIGHT|TA_TOP) ;
strTemp.Format ("%.*lf", m_nYDecimals, m_dUpperLimit) ;
m_dcGrid.TextOut (m_rectPlot.left-4, m_rectPlot.top, strTemp) ;
// y min
m_dcGrid.SetTextAlign (TA_RIGHT|TA_BASELINE) ;
strTemp.Format ("%.*lf", m_nYDecimals, m_dLowerLimit) ;
m_dcGrid.TextOut (m_rectPlot.left-4, m_rectPlot.bottom, strTemp) ;
// x min
m_dcGrid.SetTextAlign (TA_LEFT|TA_TOP) ;
m_dcGrid.TextOut (m_rectPlot.left, m_rectPlot.bottom+4, "0") ;
// x max
m_dcGrid.SetTextAlign (TA_RIGHT|TA_TOP) ;
strTemp.Format ("%d", m_nPlotWidth/m_nShiftPixels) ;
m_dcGrid.TextOut (m_rectPlot.right, m_rectPlot.bottom+4, strTemp) ;
// x units
m_dcGrid.SetTextAlign (TA_CENTER|TA_TOP) ;
m_dcGrid.TextOut ((m_rectPlot.left+m_rectPlot.right)/2,
m_rectPlot.bottom+4, m_strXUnitsString) ;
// restore the font
m_dcGrid.SelectObject(oldFont) ;
// y units
oldFont = m_dcGrid.SelectObject(&yUnitFont) ;
m_dcGrid.SetTextAlign (TA_CENTER|TA_BASELINE) ;
m_dcGrid.TextOut ((m_rectClient.left+m_rectPlot.left)/2,
(m_rectPlot.bottom+m_rectPlot.top)/2, m_strYUnitsString) ;
m_dcGrid.SelectObject(oldFont) ;
// at this point we are done filling the the grid bitmap,
// no more drawing to this bitmap is needed until the setting are changed
// if we don't have one yet, set up a memory dc for the plot
if (m_dcPlot.GetSafeHdc() == NULL)
{
m_dcPlot.CreateCompatibleDC(&dc) ;
m_bitmapPlot.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight) ;
m_pbitmapOldPlot = m_dcPlot.SelectObject(&m_bitmapPlot) ;
}
// make sure the plot bitmap is cleared
m_dcPlot.SetBkColor (m_crBackColor) ;
m_dcPlot.FillRect(m_rectClient, &m_brushBack) ;
// finally, force the plot area to redraw
InvalidateRect(m_rectClient) ;
} // InvalidateCtrl
/////////////////////////////////////////////////////////////////////////////
double COScopeCtrl::AppendPoint(double dNewPoint)
{
// append a data point to the plot
// return the previous point
double dPrevious ;
dPrevious = m_dCurrentPosition ;
m_dCurrentPosition = dNewPoint ;
DrawPoint() ;
Invalidate() ;
return dPrevious ;
} // AppendPoint
////////////////////////////////////////////////////////////////////////////
void COScopeCtrl::OnPaint()
{
CPaintDC dc(this) ; // device context for painting
CDC memDC ;
CBitmap memBitmap ;
CBitmap* oldBitmap ; // bitmap originally found in CMemDC
// no real plotting work is performed here,
// just putting the existing bitmaps on the client
// to avoid flicker, establish a memory dc, draw to it
// and then BitBlt it to the client
memDC.CreateCompatibleDC(&dc) ;
memBitmap.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight) ;
oldBitmap = (CBitmap *)memDC.SelectObject(&memBitmap) ;
if (memDC.GetSafeHdc() != NULL)
{
// first drop the grid on the memory dc
memDC.BitBlt(0, 0, m_nClientWidth, m_nClientHeight,
&m_dcGrid, 0, 0, SRCCOPY) ;
// now add the plot on top as a "pattern" via SRCPAINT.
// works well with dark background and a light plot
memDC.BitBlt(0, 0, m_nClientWidth, m_nClientHeight,
&m_dcPlot, 0, 0, SRCPAINT) ; //SRCPAINT
// finally send the result to the display
dc.BitBlt(0, 0, m_nClientWidth, m_nClientHeight,
&memDC, 0, 0, SRCCOPY) ;
}
memDC.SelectObject(oldBitmap) ;
} // OnPaint
/////////////////////////////////////////////////////////////////////////////
void COScopeCtrl::DrawPoint()
{
// this does the work of "scrolling" the plot to the left
// and appending a new data point all of the plotting is
// directed to the memory based bitmap associated with m_dcPlot
// the will subsequently be BitBlt'd to the client in OnPaint
int currX, prevX, currY, prevY ;
CPen *oldPen ;
CRect rectCleanUp ;
if (m_dcPlot.GetSafeHdc() != NULL)
{
// shift the plot by BitBlt'ing it to itself
// note: the m_dcPlot covers the entire client
// but we only shift bitmap that is the size
// of the plot rectangle
// grab the right side of the plot (exluding m_nShiftPixels on the left)
// move this grabbed bitmap to the left by m_nShiftPixels
m_dcPlot.BitBlt(m_rectPlot.left, m_rectPlot.top+1,
m_nPlotWidth, m_nPlotHeight, &m_dcPlot,
m_rectPlot.left+m_nShiftPixels, m_rectPlot.top+1,
SRCCOPY) ;
// establish a rectangle over the right side of plot
// which now needs to be cleaned up proir to adding the new point
rectCleanUp = m_rectPlot ;
rectCleanUp.left = rectCleanUp.right - m_nShiftPixels ;
// fill the cleanup area with the background
m_dcPlot.FillRect(rectCleanUp, &m_brushBack) ;
// draw the next line segement
// grab the plotting pen
oldPen = m_dcPlot.SelectObject(&m_penPlot) ;
// move to the previous point
prevX = m_rectPlot.right-m_nPlotShiftPixels ;
prevY = m_rectPlot.bottom -
(long)((m_dPreviousPosition - m_dLowerLimit) * m_dVerticalFactor) ;
m_dcPlot.MoveTo (prevX, prevY) ;
// draw to the current point
currX = m_rectPlot.right-m_nHalfShiftPixels ;
currY = m_rectPlot.bottom -
(long)((m_dCurrentPosition - m_dLowerLimit) * m_dVerticalFactor) ;
m_dcPlot.LineTo (currX, currY) ;
// restore the pen
m_dcPlot.SelectObject(oldPen) ;
// if the data leaks over the upper or lower plot boundaries
// fill the upper and lower leakage with the background
// this will facilitate clipping on an as needed basis
// as opposed to always calling IntersectClipRect
if ((prevY <= m_rectPlot.top) || (currY <= m_rectPlot.top))
m_dcPlot.FillRect(CRect(prevX, m_rectClient.top, currX+1, m_rectPlot.top+1), &m_brushBack) ;
if ((prevY >= 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 = 40 ;
m_rectPlot.top = 20 ;
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() ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -