1.新建一个MFC工程,在资源视图->Dialog下新建一个对话框ID为IDC_DIALOG1,在工具箱里为该对话框添加Static text ,并设置ID为IDC_TEXT,在类向导里添加一个类ControlDlg类继承于CDIALOGEX;
2.项目->添加类 添加一个Graph类继承于CStatic,并在里面实现画网格代码如下:
//头文件 .h
class CGraph : public CStatic
{
DECLARE_DYNAMIC(CGraph)
public:
CGraph();
virtual ~CGraph();
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
void RefreshGraph(CDC* pDC);
private:
CRect m_rectCtrl; //控件矩形区域
COLORREF m_bkColor; // 背景颜色
COLORREF m_gridColor; //网格颜色
COLORREF m_lineColor; //线条颜色
COLORREF m_fontColor; //字体颜色
CRect m_rectDraw; //用于绘制曲线的区域
int m_gapLeft; //左边留白距离
int m_gapBottom; //下边留白距离
int m_gapTop; //上边留白距离
int m_xPointNum; //X轴的点数
int m_yPointNum; //Y轴的点数
double m_xGridSpacing; //网格水平方向间距
double m_yGridSpacing; //网格垂直方向间距
CArray
double m_yPixHeight; //Y轴每个像素点所代表的高度
double m_yScaleInterval; //Y轴两个刻度值之间的数值差
double m_tableMax; //表格上限值
double m_tableMin; //表格下限值
CArray
CArray
int m_refreshRate; //刷新速度
double m_yTextBoxWidth; //Y轴刻度值的宽度
double m_yTextBoxHeight; //Y轴刻度值的高度
public:
void DrawBackground(CDC* pDc);
// 更新界面
void RefreshLayout();
//绘制坐标轴
void DrawAxises(CDC* pDC);
void DrawGrids(CDC* pDC);
// 绘制曲线
void DrawLines(CDC* pDC);
void SetTableMaxAndMin(CArray
// 寻找动态数组最大最小值
void FindMaxAndMin(CArray
// 启动定时器,开始刷新画面
void Start();
void SetRefreshRate(int eTime);
// 添加新值
void AddNewValue(double value);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnSize(UINT nType, int cx, int cy);
// 设置X轴刻度个数
void SetXPointNum(int num);
// 设置Y轴刻度个数
void SetYPointNum(int num);
// 添加一系列值
void AddSeriesNewValue(CArray
// 清除所有的值
void ClearAllValue();
// 获取绘图区域
CRect GetRectDraw();
};
//CPP文件
#include "stdafx.h"
#include "Medea.h"
#include "Graph.h"
// CGraph
IMPLEMENT_DYNAMIC(CGraph, CStatic)
CGraph::CGraph()
{
m_bkColor = RGB(0, 0, 0);
m_lineColor = RGB(0, 0, 255);
m_gridColor = RGB(0, 50, 0);
m_fontColor = RGB(255, 255, 255);
m_gapLeft = 50;
m_gapBottom = 20;
m_gapTop = 20;
m_xPointNum = 50;
m_yPointNum = 10;
m_yTextBoxWidth = 40.0;
m_yTextBoxHeight = 20.0;
}
CGraph::~CGraph()
{
}
BEGIN_MESSAGE_MAP(CGraph, CStatic)
ON_WM_PAINT()
ON_WM_TIMER()
ON_WM_SIZE()
END_MESSAGE_MAP()
void CGraph::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CStatic::OnPaint()
CDC *pDC = GetDC();
CRect rect;
GetClientRect(&rect);
//创建一个内存中的显示设备
CDC nDC;
nDC.CreateCompatibleDC(NULL);
//创建一个内存中的图像
CBitmap nBitmap;
nBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
//指定内存显示设备在内存中的图像上画图
nDC.SelectObject(&nBitmap);
// 刷新控件
RefreshGraph(&nDC);
//将内存中画好的图像直接拷贝到屏幕指定区域上
pDC->BitBlt(rect.left, rect.top, rect.right, rect.bottom, &nDC, 0, 0, SRCCOPY);
//释放相关资源
nBitmap.DeleteObject();
nDC.DeleteDC();
ReleaseDC(pDC);
}
void CGraph::RefreshGraph(CDC* pDC)
{
//更新布局
RefreshLayout();
//绘制背景
DrawBackground(pDC);
//绘制坐标轴
DrawAxises(pDC);
//绘制网格
DrawGrids(pDC);
//绘制图例
//DrawLegend(pDC, m_rectLegend);
绘制标题
//DrawTile(pDC, m_rectTitle);
//绘制曲线
DrawLines(pDC);
}
void CGraph::DrawBackground(CDC* pDC)
{
pDC->FillSolidRect(&m_rectCtrl, m_bkColor);
}
// 更新界面
void CGraph::RefreshLayout()
{
GetClientRect(&m_rectCtrl);//获取控件区域
m_rectDraw.left = m_rectCtrl.left + m_gapLeft;
m_rectDraw.bottom = m_rectCtrl.bottom - m_gapBottom;
m_rectDraw.right = m_rectCtrl.right;
m_rectDraw.top = m_rectCtrl.top + m_gapTop;
m_xGridSpacing = (double)m_rectDraw.Width() / (double)m_xPointNum;
m_yGridSpacing = (double)m_rectDraw.Height() / (double)m_yPointNum;
SetTableMaxAndMin(m_valueArray, m_tableMax, m_tableMin);
m_yPixHeight = (m_tableMax - m_tableMin) / (double)m_rectDraw.Height();
m_yScaleInterval = (m_tableMax - m_tableMin) / (double)m_yPointNum;
}
void CGraph::DrawAxises(CDC* pDC)
{
if (!pDC->GetSafeHdc()){ return; }
// 绘制X轴
CPen pen(PS_SOLID, 2, RGB(0, 255, 0));
CPen *oldPen = pDC->SelectObject(&pen);
// 下方X轴
pDC->MoveTo(m_rectDraw.left, m_rectDraw.bottom);
pDC->LineTo(m_rectDraw.right, m_rectDraw.bottom);
// 上方X轴
pDC->MoveTo(m_rectDraw.left, m_rectDraw.top);
pDC->LineTo(m_rectDraw.right, m_rectDraw.top);
// 恢复画笔
//pDC->SelectObject(oldPen);
// 绘制Y轴
// 绘制横线
pDC->MoveTo(m_rectDraw.left, m_rectDraw.bottom);
pDC->LineTo(m_rectDraw.left, m_rectDraw.top);
// 恢复画笔
pDC->SelectObject(oldPen);
}
void CGraph::DrawGrids(CDC* pDC)
{
/*if ((!pDC->GetSafeHdc()) || (!this->ShowGrid))
{
return;
}*/
CString txtStr;// 显示坐标值的文字
CFont textFont;// 坐标值文字格式
// 坐标值文字格式
textFont.CreatePointFont(80, _T("Courier New"), NULL);
// 绘制纵向网格
CPen pen(PS_SOLID, 2, m_gridColor);
CPen *oldPen = pDC->SelectObject(&pen);
for (int i = 1, xi = 0; xi = i*m_xGridSpacing + m_rectDraw.left, xi <= m_rectDraw.right; i++)
{
pDC->MoveTo(xi, m_rectDraw.bottom - 2);
pDC->LineTo(xi, m_rectDraw.top + 2);
// 显示X坐标
//CFont *oldFont = pDC->SelectObject(&textFont);// 设置字体格式
//pDC->SetTextColor(m_fontColor);// 设置字体颜色
//txtStr.Format(_T("%4.1f"), m_tableMin+ i*yScaleInterval);
//pDC->DrawText(txtStr, CRect(xi - m_yTextBoxWidth / 2,
// m_rectDraw.bottom + 1,// +1是为了不挡住X坐标轴
// xi + yScaleInterval / 2,
// m_rectDraw.bottom + m_yTextBoxHeight + 1),
// DT_BOTTOM | DT_CENTER);
//pDC->SelectObject(oldFont);
}
// 绘制横向网格
for (int i = 1, yi = 0; yi = m_rectDraw.bottom - i*m_yGridSpacing, yi>m_rectDraw.top; i++)
{
pDC->MoveTo(m_rectDraw.left, yi);
pDC->LineTo(m_rectDraw.right, yi);
// 显示Y坐标值
CFont *oldFont = pDC->SelectObject(&textFont);// 设置字体格式
pDC->SetTextColor(m_fontColor);// 设置字体颜色
txtStr.Format(_T("%4.1f"), m_tableMin + i*m_yScaleInterval);
pDC->DrawText(txtStr, CRect(m_rectCtrl.left,
yi - m_yTextBoxHeight / 2,
m_rectDraw.left - 1,
yi + m_yTextBoxHeight / 2),
DT_BOTTOM | DT_RIGHT);
if (i==1){
txtStr.Format(_T("%4.1f"), m_tableMin);
pDC->DrawText(txtStr, CRect(m_rectCtrl.left,
m_rectDraw.bottom - m_yTextBoxHeight / 2,
m_rectDraw.left - 1,
m_rectDraw.bottom + m_yTextBoxHeight / 2),
DT_BOTTOM | DT_RIGHT);
}
if (i == m_yPointNum - 1){
txtStr.Format(_T("%4.1f"), m_tableMax);
pDC->DrawText(txtStr, CRect(m_rectCtrl.left,
m_rectDraw.top - m_yTextBoxHeight / 2,
m_rectDraw.left - 1,
m_rectDraw.top + m_yTextBoxHeight / 2),
DT_BOTTOM | DT_RIGHT);
}
pDC->SelectObject(oldFont);
}
// 恢复画笔
pDC->SelectObject(oldPen);
}
// 绘制曲线
void CGraph::DrawLines(CDC* pDC)
{
// 画笔
CPen pen(PS_SOLID, 2, m_lineColor);
CPen *oldPen = pDC->SelectObject(&pen);
int vaSize = m_valueArray.GetSize();
//if (vaSize <= xPointNum + 1){
if (vaSize > m_xPointNum + 1)
m_valueArray.RemoveAt(0);
for (int i = 0; i < m_valueArray.GetSize() - 1; i++)
{
int h = m_rectDraw.Height();
int v1 = m_valueArray[i ];
int x1 = i*m_xGridSpacing + m_rectDraw.left;
int y1 = (m_valueArray[i] - m_tableMin) * m_rectDraw.Height() / (m_tableMax - m_tableMin);
y1 = m_rectDraw.bottom - y1;
pDC->MoveTo(x1, y1);
int x2 = (i + 1)*m_xGridSpacing + m_rectDraw.left;
int v2 = m_valueArray[i + 1];
int y2 = (m_valueArray[i + 1] - m_tableMin) * m_rectDraw.Height() / (m_tableMax - m_tableMin);
y2 = m_rectDraw.bottom - y2;
pDC->LineTo(x2, y2);
}
//}
// 恢复画笔
pDC->SelectObject(oldPen);
//}
}
void CGraph::SetTableMaxAndMin(CArray
{
double max = 0;
double min = 100;
FindMaxAndMin(m_array, max, min);
if (tMax > max + 1 || tMax < max)
tMax = max;
if (tMin<(min - 1) || tMin>min)
tMin = min;
}
// 寻找动态数组最大最小值
void CGraph::FindMaxAndMin(CArray
{
for (int i = 0; i < m_array.GetSize(); i++)
{
tMax = tMax>m_array[i] ? tMax : m_array[i];
tMin = tMin < m_array[i] ? tMin : m_array[i];
}
}
// 启动定时器,开始刷新画面
void CGraph::Start()
{
SetTimer(1, m_refreshRate, NULL);
}
void CGraph::SetRefreshRate(int eTime)
{
m_refreshRate = eTime;
}
// 添加新值
void CGraph::AddNewValue(double value)
{
m_valueArray.Add(value);
}
void CGraph::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
this->Invalidate();
CStatic::OnTimer(nIDEvent);
}
void CGraph::OnSize(UINT nType, int cx, int cy)
{
CStatic::OnSize(nType, cx, cy);
// TODO: 在此处添加消息处理程序代码
CRect cr;
//GetClientRect(&cr);
GetClientRect(&cr);
RefreshLayout();
Invalidate();
}
// 设置X轴刻度个数
void CGraph::SetXPointNum(int num)
{
m_xPointNum = num;
}
// 设置Y轴刻度个数
void CGraph::SetYPointNum(int num)
{
m_yPointNum = num;
}
// 添加一系列值
void CGraph::AddSeriesNewValue(CArray
{
for (int i = 0; i < ptArray.GetSize(); i++)
{
m_valueArray.Add(ptArray[i]);
}
}
// 清除所有的值
void CGraph::ClearAllValue()
{
m_valueArray.RemoveAll();
}
// 获取绘图区域
CRect CGraph::GetRectDraw()
{
return m_rectDraw;
}
2,右键Static text 为该控件添加CGraph类型的变量m_Graph,(CGraph类型是手动改的!!!)
3.为ControlDlg.cpp里加上OnSize(),在里面添加::SetWindowPos(m_Graph.GetSafeHwnd(), HWND_BOTTOM, 0, 0, cx, cy, SWP_NOZORDER);