实例详解:MFC坐标轴实现
需求:MFC坐标轴实现-----最好有步骤啊,刚刚才接触C++和MFC啊。MFC怎样在特定区域建立坐标轴,x轴自适应,y轴有固定范围,最好有网格。
解决思路:VC 内存绘图,不闪屏,具体代码如下:
// 先上传代码,在.h 文件中:
#pragma once #include <afxtempl.h> #define TEXT_AREA_WIDTH (60) ///< 文字区宽度,单位 像素
#define X_AXIS_GRAD (600) ///< X 轴刻度值
#define Y_AXIS_GRAD (50) ///< X 轴刻度值 class My_Draw : public CStatic
{
// 构造/析构 函数
public:
My_Draw();
virtual ~My_Draw();
public:
struct
{
unsigned char Show_Max_Grid :; // 是否显示大网格
unsigned char Show_Min_Grid :; // 是否显示小网格
unsigned char Draw_Enable :; // 放大/缩小使能位
unsigned char Draw_Line_Choice :; // 线被选择
unsigned char LButton_Down_Flag :; // 鼠标左键按下标志
unsigned char LButton_Up_Flag :; // 鼠标左键弹起标志
unsigned char LButton_Double_Down_Flag :; // 鼠标左键双击按下标志
}Bool_Flag; unsigned int TextAreaWidth;
int xAxisGrad,yAxisGrad;
unsigned short xMaxGrad,xMinGrad;
unsigned short yMaxGrad,yMinGrad; int Limit_Min,Limit_Max; POINT Mouse_Current_Point; // 鼠标当前坐标
POINT Button_Down_Point; // 记录鼠标左键按下时的坐标
POINT LButton_Double_Down_Point; // 记录鼠标左键双击按下的坐标
POINT Old_LButton_Double_Down_Point; // 画笔列表
CPen* pBrack; // 黑色画笔
CPen* pBlue; // 蓝色画笔
CPen* pYellow; // 黄色画笔
CPen* pGren; // 绿色画笔
CPen* pPink; // 紫色画笔
CPen* pRed; // 红色画笔
CPen* pGray; // 灰色画笔 CRect Draw_Size;
CDC memDC;
CBitmap memBitmap;
CBitmap* pOldBmp; unsigned short SheetMaxH; CWnd *pWnd; void Draw();
void Drawing(CDC *pDC); // 绘制图表
void Draw_xAxis(CDC *pDC);
void Draw_yAxis(CDC *pDC);
void Draw_Cross_Cursor(CDC *pDC); void My_Draw::SaveBmpToFile();
protected: afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()
};
// .CPP 文件中:
#include "stdafx.h"
#include "Draw_Static_Text.h"
#include "conio.h"
#include "direct.h" #ifdef _DEBUG
#define new DEBUG_NEW
#endif // 构造函数
My_Draw::My_Draw()
{
Bool_Flag.Show_Max_Grid = false;
Bool_Flag.Show_Min_Grid = false;
Bool_Flag.Draw_Enable = false;
Bool_Flag.Draw_Line_Choice = false;
Bool_Flag.LButton_Down_Flag = false;
Bool_Flag.LButton_Up_Flag = false;
Bool_Flag.LButton_Double_Down_Flag = false; TextAreaWidth = TEXT_AREA_WIDTH;
xAxisGrad = X_AXIS_GRAD;
yAxisGrad = Y_AXIS_GRAD; pBrack = new CPen(); // 黑色画笔
pBlue = new CPen(); // 蓝色画笔
pYellow = new CPen(); // 黄色画笔
pGren = new CPen(); // 绿色画笔
pRed = new CPen(); // 红色画笔
pPink = new CPen(); // 紫色画笔
pGray = new CPen(); // 灰色画笔 pBrack->CreatePen(PS_SOLID,,RGB(,,));
pBlue->CreatePen(PS_SOLID,,RGB(,,));
pYellow->CreatePen(PS_SOLID,,RGB(,,));
pGren->CreatePen(PS_SOLID,,RGB(,,));
pRed->CreatePen(PS_SOLID,,RGB(,,));
pPink->CreatePen(PS_SOLID,,RGB(,,));
pGray->CreatePen(PS_DOT,,RGB(,,)); #ifdef _DEBUG
AllocConsole();
_cprintf("Debuging....\r\n");
#endif
} // 析构函数
My_Draw::~My_Draw()
{
delete pBrack; // 黑色画笔
delete pBlue; // 蓝色画笔
delete pYellow; // 黄色画笔
delete pGren; // 绿色画笔
delete pRed; // 红色画笔
delete pPink; // 紫色画笔
delete pGray; // 灰色画笔
} BEGIN_MESSAGE_MAP(My_Draw, CStatic)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP() void My_Draw::SaveBmpToFile() // 保存图表为 Bmp 图片
{
CFileDialog dlg(false,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
"位图文件(*.bmp)|*.bmp|",NULL); if (dlg.DoModal()!= IDOK) return;
CString filename = dlg.GetFileName() + ".bmp"; // 获取绘制坐标的文本框
this->GetClientRect(&Draw_Size); // 获取窗口大小
CDC *pDC = this->GetDC(); // 获取 dc
this->Invalidate();
this->UpdateWindow(); //内存绘图
memDC.CreateCompatibleDC(pDC);
memBitmap.CreateCompatibleBitmap(pDC,Draw_Size.right,Draw_Size.bottom);
pOldBmp = memDC.SelectObject(&memBitmap);
memDC.BitBlt(Draw_Size.left,Draw_Size.top,Draw_Size.right,Draw_Size.bottom,pDC,,,SRCCOPY);
Drawing(&memDC); // 绘制坐标 BITMAP bmp;
memBitmap.GetBitmap(&bmp); // 获得位图信息
FILE *fp;
fopen_s(&fp,filename, "w+b");
BITMAPINFOHEADER bih = {}; // 位图信息头
bih.biBitCount = bmp.bmBitsPixel; // 每个像素字节大小
bih.biCompression = BI_RGB;
bih.biHeight = bmp.bmHeight; // 高度
bih.biPlanes = ;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight; // 图像数据大小
bih.biWidth = bmp.bmWidth; // 宽度
BITMAPFILEHEADER bfh = {}; // 位图文件头
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // 到位图数据的偏移量
bfh.bfSize = bfh.bfOffBits + bmp.bmWidthBytes * bmp.bmHeight; // 文件总的大小
bfh.bfType = (WORD)0x4d42;
fwrite(&bfh, , sizeof(BITMAPFILEHEADER), fp); // 写入位图文件头
fwrite(&bih, , sizeof(BITMAPINFOHEADER), fp); // 写入位图信息头
byte * p = new byte[bmp.bmWidthBytes * bmp.bmHeight]; // 申请内存保存位图数据
GetDIBits(memDC.m_hDC, (HBITMAP) memBitmap.m_hObject, , Draw_Size.Height(), p, (LPBITMAPINFO) &bih, DIB_RGB_COLORS); //获取位图数据
fwrite(p, , bmp.bmWidthBytes * bmp.bmHeight, fp); // 写入位图数据
delete [] p;
fclose(fp); memDC.SelectObject(pOldBmp);
memDC.DeleteDC(); // 释放 Dc
memBitmap.DeleteObject();
} void My_Draw::Draw()
{
this->Invalidate();
this->UpdateWindow();
this->GetClientRect(&Draw_Size); // 获取窗口大小
CDC *pDC = this->GetDC(); // 获取 dc
//内存绘图
memDC.CreateCompatibleDC(pDC);
memBitmap.CreateCompatibleBitmap(pDC,Draw_Size.right,Draw_Size.bottom);
pOldBmp = memDC.SelectObject(&memBitmap);
memDC.BitBlt(Draw_Size.left,Draw_Size.top,Draw_Size.right,Draw_Size.bottom,pDC,,,SRCCOPY);
Drawing(&memDC); // 绘制坐标
pDC->BitBlt(Draw_Size.left,Draw_Size.top,Draw_Size.right,Draw_Size.bottom,&memDC,,,SRCCOPY); memDC.SelectObject(pOldBmp);
memDC.DeleteDC();
memBitmap.DeleteObject(); ReleaseDC(pDC);
} void My_Draw::Drawing(CDC *pDC)
{
pDC->SelectObject(pBrack); // 选择当前画笔颜色
pDC->Rectangle(,,Draw_Size.Width(),Draw_Size.Height()); // 设定绘制范围 //绘出文字 pDC->SetTextColor(RGB(,,));
pDC->SetBkMode(TRANSPARENT);
pDC->TextOutA(,,"输");
pDC->TextOutA(,,"出");
pDC->TextOutA(,,"电");
pDC->TextOutA(,,"压");
pDC->TextOutA(,,"|");
pDC->TextOutA(,,"单");
pDC->TextOutA(,,"位");
pDC->TextOutA(,,"(V)"); pDC->TextOutA(Draw_Size.Width()/-,Draw_Size.Height()-,"行 程--单位 (%)"); SheetMaxH = Draw_Size.Height()-TextAreaWidth; Draw_xAxis(pDC);
Draw_yAxis(pDC);
Draw_Cross_Cursor(pDC); ReleaseDC(pDC);
} void My_Draw::Draw_xAxis(CDC *pDC)
{
CString StrScale; // 转换刻度字符串存放点
unsigned short drawCount; // 画王格计数
unsigned short temp;
unsigned int girdSize; //绘制x轴坐标
pDC->MoveTo(TextAreaWidth,SheetMaxH);
pDC->LineTo(Draw_Size.Width(),SheetMaxH);
//绘制箭头
pDC->LineTo(Draw_Size.Width()-,SheetMaxH-);
pDC->MoveTo(Draw_Size.Width(),SheetMaxH);
pDC->LineTo(Draw_Size.Width()-,SheetMaxH+); //绘制x轴刻度
drawCount = ;
if(xAxisGrad > Draw_Size.Width())
{
xAxisGrad/=;
girdSize = ;
}
else
girdSize = ; xMaxGrad = int((Draw_Size.Width() - TextAreaWidth) / xAxisGrad);
for(int i=TextAreaWidth; i<=Draw_Size.Width(); i+=xMaxGrad)
{
pDC->SelectObject(pBrack);
pDC->MoveTo(i,SheetMaxH);
if(xMaxGrad<)
temp = xMaxGrad*;
else
temp = xMaxGrad*;
if((i-TextAreaWidth)%temp==)
{
pDC->LineTo(i,SheetMaxH+); // 整数刻度,绘制长刻度 //输出对应的文本
if(drawCount < )
{
//pDC->SelectObject(font1); //选择当前字体
StrScale.Format(" %d", drawCount*girdSize);
pDC->SetTextColor(RGB(, , ));
pDC->TextOutA(i-, SheetMaxH+, StrScale); //修正文本显示坐标 3位数内,显示方式 if(Bool_Flag.Show_Max_Grid)
{
pDC->SelectObject(pGray); //使用虚线灰色画笔
pDC->MoveTo(i,SheetMaxH);
pDC->LineTo(i,);
}
}
else
{
StrScale.Format(" %d", drawCount*girdSize);
pDC->TextOutA(i-, SheetMaxH+, StrScale); //修正文本显示坐标 4位数内,显示方式 if(Bool_Flag.Show_Max_Grid)
{
pDC->SelectObject(pGray); //使用虚线灰色画笔
pDC->MoveTo(i, SheetMaxH);
pDC->LineTo(i, );
}
}
}
else
{
pDC->LineTo(i,SheetMaxH+); //小数刻度,绘制短刻度
}
drawCount++;
} ReleaseDC(pDC);
} void My_Draw::Draw_yAxis(CDC *pDC)
{
unsigned int drawCount;
CString StrScale; //转换刻度字符串存放点 drawCount = ;
//绘制y轴坐标
pDC->MoveTo(TextAreaWidth, SheetMaxH);
pDC->LineTo(TextAreaWidth, );
//绘制箭头
pDC->LineTo(TextAreaWidth-, );
pDC->MoveTo(TextAreaWidth, );
pDC->LineTo(TextAreaWidth+, ); yMaxGrad = int(SheetMaxH / yAxisGrad);
for(int i=SheetMaxH; i>=; i-=yMaxGrad)
{
pDC->SelectObject(pBrack);
StrScale.Format("%d", drawCount / );
pDC->MoveTo(TextAreaWidth, i); if(drawCount % ==)
{
pDC->LineTo(TextAreaWidth-, i); //整数刻度,绘制长刻度 if(Bool_Flag.Show_Max_Grid)
{
pDC->SelectObject(pGray); //使用实线灰色画笔
pDC->MoveTo(TextAreaWidth, i);
pDC->LineTo(Draw_Size.Width()-, i);
} pDC->SetTextColor(RGB(, , ));
pDC->TextOutA(TextAreaWidth-, i-, StrScale+"V"); //输出对应的文本
}
else
{
pDC->LineTo(TextAreaWidth-, i); //小数刻度,绘制短刻度
}
drawCount++;
} ReleaseDC(pDC);
} void My_Draw::Draw_Cross_Cursor(CDC *pDC)
{
int m_intVoltage;
int m_intAngle; // 十字光标和显示坐标信息
if(Bool_Flag.LButton_Double_Down_Flag)
{
if((LButton_Double_Down_Point.x > TextAreaWidth)
&&(LButton_Double_Down_Point.x < Draw_Size.Width())
&&(LButton_Double_Down_Point.y > )
&&(LButton_Double_Down_Point.y < SheetMaxH))
{
if(Bool_Flag.Draw_Line_Choice)
pDC->SelectObject(pGren);
else
pDC->SelectObject(pRed); pDC->MoveTo(LButton_Double_Down_Point.x, );
pDC->LineTo(LButton_Double_Down_Point.x, SheetMaxH-); pDC->MoveTo(TextAreaWidth+, LButton_Double_Down_Point.y);
pDC->LineTo(Draw_Size.Width()-,LButton_Double_Down_Point.y); Old_LButton_Double_Down_Point = LButton_Double_Down_Point; m_intVoltage = yAxisGrad;
m_intVoltage = (SheetMaxH - LButton_Double_Down_Point.y)/m_intVoltage;
m_intVoltage /= ;
m_intAngle = xAxisGrad;
m_intAngle = (LButton_Double_Down_Point.x - TextAreaWidth)/m_intAngle;
#ifdef _DEBUG
_cprintf("Voltage = %0.2f,Angle = %0.2f\r\n",xAxisGrad,m_intAngle);
#endif
UpdateData(FALSE);
}
} if(Bool_Flag.LButton_Down_Flag)
{
pDC->SelectObject(pBrack);
pDC->MoveTo(Button_Down_Point);
pDC->LineTo(Mouse_Current_Point.x,Button_Down_Point.y); pDC->MoveTo(Mouse_Current_Point.x,Button_Down_Point.y);
pDC->LineTo(Mouse_Current_Point); pDC->MoveTo(Mouse_Current_Point);
pDC->LineTo(Button_Down_Point.x,Mouse_Current_Point.y); pDC->MoveTo(Button_Down_Point.x,Mouse_Current_Point.y);
pDC->LineTo(Button_Down_Point); }
ReleaseDC(pDC);
} void My_Draw::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
Mouse_Current_Point = point; if(Bool_Flag.Draw_Line_Choice)
{
Limit_Min = point.x - ;
Limit_Max = point.x + ;
LButton_Double_Down_Point = point;
} if((Bool_Flag.LButton_Down_Flag)
||(Bool_Flag.LButton_Up_Flag))
Draw(); CStatic::OnMouseMove(nFlags, point);
} void My_Draw::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if((Bool_Flag.LButton_Double_Down_Flag)
&&(point.x >= Limit_Min)
&&(point.x <= Limit_Max))
{
if(Bool_Flag.Draw_Line_Choice)
Bool_Flag.Draw_Line_Choice = FALSE;
else
Bool_Flag.Draw_Line_Choice = TRUE; LButton_Double_Down_Point = point;
}
else
{
if((Bool_Flag.LButton_Down_Flag == FALSE)
&&(Bool_Flag.Draw_Line_Choice == FALSE))
{
Bool_Flag.LButton_Down_Flag = true;
Button_Down_Point = point;
}
}
Draw(); CStatic::OnLButtonDown(nFlags, point);
} void My_Draw::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(Bool_Flag.LButton_Down_Flag)
{
Bool_Flag.LButton_Up_Flag = true;
Bool_Flag.LButton_Down_Flag = FALSE;
Draw();
} CStatic::OnLButtonUp(nFlags, point);
} void My_Draw::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值 LButton_Double_Down_Point = point; Limit_Min = LButton_Double_Down_Point.x - ;
Limit_Max = LButton_Double_Down_Point.x + ; Bool_Flag.LButton_Double_Down_Flag = TRUE;
Draw(); CStatic::OnLButtonDblClk(nFlags, point);
}

