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

📄 chartrx.cpp

📁 实现波形的显示,可以作为示波器的一个模块
💻 CPP
📖 第 1 页 / 共 3 页
字号:
			if (x_AxisLabel.rt.right > x_label_left)
			{
				n_x_TickOneLabel ++;
				return FALSE;
			}
			x_label_left = x_AxisLabel.rt.left;
		}
		// 判断重叠结束
	}
	else
	{
		if ((nLabels - 1) < index)    // 如果标签个数小于要求的索引值,不画这个
			return TRUE;
		
		CString str1;
		LPPOINTDATA pPoint = xLabelPoints.GetPoint(index);
		str1.Format(x_LabelFormat, pPoint->x);
		x_AxisLabel.GetStringSize(pMemDC->m_hDC, str1, str1.GetLength(), &size);
		int top = rt_Back.Height() - x_AxisTitle.rt.Height() - size.cy;
		int left = x_Mark - size.cx/2;
		x_AxisLabel.rt = CRect(left, top, left + size.cx, top + size.cy);
		x_AxisLabel.ShowText(pMemDC->m_hDC, str1,  DT_CENTER | DT_VCENTER | DT_SINGLELINE);

	}

	return TRUE;
}

BOOL CChartRx::DrawYLabel(CString str, int x_Mark, int y_Mark)
{
	if (str.GetLength() > y_AxisLabel.text.GetLength())
	{
		// 默认的,可以放"1234.567这么长,8字节,如果长了,需要重新计算位置,再画一次
		y_AxisLabel.text = str; // 保存最长的一个
		return FALSE;
	}
	SIZE size;

	y_AxisLabel.GetStringSize(pMemDC->m_hDC, y_AxisLabel.text, y_AxisLabel.text.GetLength(), &size);
	int top = y_Mark - size.cy/2;
	int left = y_AxisTitle.rt.Width();
	y_AxisLabel.rt = CRect(left, top, left + size.cx, top + size.cy);
	y_AxisLabel.ShowText(pMemDC->m_hDC, str,  DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
	return TRUE;
}

void CChartRx::DrawPlot()
{
	BOOL ret;
	if (shouldReDrawChart)         // 标记重新画背景的位置:initChart(),
	{
		ret = DrawChart();         // 画plot以外的背景
		if (!ret)
		{
			double x1 = x_minSel;
			double x2 = x_maxSel;
			double y1 = y_maxSel;
			double y2 = y_minSel;
			InitChart();           // 重新计算大小
			x_minSel = x1;
			x_maxSel = x2;
			y_maxSel = y1;
			y_minSel = y2;
			ret = DrawChart();
		}
		if (nChartType == 1)           // 画plot区域,折线图
			DrawLineChart();
		if (nChartType == 2)           // 画plot区域,直方图
			DrawChartHistogram();

		DrawUserPoint();
	}
	shouldReDrawChart = FALSE;
}

// 从数据转换为图上的象素偏移,0为x轴,1为y轴
// 画坐标轴的时候使用
double CChartRx::GetPixFromValue(int nAxis, double value)
{
	double pix = 0;
	if (nAxis == 0)
	{
		if (value > x_maxSel)
			value = x_maxSel;
		if (value < x_minSel)
			value = x_minSel;
		pix = rt_Plot.Width() * (value - x_minSel) / (x_maxSel - x_minSel) + rt_Plot.left;
	}
	else
	{
		if (value > y_maxSel)
			value = y_maxSel;
		if (value < y_minSel)
			value = y_minSel;
		pix = rt_Plot.top + rt_Plot.Height() * (y_maxSel - value) / (y_maxSel - y_minSel);
	}
	return pix;
}

// 从图上的象素偏移转换为数据,0为x轴,1为y轴
double CChartRx::GetValueFormPix(int nAxis, double pix)
{
	double value = 0;
	if (nAxis == 0)
	{
		if (pix < rt_Plot.left)
			pix = rt_Plot.left;
		if (pix > rt_Plot.right)
			pix = rt_Plot.right;
		value = (x_maxSel - x_minSel) * (pix - rt_Plot.left) / rt_Plot.Width() + x_minSel;
	}
	else
	{
		if (pix < rt_Plot.top)
			pix = rt_Plot.top;
		if (pix > rt_Plot.bottom)
			pix = rt_Plot.bottom;
		value = y_maxSel - (y_maxSel - y_minSel) * (pix - rt_Plot.top) / rt_Plot.Height();
	}
	return value;
}

void CChartRx::OnMouseMove(UINT nFlags, CPoint point) 
{
	shouldReDrawChart = TRUE;
	// 关于放大的部分
	if (isMagnifying)
	{
		shouldReDrawChart = FALSE;
		CRect rt = rt_Back;
		InflateRect(&rt, -2, -2);
		ClientToScreen(&rt);
		::ClipCursor(&rt);
	}
	else
		ClipCursor(NULL);
	ptCur = point;

	// 关于拖动的部分
	if (isDraging)
	{
		::SetCursor(hCurHand);
//		int x_off = point.x - ptDown.x;
//		int y_off = point.y - ptDown.y;
//
//		// 改变用户指点点标签的坐标,即移动点;
//		LPPOINTDATA   pPoint;
//		for (int i=0; i<userPoints.GetPointCount(); i++)
//		{
//			pPoint = userPoints.GetPoint(i);
//			pPoint->x =  (int)pPoint->x + x_off;
//			pPoint->y = (int)pPoint->y + y_off;
//		}

		double x_OffData = (x_maxSel - x_minSel) * (point.x - ptDown.x) / rt_Plot.Width();
		double y_OffData = (y_maxSel - y_minSel) * (point.y - ptDown.y) / rt_Plot.Height();
		x_minSel -= x_OffData;
		x_maxSel -= x_OffData;
		y_minSel += y_OffData;
		y_maxSel += y_OffData;
		ptDown = point;

		// 12-16 add
		CRect rt = rt_Back;
		InflateRect(&rt, -2, -2);
		ClientToScreen(&rt);
		::ClipCursor(&rt);
		//
		
		InvalidateRect(rt_Back);
		return;
	}
	else
	{
		// 只要不是在拖动,或者缩放图表就不需要重画,但是窗口大小改变时候,有问题,
		// 会引发这句,刷新失败,
		shouldReDrawChart = FALSE;
		ClipCursor(NULL);
	}

	// 如果光标在绘画区,就画提示
	if (rt_Plot.PtInRect(point))
		DrawTip(point.x, point.y);
	else
	{
		TipLabel.rt.bottom = TipLabel.rt.top;
		TipLabel.rt.right = TipLabel.rt.left;
		InvalidateRect(rt_Back);
	}
	if (bShowTip)
		HCURSOR old = ::SetCursor(hCurCross);


	CWnd::OnMouseMove(nFlags, point);
}

void CChartRx::OnLButtonDown(UINT nFlags, CPoint point) 
{
	this->SetFocus();
	if (!bCanMagnify)   // 不可以放大,不处理
		return;

	isMagnifying = TRUE;
	ptDown = point;
	shouldReDrawChart = TRUE;
	CStatic::OnLButtonDown(nFlags, point);
}

void CChartRx::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if (!bCanMagnify)   // 不可以放大,不处理
		return;

	if (((point.x - ptDown.x) < 5) || ((point.y - ptDown.y)) < 5)
	{
		isMagnifying = FALSE;
		this->Invalidate();
		CStatic::OnLButtonUp(nFlags, point);
		return;
	}
	double x0 = GetValueFormPix(0, ptDown.x);
	double x1 = GetValueFormPix(0, point.x);
	double y1 = GetValueFormPix(1, ptDown.y);
	double y0 = GetValueFormPix(1, point.y);
//	CString temp;
//	temp.Format(x_LabelFormat +"," + y_LabelFormat, GetValueFormPix(0, point.x), GetValueFormPix(1, point.y));
//	temp.Format("%d  %d", point.x, point.y);
//	MessageBox(temp);
	x_minSel = x0;
	x_maxSel = x1;
	y_minSel = y0;
	y_maxSel = y1;

	userPoints.Clear();  // 清除用户标记的点
	isMagnify = TRUE;
	isMagnifying = FALSE;
	shouldReDrawChart = TRUE;

	x_LabelFormat = AddFormat(x_LabelFormat, x_max - x_min, x_maxSel-x_minSel);
	this->Invalidate();
	CStatic::OnLButtonUp(nFlags, point);

	isMagnify = FALSE;
	isMagnified = TRUE;
	// 这行需要注释掉,否则放大有问题的!
	//	shouldReDrawChart = FALSE;
}

