c++采用gdi+绘制雷达图纯api 非mfc

在这里插入图片描述
2020年11月24日晚上焦灼的我,啊啊啊啊,最近类的一批,放个图解压一下,如果觉得不错的我可以更新以下这个是怎么绘制的,暂时仅仅用来玩,数据随机生成的。

自控,永远滴神!呜呜呜
这是程序半成品的源码,可以下载玩玩:
链接:https://pan.baidu.com/s/1sNlB59R3pZAVCquDrAnYJw
提取码:by3b
复制这段内容后打开百度网盘手机App,操作更方便哦

///
2020年11月25日考完自控后五味杂陈的我,正经代码说明:
我感觉这个最难的肯定是那个余晖效果怎么做对吧,其实用的是gdi+的渐变画刷,渐变画刷有四个参数,我来给大家说明一下。为了便于说明,我就直接在代码里面说明了。

	//这里很简单,创建一个graphic对象,通过指定控件的句柄
	Graphics gGraphics(form1.Control(ID_picMain).hWnd());//这里我这种写法用的是我们老师的一个通用模块,可以获得对应ID名称的控件的句柄
	RECT rc;
	GetWindowRect(form1.Control(ID_picMain).hWnd(),&rc);
	Point center(int(0.5 * 300), int(0.5 * 300));	//求得并保存这个控件的中间位置,便于移动坐标,具体使用后面在说
	int i;
	const int iDiff = 18;	//表示的是绘制的雷达图的圆的间隔
	
	//这里用的是双缓冲的方式绘制的,所以新创建一个画布,首先在这个上面绘制内容,然后拷贝到对应控件的对象上面显示
	Bitmap bmpBuffer(300, 300);		//大小300*300的画布
	//通过画布创建一个graphic对象,后面用于画图,这里很简单
	Graphics buffer(&bmpBuffer);

	//全黑背景,首先创建画刷
	m_gdiPlus.GetBrush()->SetColor(Color::Black);	//这句代码,你可以自己创建,我这个是自己写的一个类,所以写法不太一样
	/*自己创建画刷的代码:(后面的画笔什么的自己写吧,我不多写注释介绍怎么创建了)
	SolidBrush sBrush(Color::Black);
	*/
	buffer.FillRectangle(m_gdiPlus, 0, 0, rc.right - rc.left, rc.bottom - rc.top);		//填充矩形区域为黑色
	
	
	//至于坐标面的东西,看代码下面的解释,此处不解释了
	//一定注意,下面坐标都是在转换之后的坐标系绘制的
	buffer.ResetTransform(); //重置坐标面
	buffer.TranslateTransform((REAL)center.X, (REAL)center.Y);	//平移变换,将坐标原点平移至客户区中心
	buffer.RotateTransform(m_fAngel);

	//绘制基础的坐标圆,绘制10个圈圈表示距离
	m_gdiPlus.GetPen()->SetColor(Color::Green);
	m_gdiPlus.GetPen()->SetWidth(2);
	for (i=0;i<10;i++)
	{
		buffer.DrawEllipse(m_gdiPlus, -i * iDiff, -i * iDiff, 2*i * iDiff, 2*i * iDiff);
	}

	//渐变画刷的使用,具体介绍看代码下面的说明
	//绘制指针的 pie
	buffer.RotateTransform(-60);
	LinearGradientBrush linGrBrush(Point(0, 150), Point(0, 0), Color(255, 0, 255, 0), Color(0, 0, 100, 0));//渐变画刷
	buffer.FillPie(&linGrBrush, -9*iDiff, -9 * iDiff, 2*9 * iDiff, 2*9 * iDiff, 0, 60);	//绘制渐变扇形
	buffer.ResetTransform(); //重置坐标面
	buffer.TranslateTransform((REAL)center.X, (REAL)center.Y);	//平移变换,将坐标原点平移至客户区中心
	
	//
	//绘制对应的直线坐标内容和提示方向文本
	//buffer.ResetTransform();			//重置坐标面
	buffer.DrawLine(m_gdiPlus, -9 * iDiff, 0, 9 * iDiff, 0);
	buffer.DrawLine(m_gdiPlus, 0, -9 * iDiff, 0, 9 * iDiff);
	m_gdiPlus.GetBrush()->SetColor(Color::Green);
	PointF mpoint0(0, -8 * iDiff);
	buffer.DrawString(TEXT("N"), -1, m_gdiPlus, mpoint0, (Brush*)m_gdiPlus);
	PointF mpoint1(-8 * iDiff, 0);
	buffer.DrawString(TEXT("W"), -1, m_gdiPlus, mpoint1, (Brush*)m_gdiPlus);
	PointF mpoint2(8 * iDiff, 0);
	buffer.DrawString(TEXT("E"), -1, m_gdiPlus, mpoint2, (Brush*)m_gdiPlus);
	PointF mpoint3(0, 8 * iDiff);
	buffer.DrawString(TEXT("S"), -1, m_gdiPlus, mpoint3, (Brush*)m_gdiPlus);
	
	//绘制点实现方式下面说明:
	//绘制对应的点的内容
	static bool fa = true;
	for (i=0;i<10;i++)
	{
		if (m_RadaData[i].iFrameNum != -1)
		{
			m_gdiPlus.GetBrush()->SetColor(Color((50-m_RadaData[i].iFrameNum) / 50.0 * 250, 0, 255, 0));
			//求得对应点的位置,然后以该点为中心,绘制一个小点代表目标
			buffer.FillEllipse(m_gdiPlus,
				m_RadaData[i].iLen * cos(m_RadaData[i].fAngle / 180 * 3.14) - 6,
				m_RadaData[i].iLen * sin(m_RadaData[i].fAngle / 180 * 3.14) - 6,
				12, 12);
			//此处主要是为了延迟它的变化频率变慢一点,否则点消失的太快效果不好
			fa = !fa;
			if (fa)	m_RadaData[i].iFrameNum++;
			if (m_RadaData[i].iFrameNum >= 50)
			{
				m_RadaData[i].iFrameNum = -1;
				m_RadaData[i].fAngle = rand() % 360;
				m_RadaData[i].iLen = rand() % 100 + 50;
			}
				
		}
	}
	//这里就是其他操作了,可有可无的
	buffer.ResetTransform(); //重置坐标面
	buffer.SetCompositingQuality(CompositingQualityHighQuality);
	//双缓冲的内容重新绘制到控件上面
	m_gdiPlus.GetGraphics()->DrawImage(&bmpBuffer, 100, 0, 300, 300);

