MFC+GDI+绘制出雷达余晖效果

MFC+GDI+绘制出雷达余晖效果

这个水印有点烦
1.首先要画出静态的坐标轴,用双缓冲方法在onpain消息中绘制。绘制方法都比较简单。声明一个内存DC,绘制一个圆形,再把坐标轴画上去。

void CDlg_RadarScanning::OnPaint()
{CPaintDC dc(this); // device context for painting// TODO: 在此处添加消息处理程序代码// 不为绘图消息调用 CDialogEx::OnPaint()GetClientRect(&WinRect);CenterPoint.X = WinRect.Height()/2.0;CenterPoint.Y = CenterPoint.X;ellipseRect2 = Rect(2,2,WinRect.Height()-4,WinRect.Height()-4); //外切矩形区域BitRect.Equals(ellipseRect2);pDC = this->GetDC();pDC->FillSolidRect(0,0,WinRect.right,WinRect.bottom,RGB(0,0,0));//随后建立与屏幕显示兼容的内存显示设备MemDC.DeleteDC();MemDC.CreateCompatibleDC(pDC);MemBitmap.DeleteObject();MemBitmap.CreateCompatibleBitmap(pDC,WinRect.Width(),WinRect.Height());//将位图选入到内存显示设备中//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);Graphics gp(MemDC.m_hDC);gp.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);//抗锯齿 REAL startAngle = 0.0f; // 设置起点角度REAL sweepAngle = 360.0f; // 设置旋转角度Brush* brush = NULL;brush = new SolidBrush(Color::Green);gp.FillEllipse(brush,ellipseRect2.Height/2,ellipseRect2.Height/2,5,5);//圆心// 	PointF* StarPoint = new PointF(1,ellipseRect2.Height/2);
// 	PointF* EndPoint= new PointF(ellipseRect2.Width,ellipseRect2.Height/2);PointF StarPoint(1,ellipseRect2.Height/2);PointF EndPoint(ellipseRect2.Width,ellipseRect2.Height/2+2);gp.DrawLine(&Pen(Color::Green,2),*(&StarPoint),*(&EndPoint));//水平坐标轴StarPoint.X = ellipseRect2.Width/2+2;EndPoint.X = StarPoint.X;StarPoint.Y = 1;EndPoint.Y = ellipseRect2.Height;gp.DrawLine(&Pen(Color::Green,2),*(&StarPoint),*(&EndPoint));//竖直坐标轴int Gap =ellipseRect2.Height/10+2;//刻度间隙int count = 5;for (int i=0;i<count;i++)//同心圆{gp.DrawArc(&Pen(Color::Green,2),ellipseRect2,startAngle,sweepAngle);//画圆ellipseRect2.X = ellipseRect2.X +Gap;ellipseRect2.Y = ellipseRect2.Y +Gap;ellipseRect2.Width = ellipseRect2.Width - 2*Gap;ellipseRect2.Height = ellipseRect2.Height-2*Gap;}FontFamily fontFamily(L"微软雅黑"); Gdiplus::Font myFont(&fontFamily, 10, FontStyleRegular, UnitPoint); //第二个是字体大小SolidBrush blackBrush(Color(255, 215, 0));  //半透明+文字RGB颜色int iOverrange = WinRect.Height()/10;CString strTemp;StringFormat format;                         format.SetAlignment(StringAlignmentNear);    //文本排列方式,即在对应位置居中、靠左、靠右for (int i=5;i>=0;i--)//标明刻度{strTemp.Format("%d",i*2);WCHAR* wchar= strTemp.AllocSysString();	//wcscpy_s(string, CT2CW(str));              //如果使用MFC中的CString,需要这样转换成WCHARPointF school_site((REAL)(5-i)*iOverrange, (REAL)WinRect.Height()/2);//文字放置的像素坐标gp.DrawString(wchar, wcslen(wchar), &myFont, school_site, &format, &blackBrush );//把string绘制到图上 }strTemp.Format("刻度/KM");WCHAR* wchar1= strTemp.AllocSysString();PointF school_site1((REAL)2, (REAL)2);//文字放置的像素坐标gp.DrawString(wchar1, wcslen(wchar1), &myFont, school_site1, &format, &blackBrush );////pDC->TransparentBlt(0,0,WinRect.Height()-1,WinRect.Height()-1,&MemDC,0,0,ellipseRect2.Width,ellipseRect2.Height,TRANSPARENT);pDC->BitBlt(0,0,WinRect.Height()-1,WinRect.Height()-1,&MemDC,0,0,SRCCOPY);m_iMetersPerPx = 10000.0/(WinRect.Height()/2.0);//10KM与图像刻度比例MemDC.SelectObject(pOldBit);gp.ReleaseHDC(MemDC.m_hDC);}

2.其次是绘制一个渐变的扇形区域,原点和角度要定好,而且要求是能够旋转的扇形。从简单的旋转开始就是模仿秒针旋转。一开始我也是只绘制一根线旋转。图形旋转时会留有上一次的图形,所以我们还需要把上一次角度的图形抹掉,重新定位新的角度的图形。我选择的办法是开启一个定时器,用之前画好的内存DC不断地去覆盖上一张图,在覆盖完成后再在上面绘制新角度的旋转图形即可。图形旋转我是用矩阵旋转。

			//该代码写在定时器即可static double fPi = 4.0*atan(1.0);//180度double fAngle = fPi/2,fDAngle = 2.0*fPi/60.0;//360度分成60份//转盘看为时钟盘,摆针为秒针SYSTEMTIME tmNow;GetLocalTime(&tmNow);//s为中心点,e为变化后的点,两点连起来形成摆针//Pen sPen(Color(255, 0, 0), 3); CPen mypen(PS_SOLID,2,RGB(255,255,255));CPen* pOldPen;CDC* MyDC = this->GetDC();pOldPen=MyDC->SelectObject(&mypen);Point s(CenterPoint.X,CenterPoint.Y), e; double fTime = tmNow.wSecond + tmNow.wMilliseconds/1000.0 + 0;//以系统时间为当前比例//double fTime =30;double fAng = fPi/2.0 - fTime * (2.0*fPi) /30.0;//360度分的刻度影响摆针旋转速度,分得越少越快e.X = (int)(CenterPoint.X + (WinRect.Height()/2.0) * cos(fAng)); e.Y = (int)(CenterPoint.Y -  (WinRect.Height()/2.0) * sin(fAng));MyDC->BitBlt(0,0,WinRect.Height(),WinRect.Height(),&MemDC,0,0,SRCCOPY);//将内存位图贴上再划线可将上一次图形覆盖//旋转扇形static int angl = 10;//每次旋转角度Graphics graphics(MyDC->m_hDC);graphics.SetSmoothingMode(SmoothingModeAntiAlias);//矩阵旋转Matrix matrix;matrix.Translate(CenterPoint.X, CenterPoint.Y, MatrixOrderAppend);//matrix.Scale(2, 2, MatrixOrderAppend);matrix.RotateAt(angl, PointF(CenterPoint.X, CenterPoint.Y), MatrixOrderAppend);matrix.Translate(-CenterPoint.X, -CenterPoint.Y);graphics.SetTransform(&matrix); LinearGradientBrush linGrBrush(Point(0,0),Point(120,120),Color(0,255,255,255),Color(255,0,255,100));//渐变画刷//graphics.DrawPie(&Pen(Color::Green,2),(int)0, (int)0,WinRect.Height(),WinRect.Height(),0,60);graphics.FillPie(&linGrBrush,(int)0, (int)0,WinRect.Height(),WinRect.Height(),0,60);//绘制渐变扇形//graphics.FillRectangle(&linGrBrush,(int)CenterPoint.X,(int)CenterPoint.Y, 50, WinRect.Height()/2);angl++;//以下均为旋转秒针
//			graphics.DrawLine(&Pen(Color::White,2),(int)CenterPoint.X,(int)CenterPoint.Y,(int)e.X,(int)e.Y);
// 			MyDC->MoveTo(CenterPoint.X,CenterPoint.Y);
// 			MyDC->LineTo(e.X,e.Y);MyDC->SelectObject(pOldPen);ReleaseDC(MyDC);pOldPen->DeleteObject();mypen.DeleteObject();

3.下面是添加目标。新建一个透明的对话框叠加到当前雷达扫描的对话框,新对话框重绘透明的按钮类,再贴图到按钮上,还要添加按钮的点击响应消息。然后在雷达扫描窗口上声明新窗口的对象Create窗口。至于每一个按钮都是对应一个封装的结构体,里面含有距离、高度和按钮句柄等信息,不断地调用movewindow即可实现移动。

//.h
struct FlyBtInfo
{double iDistance;double iHeight;CCDrawButtonTM flyBt;//句柄BOOL bShow;BOOL bSelected;
};
CDlg_DrawFly *m_DrawFlyDlg;
FlyBtInfo m_DrawFly[3];//.cpp
if(m_DrawFlyDlg==NULL){m_DrawFlyDlg = new CDlg_DrawFly(this);m_DrawFlyDlg->Create(IDD_DLG_DRAWFLY,this);m_DrawFlyDlg->ShowWindow(SW_SHOW);}memcpy(&m_DrawFly[0].flyBt,&m_DrawFlyDlg->m_OneFlyBt,sizeof(CCDrawButton));m_DrawFly[0].bShow=FALSE;m_DrawFly[0].bSelected =FALSE;memcpy(&m_DrawFly[1].flyBt,&m_DrawFlyDlg->m_TwoFlyBt,sizeof(CCDrawButton));m_DrawFly[1].bShow=FALSE;m_DrawFly[1].bSelected =FALSE;memcpy(&m_DrawFly[2].flyBt,&m_DrawFlyDlg->m_ThreeFlyBt,sizeof(CCDrawButton));m_DrawFly[2].bShow=FALSE;m_DrawFly[2].bSelected =FALSE;//第一个定时器
//飞机1static int x1 =WinRect.Height()/2.0*(1-sin(3.14/4));if (x1<(WinRect.Height()/2)){m_DrawFly[0].flyBt.MoveWindow(x1-10,x1-10,25,25);//m_DrawFly[0].flyBt.Invalidate();m_DrawFly[0].flyBt.ShowWindow(SW_SHOW);//根据刻度算出距离,高度这里为十分之一距离double a =WinRect.Height()/2-x1+10;m_DrawFly[0].iDistance = sqrt(pow(a,2)*2)*m_iMetersPerPx;m_DrawFly[0].iHeight = m_DrawFly[0].iDistance/10;if (m_DrawFly[0].bSelected){UpdateFlyDataToList(0);}x1 ++;} else{x1 =WinRect.Height()/2.0*(1-sin(3.14/4));}//飞机2static int x2 = WinRect.Height()/2-5;static int y2 =WinRect.Height()/2-5;int x21 = WinRect.Height()/2*(1+sin(3.14/4));int y21 = WinRect.Height()/2*(1-sin(3.14/4));if (x2<x21 || y2>y21){m_DrawFly[1].flyBt.MoveWindow(x2,y2,25,25);//m_DrawFly[1].flyBt.Invalidate();m_DrawFly[1].flyBt.ShowWindow(SW_SHOW);double a1 = pow(WinRect.Height()/2.0-x2,2);double a2 = pow(WinRect.Height()/2.0-y2,2);m_DrawFly[1].iDistance = sqrt(a1+a2)*m_iMetersPerPx;m_DrawFly[1].iHeight = m_DrawFly[1].iDistance/10;if (m_DrawFly[1].bSelected){UpdateFlyDataToList(1);}x2 ++;y2 --;}else{x2 = WinRect.Height()/2-5;y2 =WinRect.Height()/2-5;}

下面是用到的几个方法:

//更新列表数据
void CDlg_RadarScanning::UpdateFlyDataToList(int iTranceBatch)
{int BatchTemp;int count = m_FlydataList.GetItemCount();for (int i =0;i<count;i++){BatchTemp = atoi(m_FlydataList.GetItemText(i,0));if (BatchTemp == iTranceBatch){CString strDistance;strDistance.Format("%.2f",m_DrawFly[iTranceBatch].iDistance);m_FlydataList.SetItemText(i,1,strDistance);strDistance.Format("%.2f",m_DrawFly[iTranceBatch].iHeight);m_FlydataList.SetItemText(i,2,strDistance);}}
}
//点击按钮时切换位图
void CDlg_RadarScanning::ChangeFlyColor(int iTranceBatch)
{switch(iTranceBatch){case 0:m_DrawFlyDlg->m_OneFlyBt.UpdateBtn("res\\airport.png","res\\airport.png","res\\airport.png","res\\airport.png","");m_DrawFlyDlg->m_OneFlyBt.Invalidate();m_DrawFlyDlg->m_TwoFlyBt.UpdateBtn("res\\airport4.png","res\\airport4.png","res\\airport4.png","res\\airport4.png","");m_DrawFlyDlg->m_TwoFlyBt.Invalidate();break;case 1:m_DrawFlyDlg->m_OneFlyBt.UpdateBtn("res\\airport2.png","res\\airport2.png","res\\airport2.png","res\\airport2.png","");m_DrawFlyDlg->m_OneFlyBt.Invalidate();m_DrawFlyDlg->m_TwoFlyBt.UpdateBtn("res\\airport5.png","res\\airport5.png","res\\airport5.png","res\\airport5.png","");m_DrawFlyDlg->m_TwoFlyBt.Invalidate();break;}
}//按钮点击消息,通过发送消息给主窗口类
void CDlg_DrawFly::OnBnClickedOnedrawbutton()
{m_Parent->SendMessage(WM_DRAWFLY_BT_MSG,IDC_ONEDRAWBUTTON,0);// TODO: 在此添加控件通知处理程序代码
}
void CDlg_DrawFly::OnBnClickedTwodrawbutton()
{// TODO: 在此添加控件通知处理程序代码m_Parent->SendMessage(WM_DRAWFLY_BT_MSG,IDC_TWODRAWBUTTON,0);
}
void CDlg_DrawFly::OnBnClickedThreedrawbutton()
{// TODO: 在此添加控件通知处理程序代码m_Parent->SendMessage(WM_DRAWFLY_BT_MSG,IDC_THREEDRAWBUTTON,0);
}//这个方法用于响应按钮点击事件
LRESULT (主窗口类)::OnDrawFlyBTDepose(WPARAM wParam, LPARAM lParam)
{switch(wParam){case IDC_ONEDRAWBUTTON:{m_RadarScanningDlg->ChangeFlyColor(0);m_RadarScanningDlg->m_CurSelectAim =0;m_RadarScanningDlg->m_DrawFly[0].bSelected =TRUE;CString strTemp;strTemp.Format("00 跟踪");m_RadarScanningDlg->m_FlydataList.SetItemText(0,0,strTemp);m_RadarScanningDlg->m_FlydataList.SetItemText(1,0,"01");}//SelectRadarTrackBatch(0);break;case IDC_TWODRAWBUTTON:{m_RadarScanningDlg->ChangeFlyColor(1);m_RadarScanningDlg->m_CurSelectAim =1;m_RadarScanningDlg->m_DrawFly[1].bSelected =TRUE;CString strTemp;strTemp.Format("01 跟踪");m_RadarScanningDlg->m_FlydataList.SetItemText(1,0,strTemp);m_RadarScanningDlg->m_FlydataList.SetItemText(0,0,"00");}//SelectRadarTrackBatch(1);break; }return 1;
}

总结:
使用MFC确实不好做,我查了一下很多都是QT。关键是GDI+绘图和矩阵旋转比较难。虽然这个是我自己写的,但是工程是公司的,我不好公开全部代码,有什么问题可以问我。

以下是提供可学习

1.GDI+学习及代码总结之------画线、区域填充、写字
https://blog.csdn.net/harvic880925/article/details/9023329
2.GDI+绘制极坐标图、雷达图
https://blog.csdn.net/iteye_15968/article/details/82334555
3.GDI+旋转图片的几种方法
https://blog.csdn.net/fyl_077/article/details/44456213

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/267987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如果你们都忘记了鼓励原创,那,我们来 - 2017年度原创IT博主全网评选

2017最后一个月&#xff0c;当全世界都是各种年度总结&#xff0c;奖励的时候&#xff0c;IT博客圈似乎已经被人遗忘。而&#xff0c;那些还在半夜&#xff0c;加班写博客&#xff0c;分享自己经验的热心程序猿们&#xff0c;依然&#xff0c;吭哧吭哧的写着&#xff0c;为了几…

BZOJ 2599

http://www.lydsy.com/JudgeOnline/problem.php?id2599 就是开一个数组t,t[i]表示权值为i的路径最少边数 点分治&#xff0c;找到树的重心分成若干子树后&#xff0c; 得出一棵子树的所有点到根的路径长度x&#xff0c;到根有a条边&#xff0c;用t[k-x]a更新答案&#xff0c; …

android用户界面-菜单

创建菜单 Creating Menus Android提供了三种基础菜单类型&#xff1a; 选项菜单Options Menu 这是一个活动的主菜单。通过按下设备菜单键来显示它。选项菜单包含两组菜单项&#xff1a; 图标菜单Icon Menu 这个是当用户按下菜单键时最初出现屏幕下方的item集合。它支持最多…

QT打开文件

https://www.cnblogs.com/ZY-Dream/p/10571490.html

12.5

持续关注一下足球经理游戏 转载于:https://www.cnblogs.com/dandansang/p/7980132.html

流浪宠物救助网站前端页面_全国爱心人士齐聚鞍山 救助流浪猫狗

入冬之后&#xff0c;流浪猫狗的“吃饭问题”成了众多爱心人士的牵挂。12日上午&#xff0c;来自全国各地的20余位爱心人士&#xff0c;来到宁远镇张忠堡村一流浪猫狗救助站&#xff0c;将价值7000余元的宠物用品捐赠给救助站。当日早上8时许&#xff0c;爱心人士们特意到铁西八…

问题解决

问题解决了&#xff0c;把 #include <string.h> 改写成 #include <string> 就行了 #include <iostream> #include <string> #include "tinystr.h" #include "tinyxml.h" #include <vector> #include "Text.h" #in…

QT 线程之间通信

1.先说QT线程。都知道QT线程有两种使用方式&#xff0c;一种是继承QThread重写run()&#xff0c;一种是继承QObject然后再MovetoThread()到线程下。我也是刚学QT&#xff0c;之前一直做MFC。现在有个问题&#xff0c;我想要创建的是单次运行的线程&#xff0c;就是处理完后就自…

微信小程序 开发过程中遇到的坑(一)

21241.我们使用app.json文件来对微信小程序进行全局配置&#xff0c;决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 的时候在pages中写注释的时候回报错。 例如&#xff1a; {"pages":[//这是首页面"pages/welcome/welcome"] } 此时就会报错…

java 创建日程到期提醒_日程管理工具—Things 3

Mac上最好用的日程管理工具是哪个&#xff1f;Things 3 for Mac是首选&#xff0c;Things3 Mac全新的设计&#xff0c;外观简洁、大气&#xff0c;功能也是非常强大的&#xff0c;让你用一种优雅而直观的方式来管理个人事务&#xff0c;无论在生活还是工作中&#xff0c;都能取…

数据库优化小结

WHERE条件的优化&#xff1a;1、IN&#xff1a;至少多一个转换的过程&#xff08;先试图转成多个表的连接&#xff0c;如果转换不成功先执行IN里面的子查询&#xff0c;再查询外层记录&#xff09;2、NOTIN&#xff1a;不能应用表索引&#xff0c;可用NOT EXISTS替换的3、<&…

使用VS制作MFC、libmysql.dll出现计算机缺少msvcr120.dll和msvcp120.dll问题

自己应客户要求做了一个数据库的查询工具&#xff0c;结果在客户电脑那边运行出现了计算机缺少msvcr120.dll和msvcp120.dll问题&#xff0c;一开始以为是MFC程序自身有动态链接&#xff0c;结果才发现是libmysql.dll本身依赖于msvcr120.dll和msvcp120.dll&#xff0c;这两个库对…

python 流程控制if判断

简单看下if判断在python的基本用法 # gyf28 定义变量gyf # if gyf > 20: 判断 gyf 是不是〉20# print(你真年轻) 简单实现了 if判断的用法 下面我们再来做一个例子 if判断 gyf是不是〉18 并且〈 22 如果是 则执行打印的任务 输出 表白 如果条件不成立输入打印 阿姨…

python同步oracle_Python cx_Oracle 7引入苏打文档存储

在线QQ客服&#xff1a;1922638专业的SQL Server、MySQL数据库同步软件cx _甲骨文7 .0是非常受欢迎的蟒蛇甲骨文数据库接口,现在是PyPI上的产品。cx _甲骨文是一个开源包,它涵盖了大蟒数据库应用编程接口规范,并添加了许多支持神谕高级功能的内容。安东尼 图宁加刚刚发布了cx _…

总结2010展望2011

总结2010 展望2011转载于:https://www.cnblogs.com/zhouxiuquan/archive/2011/01/28/1947269.html

XP下使用FFMPEG(API和exe)遇到的问题和解决方法。

XP下使用FFMPEG&#xff08;API和exe&#xff09;遇到的问题和解决方法。1、需求背景2、遇到的问题3、解决方法下载链接1、需求背景 因为最近接到项目上的一个需求&#xff0c;就是在MP4&#xff08;H264编码&#xff09;文件里叠加指定字符&#xff0c;于是就想到了使用FFMPE…

钢材规格解读的软件_万维软件ERP五金建材行业解决方案

一、五金建材行业的特征&#xff1a;1、企业的规对较小&#xff1a;身为老板却“身兼多职”&#xff0c;采购、销售、发货、出纳啥都做&#xff1b;2、业务非常多样&#xff1a;虽然这类企业规模小&#xff0c;但也涉及到批发、零售、工程(局部工程)、家装等经营型态&#xff0…

MSDE 认证方式

1. 停止 MSSQLSERVER 以及所有其他相关服务&#xff08;如 SQLSERVERAgent 2. 打开注册表编辑器。要打开注册表编辑器&#xff0c;请依次单击开始和运行&#xff0c;然后键入&#xff1a;“regedt32”3. 找到以下两个子项之一&#xff08;取决于 MSDE 是作为默认 MSDE 实例安装…

duilib学习

记录duilib自学过程。 最近年底公司也没啥事情&#xff0c;自己就想着上网看看duilib怎么制作界面&#xff0c;因为之前想学习一直没时间&#xff0c;现在来看看。 其实学习的就好办法就是看demo&#xff0c;关于duilib网上的学习教程并不多&#xff0c;自己跟着demo敲一遍代…

2017.12.1T19_B2_2zuoye

package com.whxiong.work01; import java.util.Scanner; public class Calculator { Scanner input new Scanner(System.in); public void show() { char Calculator; double num 0; double num1 0; System.out.println("请输入第一个整数&#xff1a;"); …