void CChartRx::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	x_minSel = x_min;
	x_maxSel = x_max;
	y_maxSel = y_max;
	y_minSel = y_min;
	isMagnified = FALSE;

	x_LabelFormat = x_LabelFormatSel;
	y_LabelFormat = y_LabelFormatSel;

	n_x_TickOneLabel = n_x_TickOneLabelSel;   // 几个大刻度一个标签
	n_y_TickOneLabel = n_y_TickOneLabelSel;
		
	userPoints.Clear();  // 清除用户标记的点
	shouldReDrawChart = TRUE;
	this->Invalidate();
	this->SetFocus();
	CStatic::OnLButtonDblClk(nFlags, point);
}
void CChartRx::OnRButtonDown(UINT nFlags, CPoint point) 
{
	ptDown = point;
	isDraging = TRUE;
	::SetCursor(hCurHand);

	shouldReDrawChart = TRUE;	
	CStatic::OnRButtonDown(nFlags, point);
}

void CChartRx::OnRButtonUp(UINT nFlags, CPoint point) 
{
	isDraging = FALSE;
//	shouldReDrawChart = FALSE;
	CStatic::OnRButtonUp(nFlags, point);
}
void CChartRx::DrawTip(int x, int y)
{
	CRect rt = TipLabel.rt;
	CString temp = "X=" + AddFormat(x_LabelFormat) + " Y=" + AddFormat(y_LabelFormat);
	TipLabel.text.Format(temp, GetValueFormPix(0, x), GetValueFormPix(1, y));
	SIZE size;
	TipLabel.GetStringSize(pMemDC->m_hDC, &size);
	if (x > rt_Back.Width()/2)
	{
		TipLabel.rt.right = x - 5;
		TipLabel.rt.left = TipLabel.rt.right - size.cx;
	}
	else
	{
		TipLabel.rt.left = x + 5;
		TipLabel.rt.right = TipLabel.rt.left + size.cx;
	}

	if (y > rt_Back.Height()/2)
	{
		TipLabel.rt.bottom = y - 5;
		TipLabel.rt.top = TipLabel.rt.bottom - size.cy;
	}
	else
	{
		TipLabel.rt.top = y + 5;
		TipLabel.rt.bottom = TipLabel.rt.top + size.cy;
	}

	if (rt.left > TipLabel.rt.left)
		rt.left = TipLabel.rt.left;
	if (rt.top > TipLabel.rt.top)
		rt.top = TipLabel.rt.top;
	if (rt.bottom < TipLabel.rt.bottom)
		rt.bottom = TipLabel.rt.bottom;
	if (rt.right < TipLabel.rt.right)
		rt.right = TipLabel.rt.right;
	
	if (isMagnifying)
		this->InvalidateRect(rt_Back);
	else
		this->InvalidateRect(rt);
}

