DevC++ easyx实现悬浮窗放入网格,与在函数分离过程中遇到的BUG下理解 函数的作用时域 以及 初始化与复位的关系。

2023-12-26 13:26:14

这次就着上上上篇的悬浮窗代码DevC++ easyx实现图片拖动,一种悬浮窗实现原理与完整代码-CSDN博客

继续实现效果。

基本背景是搓出来图片拖动了,然后想把图片暂存到另一块。再细说背景的背景就是之前提到Unity复刻瓦片地图,想着整合一个铅笔绘制功能,就是绘制瓦片和瓦片粘贴都在同一个程序里运行。正是这一系列文案所追溯的故事——做一个绘图板,连同绘图,贴片。当时实现了图片缩小,然后要把这个缩小的图片的数据放到网格里面。这个网格作为备选的贴片。这就是文案所去描述的故事,只不过现在回想起来,发现以前推动代码翻新过程中,有了比较有意思的意识到矛盾的新情况。

这次直接上最终代码,然后直接解释代码是怎么来的。

#include<stdio.h>
#include<conio.h>
#include<graphics.h>
#include<windows.h>
struct picsave {
	int lx;
	int ly;
	int rx;
	int ry;
	int  useflag=0;
} a[10];

struct pircle {
	IMAGE img2;
	IMAGE img3;
	const int orilx=100,orily=100;
	int nowlx=100,nowly=100;
	const int a=100,h=100;
//	原有图片的左上角坐标
	int m1x=0,m1y=0;

	int  putflag=0;
	int  drawflag=0;


} save;



void draw(struct ExMessage m,struct pircle *save) {
	if(save->drawflag==true) {

		putpixel(m.x,m.y,RGB(255,155,4));
	}


	switch(m.message) {
		case WM_LBUTTONDOWN:
			if(m.x>save->nowlx&&m.x<save->nowlx+save->a&&m.y>save->nowly&&m.y<save->nowly+save->h&&m.ctrl) {
//				检测不在图片里面
			} else {
				printf("m.x = %d\tm.y = %d\t%d\t%d\n",m.x,m.y,save->m1x,save->m1y);
				save->drawflag=true;
//				printf("drawflag = %d\n",save->drawflag);
			}

			break;

		case WM_LBUTTONUP:

			save->drawflag=false;
//			printf("%d\n",save->drawflag);
			break;
	}

}


void check(struct ExMessage m,struct pircle *save,struct picsave a[]) {
	printf("putflag = %d\n",save->putflag);
	printf("%d %d\n",m.x,m.y);
	printf("%d %d\n",save->nowlx,save->nowly);

	if(save->putflag==true) {
		BeginBatchDraw();

		putimage(save->nowlx,save->nowly,&save->img3);

		save->nowlx=save->nowlx+m.x-save->m1x;
		save->nowly=save->nowly+m.y-save->m1y;
		save->m1x=m.x;
		save->m1y=m.y;
		getimage(&save->img3,save->nowlx,save->nowly,save->a,save->h);

		putimage(save->nowlx,save->nowly,&save->img2);

		EndBatchDraw();

//			一次绘图出来,没有屏闪了
	}
	switch(m.message) {

		case WM_LBUTTONDOWN:
			if(m.x>save->nowlx&&m.x<save->nowlx+save->a&&m.y>save->nowly&&m.y<save->nowly+save->h) {
				save->putflag=true;
//					启动批复制粘贴
				getimage(&save->img2,save->nowlx,save->nowly,save->a,save->h);
				save->m1x=m.x;
				save->m1y=m.y;

			}
			break;
		case WM_LBUTTONUP:

			save->putflag=0;


//			int i;
//			for(i=0; i<6; i++) {
//
//				if(a[i].useflag==0) {
//					if(m.x>a[i].lx&&m.x<a[i].rx&&m.y>a[i].ly&&m.y<a[i].ry) {
//						BeginBatchDraw();
//
//						putimage(save->nowlx,save->nowly,&save->img3);
//
//						save->nowlx=save->nowlx+m.x-save->m1x;
//						save->nowly=save->nowly+m.y-save->m1y;
//						save->m1x=m.x;
//						save->m1y=m.y;
//						getimage(&save->img3,save->orilx,save->orily,save->a,save->h);
//
//						putimage(a[i].lx,a[i].ly,&save->img2);
//
//						EndBatchDraw();
//
//						save->nowlx=save->orilx;
//						save->nowly=save->orily;
//						save->m1x=0;
//						save->m1y=0;
//
//						a[i].useflag=1;
//						break;
//					}
//				}
//	}

//			实现一次性存档

			break;
	}

}

