⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 oscopectrl.cpp

📁 VeryCD版的电驴源程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		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 + -