void CChartRx::DrawScreen(CPaintDC *pDC)
{
	// 从背景图直接拷贝数据,减少了画背景的时间
//	pTempDC->SelectObject(m_pScreen);
	pMemDC->SelectObject(m_pBackGround);
//	pTempDC->BitBlt(0, 0, rt_Back.Width(), rt_Back.Height(), pMemDC, 0, 0, SRCCOPY); 

	pDC->BitBlt(0, 0, rt_Back.Width(), rt_Back.Height(), pMemDC, 0, 0, SRCCOPY); 

	CPen pen;
	pen.CreatePen(PS_SOLID, 1, crForeGround);
	if (isMagnifying)  // 画矩形
	{
		pDC->SelectObject(pen);
		CRect rt(ptDown, ptCur);
		pDC->MoveTo(ptDown);
		pDC->LineTo(ptDown.x, ptCur.y);
		pDC->LineTo(ptCur);
		pDC->LineTo(ptCur.x, ptDown.y);
		pDC->LineTo(ptDown);
	}
	else if(isDraging)
	{
	}
	else
	{
		if (bShowTip)
			TipLabel.ShowText(pDC->m_hDC, TipLabel.text, DT_CENTER | DT_SINGLELINE | DT_VCENTER); //
	}

}

void CChartRx::SaveBmpEx(LPCTSTR lpFileName)
{
	crBackGround = RGB(250, 250, 250);
	TitleLabel.SetColor(RGB(0, 0, 0));
	x_AxisTitle.SetColor(RGB(0, 0, 0)); // 128
	y_AxisTitle.SetColor(RGB(0, 0, 0));
	x_AxisLabel.SetColor(RGB(0, 0, 0));
	y_AxisLabel.SetColor(RGB(0, 0, 0));
	uptLine.SetStyle(1, PS_SOLID, RGB(0, 0, 0));
	userPointsLabel.SetColor(RGB(0, 0, 0));

		// 表格基本线的画笔
	x_Axis.SetStyle(1, PS_SOLID, RGB(0, 80, 0));         // x轴
	y_Axis.SetStyle(1, PS_SOLID, RGB(0, 80, 0));         // y轴
	h_Grid.SetStyle(1, PS_DOT, RGB(0, 80, 0));           // 横格线
	v_Grid.SetStyle(1, PS_DOT, RGB(0, 80, 0));           // 竖格线
	x_Degree.SetStyle(1, PS_SOLID, RGB(0, 80, 0));       // x轴上刻度
	y_Degree.SetStyle(1, PS_SOLID, RGB(0, 80, 0));       // y轴上刻度

	SetRedraw(FALSE);         // 控制屏幕不刷新
	shouldReDrawChart = TRUE; // 在内存中重新画一遍
	DrawPlot();

	SaveBmp(lpFileName);

	crBackGround = RGB(0, 60, 0);
	TitleLabel.SetColor(RGB(255, 255, 0));
	x_AxisTitle.SetColor(RGB(255, 255, 0)); // 128
	y_AxisTitle.SetColor(RGB(255, 255, 0));
	x_AxisLabel.SetColor(RGB(255, 255, 0));
	y_AxisLabel.SetColor(RGB(255, 255, 0));
	uptLine.SetStyle(1, PS_SOLID, RGB(255, 255, 0));
	userPointsLabel.SetColor(RGB(255, 255, 0));

	// 表格基本线的画笔
	x_Axis.SetStyle(1, PS_SOLID, RGB(0, 192, 0));         // x轴
	y_Axis.SetStyle(1, PS_SOLID, RGB(0, 192, 0));         // y轴
	h_Grid.SetStyle(1, PS_DOT, RGB(0, 192, 0));           // 横格线
	v_Grid.SetStyle(1, PS_DOT, RGB(0, 192, 0));           // 竖格线
	x_Degree.SetStyle(1, PS_SOLID, RGB(0, 192, 0));       // x轴上刻度
	y_Degree.SetStyle(1, PS_SOLID, RGB(0, 192, 0));       // y轴上刻度


	shouldReDrawChart = TRUE;
	DrawPlot();
	SetRedraw(TRUE);         // 控制屏幕不刷新
	


}