void flow(ExMessage m,struct picsave a[],struct pircle *save) {
	if(save->putflag==0&&m.message==WM_LBUTTONUP) {
		int i;
		for(i=0; i<6; i++) {

			if(a[i].useflag==0) {
				if(m.x>a[i].lx&&m.x<a[i].rx&&m.y>a[i].ly&&m.y<a[i].ry) {
					BeginBatchDraw();

					putimage(save->nowlx,save->nowly,&save->img3);

//					save->nowlx=save->nowlx+m.x-save->m1x;
//					save->nowly=save->nowly+m.y-save->m1y;
//					save->m1x=m.x;
//					save->m1y=m.y;

					getimage(&save->img3,save->orilx,save->orily,save->a,save->h);

					putimage(a[i].lx,a[i].ly,&save->img2);

					EndBatchDraw();

					save->nowlx=save->orilx;
					save->nowly=save->orily;
					save->m1x=0;
					save->m1y=0;

					a[i].useflag=1;
					break;
				}
			}
		}
	}

}

int main() {
	initgraph(640,640,EX_SHOWCONSOLE);
	setbkcolor(WHITE);
	cleardevice();


	setfillcolor(BLACK);
	setlinecolor(BLACK);
	fillrectangle(100,100,200,200);
//	这是初始图片左上角位置,以后都是新图片左上角的位置
	int i;
//	setlinecolor(WHITE);
	setfillcolor(GREEN);
	int q=100;
	for(i=1; i<5; i++) {
		a[i].lx=q;
		a[i].ly=400;
		a[i].rx=q+100;
		a[i].ry=500;
		q=q+100;
		fillrectangle(a[i].lx,a[i].ly,a[i].rx,a[i].ry);
	}
//	save.drawflag=1;

	ExMessage m;
	while(1) {
		m=getmessage(EX_MOUSE|EX_KEY);


		if(save.drawflag==false||save.drawflag==true) {
			draw(m,&save);

		}
		if(save.putflag==true||save.putflag==false) {
			check(m,&save,a);
			flow(m,a,&save);

		}


	}
	closegraph();
	return 0;
}


由于鼠标检测实现原理是,通过鼠标坐标m.x? m.y和鼠标事件如左键按下,右键按下,实际上延续这个问题就是坐标的问题,不断穷举坐标的各种相关、各种不知道相关不相关的判断。

想象中的需求经过几次描述出来就是,图片到了网格,图片就被网格吸收。

换成坐标来说,图片的坐标进了网格,图片就停在网格里。

但是想象一下图片只是黏在网格上,而不是正好嵌入,就单纯的坐标检测是否重叠也不好想象代码。

这里是参考UNITY,想起来以鼠标为主,就是鼠标在哪个网格,图片就嵌进去哪个网格,这样也能接受,那如此这样,只要能实现检测鼠标的位置就可以了。正好之前的代码check负责拖动,只要拖动结束的时候直接检测就行了,这样代码位置也解决了。于是就直接在check函数里的case LW_LBUTTONUP:这个分支下去写,就是check()函数那一大片注释处。只要全部取消,就能直接使用那部分代码实现检测。

后来是想着,由于地图实现拖动了,图片也实现的网格吸收,就想着独立出来这部分吸收代码,希望以后能够直接使用,或者减少函数长度,一个函数一个功能,减少脑子别扭难受的情况。于是就分离出来flow()函数,这就是专门处理图片嵌入网格存储的。flow()有一堆空白图片数组,然后每个数组的一项单元里,都有这个项对应的坐标,每一个网格的左上角坐标就都在这个项目里面。

然后运行成功,但是,鼠标一碰到网格图片就自己进去了。