坐标问题

1.平移变换
buffer.TranslateTransform((REAL)center.X, (REAL)center.Y);
2.旋转变换
buffer.RotateTransform(m_fAngel); //角度制,180°这么类似的用
为了更好理解直接放图了
在这里插入图片描述

额,应该挺好理解的,不多说。

渐变画刷用法

LinearGradientBrush linGrBrush(
Point(0, 150), Point(0, 0),
Color(255, 0, 255, 0), Color(0, 0, 100, 0));//渐变画刷
其中Color(255,0,0,0);第一个东西是A代表的是透明度,如果A为0,代表刷子刷上去的东西就相当于是只有0被刷上去了,所以就跟没刷上去一样,255是完全不透明。实现方式见下图:
在这里插入图片描述
然后刚好可以实现那种波纹的效果是吧,这个图感觉手画的,能够比较清晰的显示内容,有点丑,不要介意,哈哈哈哈哈。(对了,上面不是又转了-60°是吧,因为,我这么绘制是不是你就发现这个扇形前面是从60°出发的,看起来就不太好看,所以又逆时针旋转了60°)

周期性的显示和消失的效果实现

看编程能力,不管会不会,能用结构体枚举绝对不写普通的变量,是吧,结构体一写,一看就是挺有想法的,有经验的,说白了,我觉得唬人可以,哈哈哈哈。不过另外,用结构体便于数据的维护和修改,写多了就知道了。

//结构体用来保存雷达传入的参数的内容,一个是位置信息,一个是对应的显示的帧数信息
struct SRadaData 
{
	float fAngle;			//角度
	int iLen;				//长度
	int iFrameNum = -1;		//对应的显示的帧数,为0表示启动,否则表示暂时不可用状态
};

有个定时器,然后会自动不断的刷新雷达旋转的角度,实现动态的效果,这个结构体重要的是第三个参数,我想的是,用数组存储雷达的目标点,然后如果第三个数为-1,代表该点现在不可用,就每次绘制不要显示它,如果发现我扫到了这个点,我就给它置零,表示发现你了,开始绘制这个点吧,这里点渐渐消失是在绘制的时候每次这个数值加上1,这不就可以知道这个点到底是从被发现到现在绘制了几次了,给它对应的透明度,如果超出一定此处就把这个参数设置为-1,表示这个点不可用了,给它一个随机地址,然后重复该过程就实现了该过程。是不是很奇妙呀。

	//这里的代码写到定时器的回调函数里面,每次都执行这个内容,定时器如果不太懂的话,另外再说吧,这篇不讲解太多这个东西
	
	m_fAngel+=3;	//控制雷达不断的旋转
	if (m_fAngel>=360)
	{
		m_fAngel = 0;
	}
	//此处判断对应的雷达的角度是否过去了对应的角度的信息
	int i;
	for (i=0;i<10;i++)
	{
		if (abs(m_fAngel - m_RadaData[i].fAngle) < 3)	//求的是绝对值
		{
			m_RadaData[i].iFrameNum = 0;
		}
	}
	
	m_gdiMain.InvalidateAll();	//此处擦除内容,发送WM_PAINT消息让控件重新绘制

暂时写这么多吧,有什么其他的疑问我再更新更新吧,觉得不错的给个赞,/偷瞄,我也知道到底好不好,可以大家一起改正也行,呲牙。

  • 12
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值