程序运行效果图
现在说明一下
1. 新建一个 MFC 应用程序

2. 选择“基于对话框”

3. 添加一个 “Picture 控件”

4. 为控件添加一个变量 my_Graw

5. 将源文件包含进来,并在 My_ClassDlg.h 中包含 #include "My Draw.h"

6. 在 My_ClassDlg.h 头文件中将刚才声明的 Picture 控件变量 CStatic my_Graw ; 改成 My_Draw my_Graw;
7. 在 My_ClassDlg.cpp 文件 void CMy_ClassDlg::OnPaint() 尾部添加 my_Graw.Draw();
8. 编译运行
读者可根据自己的需要在响应的地方改下就好了。
示例下载 http://download.csdn.net/detail/longzhishen/7227255
实例详解:MFC坐标轴实现的更多相关文章
- linux基础-磁盘阵列(RAID)实例详解
磁盘阵列(RAID)实例详解 raid技术分类 软raid技术 硬raid技术 Raid和lvm的区别 为什么选择用raid RAID详解 RAID-0 RAID-1 RAID-5 Raid-10 R ...
- Cocos2d-x 3.X手游开发实例详解
Cocos2d-x 3.X手游开发实例详解(最新最简Cocos2d-x手机游戏开发学习方法,以热门游戏2048.卡牌为例,完整再现手游的开发过程,实例丰富,代码完备,Cocos2d-x作者之一林顺和泰 ...
- JavaScript学习笔记-实例详解-类(二)
实例详解-类(二) //===给Object.prototype添加只读\不可枚举\不可配置的属性objectId(function(){ Object.defineProperty(Object ...
- JavaScript学习笔记-实例详解-类(一)
实例详解-类(一): //每个javascript函数(除了bind())都自动拥有一个prototype对象// 在未添加属性或重写prototype对象之前,它只包含唯一一个不可枚举属性const ...
- Entity Framework实例详解
Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表.然而,有时候,不能也不想遵循这些约定,那就需要重写它们.重写默认约定有两种方式:Data Anno ...
- 免费的HTML5连载来了《HTML5网页开发实例详解》连载(二)
最近新浪.百度.腾讯.京东.大众点评.淘宝等流行的网站都加大了招聘HTML5的力度,HTML5开发人员成了抢手货,本次连载的是由大众点评前端工程师和一淘网前端工程师基情奉献的<HTML5网页开发 ...
- Linux下rz命令使用的实例详解
Linux中rz命令和sz命令都可用于文件传输,而rz命令主要用于文件的上传,下面将通过几个实例来给大家详细介绍下Linux下rz命令的用法,一起来学习下吧. rz命令可以批量上传文件,当然也可上传单 ...
- 实例详解 DB2 排序监控和调优
实例详解 DB2 排序监控和调优http://automationqa.com/forum.php?mod=viewthread&tid=2882&fromuid=2
- 转:【工欲善其事必先利其器】—Entity Framework实例详解
开始本篇文章之前,先说一下Entity Framework 6 Alpha1在NuGet中已可用,原文链接http://blogs.msdn.com/b/adonet/archive/2012/10/ ...
- Linux计划任务Crontab实例详解教程
说明:Crontab是Linux系统中在固定时间执行某一个程序的工具,类似于Windows系统中的任务计划程序 下面通过详细实例来说明在Linux系统中如何使用Crontab 操作系统:CentOS ...
随机推荐
- 设计模式——适配器模式(type-c转3.5mm耳机口)
本文首发于cdream的个人博客,点击获得更好的阅读体验! 欢迎转载,转载请注明出处. 本文简述适配器模式,考虑到java中没有多继承就只写了对象适配器模式,然后例子是怎么用转接口把3.5mm耳机插在 ...
- Freemarker出现NullNumberException异常
Spring Boot项目使用了Freemarker模板引擎. 在ftl文件中使用了一些变量,但是一直出现错误,无法正常渲染页面,反复出现的报错是: freemarker.core.NonNumeri ...
- 你真的了解 Unicode 和 UTF-8 吗?
目录 引言 ASCII 码 什么是 ASCII 码? ASCII 码都包含哪些字符? ASCII 码的局限在哪里? Unicode 什么是 Unicode ? Unicode 的实现方式有几种? Un ...
- 【JavaFx教程】第六部分:统计图
第6部分的主题 创建一个统计图显示生日的分布. 生日统计 在AddressApp中所有人员都有生日.当我们人员庆祝他们生日的时候,如果有一些生日的统计不是会更好. 我们使用柱状图,包含每个月的一个条形 ...
- JDBC、mybatis、hibernate连接数据库
JDBC连接数据库五步骤: 一.加载驱动 Class.forName(“com.mysql.jdbc.Driver”); 二.建立连接 Connection conn = DriverManager. ...
- 关于chrome 插件PageMonitor 安装及使用步骤
首先是安装: 第一步:打开谷歌浏览器的设置界面(如果没有谷歌浏览器需要下载安装下) 然后 点击左侧扩展程序:出现如下图 然后把附件中Page_Monitor_Chrome.crx文件托到扩展程序界面, ...
- ubuntu16.04 linux 编译安装apache2.4.33
下载软件包: wget http://mirror.bit.edu.cn/apache//httpd/httpd-2.4.33.tar.gz wget http://mirrors.tuna.tsin ...
- django 参考
1. 路由系统 https://www.cnblogs.com/maple-shaw/articles/9282718.html 2. 视图 https://www.cnblogs.com/maple ...
- 前端开发面试题-JavaScript(转载)
本文由 本文的原作者markyun 收集总结. 介绍js的基本数据类型. Undefined.Null.Boolean.Number.String. ECMAScript 2015 新增:Symbol ...
- Android 2018最新的三方库
文章出处https://blog.csdn.net/qq_32368129/article/details/78749880 1.MaterialStepperView 它是用Material Des ...