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;为了几…

android用户界面-菜单

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

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

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

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

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

duilib学习

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

记:ubuntu下交叉编译arm的链接库

以第三方库libjpeg为例&#xff0c;编译所需要的三步&#xff1a; 1、配置./configure脚本参数&#xff0c; ./configure --prefix/home/huanghaitao/Winshare/jpeg-9c/libjpeg CCarm-linux-gnueabihf-gcc --hostarm-linux --enable-shared --enable-static–prefix&#xff0…

flash 绘图API:绘制弧线

把之前没有记录的笔记都记录一下&#xff0c;顺便方便日后查询。绘制弧线&#xff0c;对于一些制作课件的人来讲会有一些用处的。绘制弧线采用的基本思路是采用描点的方法实现。从一个开始角度&#xff0c;到另一个角度结束&#xff0c;在这个角度区间里面进行描点连线。 【A&a…

关于SDL SDL_CreateWindowFrom和SDL_DestroyWindow第二次后无法将视频显示出来。

最近自己用QT搞一个监控平台的程序UI&#xff0c;然后后台一些视频处理是使用FFMPEG和SDL来做的。 在关闭播放窗口SDL_DestroyWindow后&#xff0c;再次去显示视频就会发现显示不出来。代码如下 int SDLPlayer::SDLPlay() {SDL_Window *sdlScreen{ NULL };//窗口SDL_Renderer*…

vos限制客户呼出时间

问题&#xff1a; 公司希望自己的卡线晚上 21&#xff1a;00-24&#xff1a;00 早上00&#xff1a;00-7&#xff1a;30不能打出电话&#xff0c;以防遭投拆&#xff0c; 那么如何设置&#xff1f; 方法&#xff1a; 找到客户使用的落地网关&#xff0c; 落地网关——补充设置…

QT-监视平台

空余时间学习QT的UI&#xff0c;做了一个监视平台&#xff0c;直接上图。 页面1&#xff1a;视频监控 页面2&#xff1a;视频回放 页面3&#xff1a;系统设置 未完成。。。。。。。。 做的不好的地方请大家指正&#xff0c;项目现在还在开发阶段&#xff0c;仅供学习参考…

Orchard架构介绍

在如何使用Orchard搭建敏捷个人的网站&#xff08;2&#xff09;中 介绍了如何使用Orchard&#xff0c;但对于我们来说&#xff0c;更重要的是学习Orchard是如何架构的&#xff0c;如果我们自己编写一个类似应用该如何做。今天有空再次看看 Orchard的其它内容&#xff0c;本篇介…

【服务器】一次对Close_Wait 状态故障的排查经历

最近接连听说一台线上服务器总是不响应客户端请求。 登录服务器后查询iis状态&#xff0c;发现应用程序池状态变为已停止。 按经验想&#xff0c;重启后应该就ok&#xff0c;第一次遇到也确实起了作用&#xff0c;当时完全没在意&#xff0c;以为是其他人无意把服务关闭了而已。…

听力阈值计算_中耳功能分析:临床听力测试的重要手段!

点击甘峰听力关注我们中耳功能测试是临床听力学测试中一个重要部分&#xff0c;和常规的气、骨导纯音测试不一样&#xff0c;中耳功能测试从测试的内容看&#xff0c;主要有鼓室声导抗测试、声順值测试、镫骨肌反射阈值测试、咽鼓管功能测试等。从测试的原理看&#xff0c;现代…

go json 自定义_Go语言Echo Web框架9-日志

上一节:Go语言Echo Web框架8-JWT 这一节介绍日志echo自带的日志中间件记录有关每个HTTP请求的信息日志日志中间件用法e.Use(middleware.Logger())样本输出{ "time":"2020-09-13T21:58:07.372015644-08:00", "remote_ip":"::1", &…

cad文字递增快捷键_十年经验总结,100个CAD快捷键。

CAD绘图快捷键命令&#xff1a;1. 圆 > C2. 点 > PO3. 直线 > L4. 圆弧 > A5. 椭圆 > EL6. 表格 > TB7. 矩形 > REC8. 面域 > REG9. 创建块 > B10. 插入块 > I11. 多段线 > PL12. 构造线 > XL13. 图案填充 > H14. 样条曲线 > SPL15.…

实验5: IOS的升级与恢复

实验5: IOS的升级与恢复 实验目的通过本实验可以掌握 1) 掌握IOS 正常的情况下升级IOS2) IOS 丢失的情况下使用TFTP恢复IOS3) IOS 丢失的情况下使用Xmodem恢复IOS 拓扑结构 实验步骤n IOS 正常的情况下升级IOS (TFTP)Router#conf t //进…

MYSQL:基础——触发器

MYSQL基础——触发器 引入触发器 什么是触发器 如果你想要某条语句(或某些语句)在事件发生时自动执行。比如&#xff1a; 每当订购一个产品时&#xff0c;都从库存数量中减去订购的数量&#xff1b;无论何时删除一行&#xff0c;都在某个存档表中保留一个副本。就需要用到触发器…

双线macd指标参数最佳设置_常用指标知多少(二)

均线日期的选择种类有很多&#xff0c;一般行情软件常用的均线日期是5日、10日、20日、30日和60日&#xff0c;一般也会默认是这些日期&#xff0c;也有的加上了长线的120日和250日&#xff0c;很好理解&#xff0c;因为每周交易日是5天&#xff0c;所以以倍数做比较。使用海龟…