实例详解: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 ...
随机推荐
- Java代码优化笔记
指定类.方法的final修饰符 为类指定final修饰符可以让类不可以被继承,为方法指定final修饰符可以让方法不可以被重写.如果指定了一个类为final,则该类所有的方法都是final的.Java ...
- 什么是Solr
什么是Solr Lucene复习: 1.什么是lucene:全文检索工具包 2.Lucene的工作原理: 索引数据的创建 从原始文件中提取一些可以用来搜索的数据(封装成各种Field),把各field ...
- Java - "JUC线程池" 架构
Java多线程系列--“JUC线程池”01之 线程池架构 概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介 ...
- Java面试题阶段汇总
初级面试题 Java面试题-基础篇一 Java面试题-基础篇二 Java面试题-集合框架篇三 Java面试题-基础篇四 Java面试题-基础篇五 Java面试题-javaweb篇六 Java面试题 ...
- Hadoop在启动时的坑——start-all.sh报错
1.若你用的Linux系统是CentOS的话,这是一个坑: 它会提示你JAVA_HOME找不到,现在去修改文件: .修改hadoop配置文件,手动指定JAVA_HOME环境变量 [${hadoop_h ...
- 获取url地址的参数值
使用频率很高,百度了记录一下 $.getUrlParam = function (name) { var reg = new RegExp("(^|&)" + name + ...
- JS实现选择菜单栏(配合慕课网淘宝搜索框的课程)
以下是关于实现慕课网淘宝搜索框的JS代码,不过只有选择菜单栏(其余比较容易实现). <!doctype html> <html> <head> <!--在IE ...
- Android:Error:Execution failed for task ':app:clean'. > Unable to delete directory
as clean项目之后有时候会报错. 可以找得到目录删掉,然后重启as,但是下次clean可能又会报类似的错误. 解决方法如下: 进入File-Setting-Build,Execution,De ...
- Python笔记(六):推导数据
(一) 准备工作 创建1个文件记录运动员的跑步成绩 james.txt 2-34,3:21,2.34,2.45,3.01,2:01,2:01,3:10,2-22 (二) 要求 在屏幕上输出运动员最 ...
- Problem4-Project Euler
Largest palindrome product A palindromic number reads the same both ways. The largest palindrome m ...