这个BUG的效果是无论鼠标点没点击,只要鼠标拖动过图片,然后鼠标移动到网格上,就会有图片贴上去。

然后当时不知道哪里出问题了,唯一确定的是代码没复制粘贴整合成新函数的时候是正常的,于是就检测数据,相当于把有关拖动的变量内容都打印出来,先是在flow()里面增加打印的坐标信息语句,发现随着鼠标移动,就会一直打印鼠标坐标,而按照原计划,是只有鼠标松动的时候才进行检测,相当于打印鼠标只有在鼠标松开,而不是鼠标一移动就打印。flow函数失去了限制功能。

然后扩大范围,相当于发现if(save->putflag==0)失效了,之前想着不是鼠标松开,上一个函数直接就把save->putflag变成0,但是实际上这样却失败了,最后只能再就加上重复的&&m.message==LW_LBUTTONUP,才解决问题,但是没有理解bug。明明上个函数也已经用过一次m.message==LW_LBUTTONUP了。

现在来看,原来是鼠标松开,实现了flag变化,但是flag变化后是长期的,而鼠标松开是一瞬间相等。显然这样一看才理解,作用时间不一样导致了函数运行情况不同。也就是说,根本是没有意识到范围,默认中范围就已经不包含了一瞬间的变化,和长期状态的影响。只能通过矛盾来主动意识到意料之外,强行拓宽思考范围。

当然,文案不只是说为了解决BUG,可以看出来,刚才的BUG就是意外实现了鼠标拖动批量绘制,而这其实这也是以后像素绘画的原理。但是由于在这里能够主动意识到矛盾,对矛盾开发一下,自然而然就是另一个文案了。实际上无中生有的BUG和无中生有的解决方案,其实是同根同源的。他们都脱离过主动意识,而是从一些没来得及,或者以为不相关的情况里自然而然的穷举产生的。

人和BUG和谐共生可还行?但是一般都是BUG得不到理解,BUG也放不到合适的地方去应用emm。

理解BUG可以成为灵感的来源,但是理解bug比解决bug还要费劲,几乎把整个代码用人脑跑一边才能理解问题现象,确实代价比较大。

注意到if(save->putflag==0)和if(save->putflag==0&&m.message==WM.LBUTTONUP)的区别。

第一个BUG完事儿。

另一个BUG是在函数flow分离之前发生的。但是由于代码是复制粘贴,把原来函数的限制条件也复制粘贴过来,其实问题一样。

先看BUG效果

黑色方块变绿色了

纹理和第一幅图的比较像

答案解密:

注意旁边浅蓝色的代码

注意到坐标信息是原图的坐标

相当于又把原图复制粘贴到img3上。

按照惯例,前三章博客里img3含义都是底图,

这里也是一样,描述出来就是,原图变成了底图,

原来根本原因就是悬浮窗的底图把图片放置位置的网格复制了,

然后图片恢复到原处,借用悬浮窗先恢复原图,结果成了原图位置恢复网格纹理

所以需要清空img3,或者说不能清空的话,就把原来的图复制粘贴上。

这就是所谓复位——初始化所解决的矛盾的另一种表现形式。

初始化可以说是在旧数据矛盾不明显下的解决方案,因为不能解释旧数据是什么,

而复位,可以说是在旧数据矛盾明显下的解决方案,因为知道旧数据是上一次图片,而不需要使用这上一次图片,或者说不得不使用粘贴功能,但是可以更改粘贴的内容,把粘贴原来的旧图片变成粘贴相同的图片。

复位就是同样是图片,但是图片里面的数据清除。

而初始化,则是这个存数据的地方,曾经是存过图片的,但是这个数据现在已经不用来存图片,可以存其他的数据,但是里面存的图片数据还没清楚,就需要初始化,在不知道里面存的是什么的情况下直接清除数据,或者用新数据覆盖旧的乱七八糟的数据。

这就是从相同图片变量复位,同一个内存的重写,实现对危险数据的清除;到不同变量类型,使用相同内存,对内存重写数据,所描述出的初始化。

这就是复位和初始化的关系。

文章来源:https://blog.csdn.net/a1309602336/article/details/135215392
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。