📄 oscopectrl.cpp
字号:
if(CustShift.m_nPointsToDo == 1)
m_nShiftPixels = CustShift.m_nWidthToDo;
CustShift.m_nWidthToDo -= m_nShiftPixels;
CustShift.m_nPointsToDo--;
}
// now comes DrawPoint's shift process
if(m_dcPlot.GetSafeHdc() != NULL)
{
if(m_nShiftPixels > 0)
{
ScrollRect.left = m_rectPlot.left;
ScrollRect.top = m_rectPlot.top + 1;
ScrollRect.right = m_rectPlot.left + m_nPlotWidth;
ScrollRect.bottom = m_rectPlot.top + 1 + m_nPlotHeight;
ScrollRect = m_rectPlot;
ScrollRect.right ++;
m_dcPlot.ScrollDC(-m_nShiftPixels, 0, (LPCRECT)&ScrollRect, (LPCRECT)&ScrollRect, NULL, NULL);
// 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 + 1;
rectCleanUp.right ++;
// fill the cleanup area with the background
m_dcPlot.FillRect(rectCleanUp, &m_brushBack);
}
// draw the next line segement
for(iTrend = 0; iTrend < m_NTrends; iTrend ++)
{
currY = m_rectPlot.bottom -
(long)((m_PlotData[iTrend].dCurrentPosition - m_PlotData[iTrend].dLowerLimit) * m_PlotData[iTrend].dVerticalFactor);
m_PlotData[iTrend].nPrevY = currY;
// store the current point for connection to the next point
m_PlotData[iTrend].dPreviousPosition = m_PlotData[iTrend].dCurrentPosition;
}
}
// -----------------------------------------
if(bInvalidate && m_bDoUpdate)
Invalidate();
return;
} // AppendEmptyPoint
////////////////////////////////////////////////////////////////////////////
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);
memBitmap.DeleteObject();
} // 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, iTrend;
CPen *oldPen;
CRect ScrollRect, rectCleanUp;
if(m_dcPlot.GetSafeHdc() != NULL)
{
if(m_nShiftPixels > 0)
{
ScrollRect.left = m_rectPlot.left;
ScrollRect.top = m_rectPlot.top + 1;
ScrollRect.right = m_rectPlot.left + m_nPlotWidth;
ScrollRect.bottom = m_rectPlot.top + 1 + m_nPlotHeight;
ScrollRect = m_rectPlot;
ScrollRect.right ++;
m_dcPlot.ScrollDC(-m_nShiftPixels, 0, (LPCRECT)&ScrollRect, (LPCRECT)&ScrollRect, NULL, NULL);
// 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 + 1;
rectCleanUp.right ++;
// fill the cleanup area with the background
m_dcPlot.FillRect(rectCleanUp, &m_brushBack);
}
// draw the next line segement
for(iTrend = 0; iTrend < m_NTrends; iTrend ++)
{
// grab the plotting pen
oldPen = m_dcPlot.SelectObject(&m_PlotData[iTrend].penPlot);
// move to the previous point
prevX = m_rectPlot.right - m_nShiftPixels;
if(m_PlotData[iTrend].nPrevY > 0)
{
prevY = m_PlotData[iTrend].nPrevY;
}
else
{
prevY = m_rectPlot.bottom -
(long)((m_PlotData[iTrend].dPreviousPosition - m_PlotData[iTrend].dLowerLimit) * m_PlotData[iTrend].dVerticalFactor);
}
if(!m_PlotData[iTrend].BarsPlot)
m_dcPlot.MoveTo(prevX - 1, prevY);
// draw to the current point
currX = m_rectPlot.right;
currY = m_rectPlot.bottom -
(long)((m_PlotData[iTrend].dCurrentPosition - m_PlotData[iTrend].dLowerLimit) * m_PlotData[iTrend].dVerticalFactor);
m_PlotData[iTrend].nPrevY = currY;
if(m_PlotData[iTrend].BarsPlot)
m_dcPlot.MoveTo(currX - 1, m_rectPlot.bottom);
else
{
if(abs(prevX - currX) > abs(prevY - currY))
{
currX += prevX - currX>0 ? -1 : 1;
}
else
{
currY += prevY - currY>0 ? -1 : 1;
}
}
m_dcPlot.LineTo(currX - 1, currY);
//if(drawBars) || m_PlotData[iTrend].BarsPlot)
// m_dcPlot.LineTo(currX - 1, m_rectPlot.bottom);
// m_dcPlot.Rectangle(currX-1,currY,currX-1,m_rectPlot.bottom);
// 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 - 1, m_rectClient.top, currX + 5, m_rectPlot.top + 1), &m_brushBack);
if((prevY >= m_rectPlot.bottom) || (currY >= m_rectPlot.bottom))
m_dcPlot.FillRect(CRect(prevX - 1, m_rectPlot.bottom + 1, currX + 5, m_rectClient.bottom + 1), &m_brushBack);
// store the current point for connection to the next point
m_PlotData[iTrend].dPreviousPosition = m_PlotData[iTrend].dCurrentPosition;
}
}
} // end DrawPoint
/////////////////////////////////////////////////////////////////////////////
void COScopeCtrl::OnSize(UINT nType, int cx, int cy)
{
if (!cx && !cy)
return;
int iTrend;
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
for(iTrend = 0; iTrend < m_NTrends; iTrend ++)
m_PlotData[iTrend].dVerticalFactor = (double)m_nPlotHeight / m_PlotData[iTrend].dRange;
// destroy and recreate the grid bitmap
CClientDC dc(this);
if(m_pbitmapOldGrid && m_bitmapGrid.GetSafeHandle() && m_dcGrid.GetSafeHdc())
{
m_dcGrid.SelectObject(m_pbitmapOldGrid);
m_bitmapGrid.DeleteObject();
m_bitmapGrid.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
m_pbitmapOldGrid = m_dcGrid.SelectObject(&m_bitmapGrid);
}
// destroy and recreate the plot bitmap
if(m_pbitmapOldPlot && m_bitmapPlot.GetSafeHandle() && m_dcPlot.GetSafeHdc())
{
m_dcPlot.SelectObject(m_pbitmapOldPlot);
m_bitmapPlot.DeleteObject();
m_bitmapPlot.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight);
m_pbitmapOldPlot = m_dcPlot.SelectObject(&m_bitmapPlot);
}
InvalidateCtrl();
} // OnSize
/////////////////////////////////////////////////////////////////////////////
void COScopeCtrl::Reset()
{
// simply invalidate the entire control
for(int i = 0; i < m_NTrends; i++)
{
// Clear all points
m_PlotData[i].dPreviousPosition = 0.0;
m_PlotData[i].nPrevY = -1;
for(int iTrend = 0; iTrend < m_NTrends; iTrend++){
m_PlotData[iTrend].lstPoints.RemoveAll();
}
}
// to clear the existing data (in the form of a bitmap)
// simply invalidate the entire control
InvalidateCtrl();
}
int COScopeCtrl::ReCreateGraph(void)
{
for(int i = 0; i < m_NTrends; i++)
{
m_PlotData[i].dPreviousPosition = 0.0;
m_PlotData[i].nPrevY = -1;
}
double *pAddPoints = new double[m_NTrends];
POSITION* pPosArray = new POSITION[m_NTrends];
// Try to avoid to call the method AppendPoints() more than necessary
// Remark: the default size of the list is 1024
int pointToDraw = m_PlotData[0].lstPoints.GetCount();
if(pointToDraw > (m_nPlotWidth/m_nShiftPixels)+1)
{
pointToDraw = (m_nPlotWidth/m_nShiftPixels)+1;
}
int startIndex = m_PlotData[0].lstPoints.GetCount() - pointToDraw;
// Prepare to go through the elements on n lists in parallel
for(int iTrend = 0; iTrend < m_NTrends; iTrend++)
{
pPosArray[iTrend] = m_PlotData[iTrend].lstPoints.FindIndex(startIndex);
}
// We will assume that each trends have the same among of points, so we test only the first iterator
while(pPosArray[0] != 0){
for(int iTrend = 0; iTrend < m_NTrends; iTrend++){
pAddPoints[iTrend] = m_PlotData[iTrend].lstPoints.GetNext(pPosArray[iTrend]);
}
// Pass false for new bUseTrendRatio parameter so that graph is recreated correctly...
AppendPoints(pAddPoints, false, false, false);
}
delete[] pAddPoints;
delete[] pPosArray;
// Draw the new graph without waiting on the next AppendPoints()
Invalidate();
return 0;
}
void COScopeCtrl::OnTimer(UINT nIDEvent)
{
if(nIDEvent == m_nRedrawTimer)
{
KillTimer(m_nRedrawTimer);
m_nRedrawTimer = 0;
m_bDoUpdate = true;
ReCreateGraph();
}
CWnd::OnTimer(nIDEvent);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -