首页
社区
课程
招聘
[求助]请教下这个软件在桌面上飘雪的是怎么实现的
发表于: 2009-12-23 16:54 10352

[求助]请教下这个软件在桌面上飘雪的是怎么实现的

2009-12-23 16:54
10352
这是我收到的一个圣诞节小礼物,我对其在桌面上绘制雪花技术比较感兴趣,想请教下各位里面具体是怎么实现的:
1.雪花是怎么绘出来的?
2.怎样无闪烁刷新绘图?
3.即使我把一个窗口放在雪花上面也不会感觉到明显的屏幕刷新。

我自己用c++实现了一下,发现
1.使用InvalidateRect(NULL,&rc,FALSE);会有明显的屏幕闪烁。
2.使用RedrawWindow(ChWnd,&rc,NULL,0x85);发现也会有屏幕闪烁现象。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (20)
雪    币: 4560
活跃值: (1002)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
粗略看了看是用了异形窗体的方法,雪花都是窗体用定时器控制下落
2009-12-23 17:18
0
雪    币: 297
活跃值: (10)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
3
我觉得是用GDI的光栅布尔操作实现的。
2009-12-23 19:02
0
雪    币: 22
活跃值: (443)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
http://www.2ccc.com/article.asp?articleid=1714
2009-12-23 19:49
0
雪    币: 191
活跃值: (55)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
谢谢楼上各位,楼上的朋友给的网址里面的代码,我在网上找到了c++版本,下面是我修改后的代码,附件中是VC9项目,我的代码雪花飘过时会有闪屏现象,为什么不能实现无闪重绘呢:
#include<windows.h>
#include<time.h>
#include<stdlib.h>
const int SnowNumber=20; //雪点数量
struct SnowNode
{
	POINT postion; //雪点位置
	int   iColor; //先前的颜色
	int   iSpeed; //下落速度 
	int   iMove; //下落距离
	int   iStick; //粘贴度
};
SnowNode SnowNodes[SnowNumber]; //雪点数组
int   hTimer=0;
int   CrWind=0;
int   CrStep=0; //当前循环步数(用于限速)
int   ScreenWidth=0;   //屏幕宽度
int   ScreenHeight=0;   //屏幕高度

void GetScreenSize();
void CALLBACK TimerProc(HANDLE hWnd,UINT uMsg,UINT idEvent,DWORD dwTime);
void InitSnowNodes();
void MoveSnowNodes();

int WINAPI WinMain(HINSTANCE hInstance,
				   HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine,
				   int   nCmdShow
				   )
{
	MSG msg; //标准windows消息 
	LARGE_INTEGER Frequency; //高性能定时器频率
	LARGE_INTEGER StartCt,EndCt;//高性能定时器计数
	int ElapsedTime;      //时间间隔
	srand((unsigned)time(NULL));
	GetScreenSize();
	InitSnowNodes();
	QueryPerformanceFrequency(&Frequency);
	hTimer=SetTimer(0,0,rand()%5*500,(TIMERPROC)TimerProc);
	if(hTimer==0)
	{
		MessageBox(0,TEXT("创建定时器失败"),TEXT("提示"),MB_OK|MB_ICONINFORMATION);
		return -1;
	}
	RegisterHotKey(0,0,MOD_CONTROL,(int)'L');
	while(1)
	{
		QueryPerformanceCounter(&StartCt); //执行运算前计数值
		if(PeekMessage(&msg,0,0,0,1))
		{
			switch(msg.message)
			{
			case WM_TIMER: 
				TimerProc(0,0,0,0);
				break; //预设风向改变时间已到
			case WM_HOTKEY: 
				KillTimer(0,hTimer);//删除随机风向定时 器
				UnregisterHotKey(0,0);//删除退出热键
				InvalidateRect(0,NULL,true);
				exit(1);
				break;
			case WM_DISPLAYCHANGE:
				GetScreenSize(); //重新取屏幕的尺寸
				InitSnowNodes(); //初始化雪点的数组
				break;
			}

		}
		MoveSnowNodes();
		QueryPerformanceCounter(&EndCt);//执行运算后的计数值
		ElapsedTime=(EndCt.QuadPart-StartCt.QuadPart)/Frequency.QuadPart;
		if((ElapsedTime<0.0005))
			Sleep(200); //简单限速
		else if(ElapsedTime<0.0010)
			Sleep(100);
		else if(ElapsedTime<0.0015)
			Sleep(300);
		

	}
	MessageBox(0,TEXT("消息"),TEXT("消息"),MB_OK|MB_ICONINFORMATION);
	return 0;
}
void GetScreenSize()
{
	ScreenWidth=GetSystemMetrics(SM_CXSCREEN);
	ScreenHeight=GetSystemMetrics(SM_CYSCREEN);
	return ;
}

void CALLBACK TimerProc(HANDLE hWnd,UINT uMsg,UINT idEvent,DWORD dwTime)
{
	// MessageBox(0,TEXT("消息"),TEXT("消息"),MB_OK|MB_ICONINFORMATION);
	srand((unsigned)time(NULL));
	if(hTimer==0)
	{
		MessageBox(0,TEXT("创建定时器失败"),TEXT("提示"),MB_OK|MB_ICONINFORMATION);
		return ;
	}
	SetTimer(0,hTimer,((rand()%27+4)*500),(TIMERPROC)TimerProc); //// 重设下次风向改变时间
	//修改风向
	if(CrWind!=0)
		CrWind=0;
	else
		CrWind=rand()%3-1;
	return ;
}

void InitSnowNodes()
{
	HDC hScreenDC=0;
	int j=0;
	hScreenDC=CreateDC("DISPLAY",NULL,NULL,NULL);
	if(hScreenDC==NULL)
	{
		MessageBox(0,"获取屏幕DC失败!","信息",MB_OK|MB_ICONERROR);
		return ;
	}
	srand((unsigned)time(NULL));
	for(j=0;j<SnowNumber;j++)
	{
		SnowNodes[j].postion.x=rand()%ScreenWidth;
		SnowNodes[j].postion.y=rand()%ScreenHeight;
		SnowNodes[j].iColor=GetPixel(hScreenDC,SnowNodes[j].postion.x,SnowNodes[j].postion.y);
		SnowNodes[j].iSpeed=(rand()%5+1);       //每次下落距离(1-5)
		SnowNodes[j].iStick=(30-rand()%SnowNodes[j].iSpeed); //粘贴度(几次循环作一次粘贴连判断

	}
	DeleteDC(hScreenDC);
}

void MoveSnowNodes()
{
	HDC hScreenDC=0;
	srand((unsigned)time(NULL));
	int x=0,y=0,i=0;
	hScreenDC= GetDC(NULL);
	if(hScreenDC==NULL)
	{
		MessageBox(0,"获取屏幕DC失败!","信息",MB_OK|MB_ICONERROR);
		return ;
	}
	 HPEN hNewPen = CreatePen(PS_SOLID,1,0xFFFFFF);
	 HPEN hOldPen = (HPEN)SelectObject(hScreenDC, hNewPen);
	for(i=0;i<SnowNumber;i++)
	{
		x	= SnowNodes[i].postion.x;
		y	= SnowNodes[i].postion.y;
		 
		RECT rc;
		rc.left =x;
		rc.top=y;
		rc.right = x+15;
		rc.bottom = y+15;
		//InvalidateRect(NULL,&rc,FALSE);
		SelectObject(hScreenDC,GetStockObject(NULL_BRUSH)); 
		//SetROP2(hScreenDC, R2_XORPEN ); 
		//FillRect(hScreenDC,&rc,(HBRUSH)GetStockObject(NULL_BRUSH));
		//Rectangle (hScreenDC, x, y, x+15, y+15);
		//SetROP2(hScreenDC,R2_BLACK); 
		HWND   ChWnd = GetDesktopWindow();    ;//取得桌面子句柄   
		SetCapture(ChWnd);//
		RedrawWindow(ChWnd,&rc,NULL,0x85);
		SnowNodes[i].postion.x = (SnowNodes[i].postion.x+10)%1280;
		SnowNodes[i].postion.y = (SnowNodes[i].postion.y + 10)%1000;
		x	= SnowNodes[i].postion.x;
		y	= SnowNodes[i].postion.y;
		MoveToEx(hScreenDC, x + 7, y, 0);
		LineTo(hScreenDC, x + 7, y + 15);
		MoveToEx(hScreenDC, x, y + 7, 0);
		LineTo(hScreenDC, x + 15, y + 7);

		MoveToEx(hScreenDC, x + 2, y + 2, 0);
		LineTo(hScreenDC,x + 13, y + 13);
		MoveToEx(hScreenDC, x + 2, y + 12, 0);
		LineTo(hScreenDC, x + 13, y + 1);

		MoveToEx(hScreenDC, x + 6, y + 2, 0);
		LineTo(hScreenDC, x + 9, y + 2);
		MoveToEx(hScreenDC, x + 6,y + 12, 0);
		LineTo(hScreenDC, x + 9, y + 12);

		MoveToEx(hScreenDC, x + 2, y + 6, 0);
		LineTo(hScreenDC, x + 2, y + 9);
		MoveToEx(hScreenDC,x + 12, y + 6, 0);
		LineTo(hScreenDC, x + 12, y + 9);
	}
	SelectObject(hScreenDC, hOldPen);
	DeleteDC(hScreenDC);
}
上传的附件:
2009-12-24 09:05
0
雪    币: 252
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
可以用缓冲来解决,先在内存中作画,然后BitBlt到Desktop的DC环境中去.
2009-12-24 09:20
0
雪    币: 367
活跃值: (20)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
7
WS_EX_LAYERED
2009-12-24 09:24
0
雪    币: 191
活跃值: (55)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
8
回六楼的朋友,我想如果使用双缓冲技术的话:
1.我只是在桌面上划线,如果我在内存DC中画好,再贴上去会不会更慢呢。
2.我只想让雪花在桌面的最上面飘,使用bltbit贴图会不会影响桌面上其他窗口的显示呢。
2009-12-24 09:43
0
雪    币: 186
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
用的是一些不规则窗口 不是在桌面上画的 没有闪烁
2009-12-24 09:50
0
雪    币: 211
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
如楼上所说他用的是窗口 不是直接绘图的 所以没有闪烁
2009-12-24 10:26
0
雪    币: 191
活跃值: (55)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
11

谢谢楼上二位提醒,原来是这样的,终于明白了,我去网上找一个不规则窗口的例子,大家有一些代码可以参考么,呵呵,真的很谢谢大家,我写好后会把代码贴出来的。
2009-12-24 10:59
0
雪    币: 394
活跃值: (131)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
12
这个程序好象和瑞星冲的
2009-12-24 14:52
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
13
汗... 1楼发的那个有内存泄漏
上个修正版:
上传的附件:
2009-12-25 01:03
0
雪    币: 636
活跃值: (174)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
14
拖IDA看了下,这厮就不是用GDI画的雪花,每一朵雪花都是一个窗口,不停地SetWindowPos,而且如楼上所说,还内存泄露……
2009-12-25 10:23
0
雪    币: 636
活跃值: (174)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
15
它移动窗口当然不闪,楼主自己画的必然没法跟它的效果比,而且自己画的还要涉及这么完美清楚痕迹的问题……麻烦……
2009-12-25 10:25
0
雪    币: 191
活跃值: (55)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
16
谢谢Fypher大侠的指点,总算知道这个是怎么雪花是怎么绘出来的了,回头我好好学学GDI+,怎么用GDI+实现透明贴图。
2009-12-28 10:35
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
进来学习下。
2009-12-28 12:04
0
雪    币: 252
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
静态的东西只需要在内存中一次性绘制,以后不需要绘制直接BitBlt到桌面DC上,你觉得会更慢么?
2010-1-10 16:15
0
雪    币: 256
活跃值: (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
19
可能是用OPENGL或DX写的吧
2010-1-12 13:41
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
20
关于透明贴图,我用易语言实现过,也是GDI,关键代码:

.版本 2

' 下面程序画板开始
GpInput.GdiplusVersion = 1
GdiplusStartup (Token, GpInput, 0)  ' 启动 GDI+

HDC = GetDC (0)  ' 取屏幕DC

' 创建第1个BMP
DC1 = CreateCompatibleDC (HDC)  ' 取屏幕兼容DC,目标DC
BMP1 = CreateCompatibleBitmap (HDC, 取屏幕宽度 (), 取屏幕高度 ())  ' 取屏幕兼容BMP
SelectObject (DC1, BMP1)  ' 关联到目标DC

' 创建第2个BMP
DC2 = CreateCompatibleDC (HDC)  ' 取屏幕兼容DC
BMP2 = CreateCompatibleBitmap (HDC, 取屏幕宽度 (), 取屏幕高度 ())  ' 取屏幕兼容BMP
SelectObject (DC2, BMP2)  ' 关联到目标DC

ReleaseDC (0, HDC)  ' 删除屏幕DC

' 在源BMP上画图形
you code
....

' 进行透明叠加,结果在目标DC(DC1)

tmp = 取空白字节集 (4)
tmp [3] = 透明度
bf = 取字节集数据 (tmp, #整数型, 1)  ' 取tmp从位置1开始的4字节

AlphaBlend (DC1, 0, 0, 取屏幕宽度 (), 取屏幕高度 (), DC2, 0, 0, 取屏幕宽度 (), 取屏幕高度 (), bf)
2010-1-14 00:24
0
雪    币: 212
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
21
效果还不错!
2010-1-17 14:02
0
游客
登录 | 注册 方可回帖
返回
//