寻求Visual C++绘制XY数据图的最简程序示例(光谱仪应用)
Visual C++ XY数据图绘制示例(光谱仪用)
以下是基于MFC的极简XY数据图实现,仅保留核心绘图功能,方便你后续扩展COM端口读取、异步线程等逻辑:
实现步骤
- 创建一个MFC单文档应用程序(项目名比如
SpectroChart) - 在视图类(比如
CSpectroChartView)的OnDraw函数中替换为以下代码:
void CSpectroChartView::OnDraw(CDC* pDC) { CSpectroChartDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // 获取客户区尺寸 CRect clientRect; GetClientRect(&clientRect); int nWidth = clientRect.Width(); int nHeight = clientRect.Height(); // 绘图区域边距 const int nMargin = 50; CRect plotRect(nMargin, nMargin, nWidth - nMargin, nHeight - nMargin); // 绘制坐标轴 pDC->MoveTo(plotRect.left, plotRect.bottom); pDC->LineTo(plotRect.right, plotRect.bottom); // X轴 pDC->MoveTo(plotRect.left, plotRect.bottom); pDC->LineTo(plotRect.left, plotRect.top); // Y轴 // 绘制网格线(可选) pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(RGB(128, 128, 128)); int nXGridCount = 10; int nYGridCount = 8; for (int i = 1; i < nXGridCount; i++) { int x = plotRect.left + (plotRect.Width() * i) / nXGridCount; pDC->MoveTo(x, plotRect.top); pDC->LineTo(x, plotRect.bottom); // 绘制X轴刻度标签 CString strLabel; strLabel.Format(_T("%.1f"), (double)i * 100 / nXGridCount); // 模拟波长刻度 pDC->TextOut(x - 15, plotRect.bottom + 5, strLabel); } for (int i = 1; i < nYGridCount; i++) { int y = plotRect.bottom - (plotRect.Height() * i) / nYGridCount; pDC->MoveTo(plotRect.left, y); pDC->LineTo(plotRect.right, y); // 绘制Y轴刻度标签 CString strLabel; strLabel.Format(_T("%.1f"), (double)i * 1.0 / nYGridCount); // 模拟强度刻度 pDC->TextOut(plotRect.left - 40, y - 10, strLabel); } // 生成模拟光谱数据(替换为你的真实数据) const int nDataCount = 100; double dXData[nDataCount]; double dYData[nDataCount]; for (int i = 0; i < nDataCount; i++) { dXData[i] = (double)i * 100 / nDataCount; // 模拟0-100nm波长 dYData[i] = 0.8 * sin(dXData[i] * 0.1) + 0.1 * rand() / RAND_MAX; // 模拟光谱曲线 } // 转换数据点为屏幕坐标并绘制曲线 pDC->SetPen(CreatePen(PS_SOLID, 2, RGB(255, 0, 0))); POINT points[nDataCount]; for (int i = 0; i < nDataCount; i++) { // X坐标映射:数据范围[0,100] → 绘图区域宽度 points[i].x = plotRect.left + (int)((dXData[i] / 100.0) * plotRect.Width()); // Y坐标映射:数据范围[0,1] → 绘图区域高度(注意Y轴向下为正,所以反转) points[i].y = plotRect.bottom - (int)((dYData[i] / 1.0) * plotRect.Height()); } pDC->Polyline(points, nDataCount); // 绘制坐标轴标题 pDC->SetTextColor(RGB(0, 0, 0)); pDC->TextOut(plotRect.right / 2 - 20, plotRect.bottom + 20, _T("波长(nm)")); pDC->TextOut(plotRect.left - 30, plotRect.top / 2, _T("强度")); }
关键说明
- 核心逻辑:通过
CDC类的绘图函数实现坐标轴、网格、曲线的绘制 - 坐标映射:将光谱数据的数值范围转换为屏幕像素坐标,适配窗口大小
- 模拟数据:当前用正弦波+随机噪声模拟光谱曲线,你后续只需替换为从COM端口读取的真实数据
- 扩展方向:
- 添加异步线程读取COM端口数据,存储到文档类的全局数据结构中
- 线程中调用
Invalidate()触发视图重绘,更新图表 - 后续可添加按钮、输入框等控件,通过MFC消息机制控制数据读取
内容的提问来源于stack exchange,提问作者DrM
相关产品推荐
相关产品推荐