BOOL CChartRx::SaveBmp(LPCTSTR lpFileName)
{
	int iBits;                 // 当前分辨率下每象素所占字节数
	WORD wBitCount;            // 位图中每象素所占字节数
	DWORD dwPaletteSize = 0;   // 定义调色板大小, 
	DWORD dwBmBitsSize = 0;    // 位图中像素字节大小  
	DWORD dwDIBSize = 0;       // 位图文件大小
	DWORD dwWritten = 0;       // 写入文件字节数
	BITMAP Bitmap;             // 位图属性结构
	BITMAPFILEHEADER bmfHdr;   // 位图文件头结构 
	BITMAPINFOHEADER bi;       // 位图信息头结构
	
	LPBITMAPINFOHEADER lpbi;   //指向位图信息头结构 
	
	HANDLE fh = NULL;          // 定义文件, 
	HANDLE hDib = NULL;        //分配内存句柄,
	HANDLE hPal = NULL;        //调色板句柄
	HANDLE hOldPal = NULL; 
	
	//计算位图文件每个像素所占字节数 
	pMemDC->SelectObject(m_pBackGround);
	iBits = GetDeviceCaps(pMemDC->m_hDC, BITSPIXEL) * GetDeviceCaps(pMemDC->m_hDC, PLANES); 
	
	if (iBits <= 1) 
		wBitCount = 1; 
	else if (iBits <= 4) 
		wBitCount = 4; 
	else if (iBits <= 8)
		wBitCount = 8; 
	else 
		wBitCount = 24; 
	
	//wBitCount = 4;
	HBITMAP hBitmap = HBITMAP(*m_pBackGround);
	::GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&Bitmap);
	bi.biSize = sizeof(BITMAPINFOHEADER);
	bi.biWidth = Bitmap.bmWidth;
	bi.biHeight = Bitmap.bmHeight;
	bi.biPlanes = 1;
	bi.biBitCount = wBitCount;
	bi.biCompression = BI_RGB;
	bi.biSizeImage = 0;
	bi.biXPelsPerMeter = 0;
	bi.biYPelsPerMeter = 0;
	bi.biClrImportant = 0;
	bi.biClrUsed = 0;
	
	dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;
	
	//为位图内容分配内存 
	hDib = ::GlobalAlloc(GHND, dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER)); 
	lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib); 
	*lpbi = bi; 
	
	// 处理调色板 
	hPal = ::GetStockObject(DEFAULT_PALETTE); 
	if (hPal) 
	{ 
		hOldPal = ::SelectPalette(pMemDC->m_hDC, (HPALETTE)hPal, FALSE); 
	}
	
	// 获取该调色板下新的像素值 
	::GetDIBits(pMemDC->m_hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) 
		+dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS); 
	
	//恢复调色板 
	if (hOldPal) 
	{ 
		::SelectPalette(pMemDC->m_hDC, (HPALETTE)hOldPal, TRUE); 
		::RealizePalette(pMemDC->m_hDC); 
	} 
	
	//创建位图文件 
	fh = ::CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS, 
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); 
	
	if (fh == INVALID_HANDLE_VALUE) 
		return FALSE; 
	
	// 设置位图文件头 
	bmfHdr.bfType = 0x4D42; // "BM" 
	dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; 
	bmfHdr.bfSize = dwDIBSize; 
	bmfHdr.bfReserved1 = 0; 
	bmfHdr.bfReserved2 = 0; 
	bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; 
	// 写入位图文件头 
	::WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); 
	// 写入位图文件其余内容 
	::WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL); 
	//清除 
	::GlobalUnlock(hDib); // 解锁
	::GlobalFree(hDib);   // 释放文件数据存储区域
	::CloseHandle(fh);    // 关闭文件
	
	return TRUE;
}

void CChartRx::SetSerialCount(int count)
{
	// 一个线,或者说一个通道是一组数对,一个数对为一个点坐标,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -