屏保设计
青岛理工大学
C++
计算机工程学院
计算机科学与技术
胡松朝_
073: 计算 200707046
: 屏幕保护程序______
: _ 2009.12.21 —2009.12.31 __
: 青岛理工大学 2# 实验楼 402
: 李兰
完成日期: 2009 年 12 月 31 日
1
对于电脑用户来说,选择电脑时,首先提出的指标一定是奔腾、赛扬等一系列
与CPU有关的数据,电脑的心脏固然重要,但对于经常与电脑打交道的人来说,电
脑的“脸”—显示器,同样是最关心的问题之一。如果你每天面对的是一个色彩柔
和、清新亮丽的“笑脸”,你在它身边工作一定特别来劲,工作效率也一定会提高。
当你买了一台电脑后,希望它的寿命的时间越长越好,这样你既可以享受电脑给你
带来的快乐,还可以不要花太多的钱来维护你的电脑。屏幕保护程序可以起到保护
你的显示器的作用,这样可以相对减少你的金钱支出。
在未启动屏保的情况下,当你长时间不使用电脑的时候显示器的屏幕长时间显
示不变的画面,这将会使屏幕发光器件疲劳变色/甚至烧毁/最终使屏幕,某个区域
偏色或变暗。 对于CRT的显示器来说,在图形界面的操作系统下,显示屏上显示的
色彩多种多样,当用户停止对电脑进行操作时,屏幕显示就会始终固定在同一个画
面上,即电子束长期轰击荧光层的相同区域,长时间下去,会因为显示屏荧光层的
疲劳效应导致屏幕老化,甚至是显像管被击穿。屏幕保护程序一直作为保护CRT显
示屏的最佳帮手,通过不断变化的图形显示使荧光层上的固定点不会被长时间轰击,
从而避免了屏幕的损坏。
另外,屏幕保护程序所提供的动画效果,可以给你的忙碌生活添加积分乐趣。
2
本程序为windows操作系统的屏幕保护程序。
在程序运行时,会在屏幕最上方出现全屏窗口,自动载入满屏图片,同时由上至下出现大小随机速度随机的白色雪花慢慢摇曳飘落,黑色调的浪漫图片从右至左缓缓流动,伴随着美妙音乐,给人视觉享受。当按下键盘非系统键,或按下鼠标左、右及滚轮键时程序自动退出,为了防止桌面震动带来的影响,鼠标必须移动大于200像素的距离,屏保程序才能退出。
1
设定系统屏保,按时自动
启动程序
图片载入及及图片循环流动雪点随机显示显示
按下键盘键及音乐载入及循点击或移动鼠环播放标程序结束
类构造函数_tWinMain 全局变量定义 用户设定启动CMyscreenApp(WinMain)theApp
InitInstance定时完成初始化工OnTimer作
映射对话框相关BEGIN_MESSAGECMyscreenDlg_MAP
数据交换画图片和载入DoDataExchang音乐OnPainte画雪点画屏幕PointDrawBitmap
消息
OnLButtonDown
消息
OnMouseMove
消息库函数用户发出结束
OnKeyDownPostMessage命令
消息销毁
OnMouseWheelOnDestroy
消息
OnRButtonDown
BOOL CMyscreenDlg::OnInitDialog()//初始化对话框
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically// when the application's main window is not a dialogSetIcon(m_hIcon, TRUE);// Set big iconSetIcon(m_hIcon, FALSE);// Set small icon// TODO: Add extra initialization here
CRect m_rcMain;//设一个矩形对象
GetWindowRect(&m_rcMain);//得到窗口并存储
LONG style=GetWindowLong(m_hWnd,GWL_STYLE);//得到窗口状态 style &= ~WS_CAPTION; //Creates a window that has a title bar (includes the WS_BORDER
style).
SetWindowLong(m_hWnd,GWL_STYLE,style); //设置窗口s_showW = GetSystemMetrics(SM_CXSCREEN); // 得到屏幕宽度s_showH = GetSystemMetrics(SM_CYSCREEN); //得到屏幕高度//show window
for (int i=1; i<=SnowCount; i++)//进入循环,随机生成雪点的速度及坐标,共300个
{
Snow[i].speed = rand()%10;
Snow[i].x = rand()%s_showW;
Snow[i].y = rand()%s_showH;
}
SetWindowPos(NULL,-20,0,s_showW+25,s_showH,SWP_NOZORDER);//设置窗口位置及大小,要比屏幕
大些,遮盖整个屏幕
::GetCursorPos(&w_point);//获得鼠标的位置
ShowCursor(FALSE);//隐藏鼠标
SetTimer(1,1,NULL);//图片流动定时
SetTimer(2,300,NULL);//雪花定时
return TRUE; // return TRUE unless you set the focus to a control
}
void CMyscreenDlg::OnPaint() //画图片和载入音乐
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1)/2 ;
int y = (rect.Height() - cyIcon + 1)/2 ;
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CPaintDC dc(this); //创建设备上下文类的对象
w_pdcmem = new CDC;//分配新的内存
w_bitmap.LoadBitmap(IDB_BITMAP1);//载入图片
w_pdcmem->CreateCompatibleDC(&dc);//关联内存
w_pdcmem->SelectObject(&w_bitmap);//图片载入内存
w_showX = 0; //初始为0
sndPlaySound( "music.wav" , SND_ASYNC | SND_LOOP ); //载入音乐
CDialog::OnPaint();
}
}
void CMyscreenDlg::DrawBitmap()//填充整个窗口,并显示{
CClientDC dc(this);
CDC dcmem;
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc,s_showW,s_showH);
dcmem.CreateCompatibleDC(&dc);
dcmem.SelectObject(&bitmap);
dcmem.SetBkMode(0);
dcmem.FillRect(&CRect(0,0,s_showW,s_showH),
&CBrush(RGB(0,0,255)));//填充整个屏幕为蓝色(这步可以省)
UINT y =0;
//从内存读取填充矩形和图片一并拷贝到屏幕上
dcmem.StretchBlt(
0,y,s_showW,s_showH,
w_pdcmem,
w_showX,0,s_showW,s_showH,
SRCCOPY);
dc.BitBlt(20,0,s_showW,s_showH,&dcmem,0,0,SRCCOPY);//显示在屏幕上}
void CMyscreenDlg::OnLButtonDown(UINT nFlags, CPoint point) {
// TODO: Add your message handler code here and/or call default
PostMessage(WM_CLOSE);
CDialog::OnLButtonDown(nFlags, point);
}
void CMyscreenDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
// TODO: Add your message handler code here and/or call default
PostMessage(WM_CLOSE);
CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
}
//…………其他消息响应函数原理如上,不再列出…………………
void CMyscreenDlg::OnTimer(UINT nIDEvent) //定时器函数,用于定时刷新窗口实现动态效果
{
{
w_showX += 1;//每次移动一个像素
if(w_showX>=1050)//当图片移动大于1050像素时,从新显示
{
w_showX = 0;
}
DrawBitmap( );//显示位图
CDialog::OnTimer(nIDEvent);//定时器1
}
CClientDC dc(this);
for (int i=1; i<=SnowCount; i++)//设置300个雪点的状态
{
Snow[i].y += Snow[i].speed;//雪点纵坐标与速度相关
if (Snow[i].y > s_showH)//当雪点的纵坐标大于屏幕高度时,调整坐标,更换速
度
{
Snow[i].x = rand() % s_showW;
Snow[i].y = -Snow[i].speed;
Snow[i].speed =rand()%10;
}
Point(&dc,Snow[i].x,Snow[i].y,int(Snow[i].speed/4)+1);//保存雪点状态
}
CDialog::OnTimer(nIDEvent);//定时器2}
void CMyscreenDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
delete w_pdcmem;
KillTimer(1);//关掉计时器1
KillTimer(2);//关掉计时器2
}
void CMyscreenDlg::OnActivateApp(BOOL bActive, HTASK hTask)//只允许一个程序运行
{
CWnd::OnActivateApp(bActive, hTask);
// TODO: Add your message handler code here
if (!bActive) //is being deactivated
PostMessage(WM_CLOSE);
}
void CMyscreenDlg::Point(CDC *dc, int x, int y, int Size)//画雪点,大小和速度一致
{
CPen lPen(PS_SOLID, Size+1, RGB(255,255,255));//设置画笔
dc->SelectObject(&lPen);//选择画笔
dc->MoveTo(x,y);//移动当前点到(x,y)上
dc->LineTo(x,y);//在(x,y)画直线,即本点上画直线,相当于画个点,作为雪花}
1
在Windows环境下,采用Microsoft Visual C++ 6.0作为开发工具,并使用MFC Application Framework作为本软件的基本架构。采用C++来进行图像编程的主要原因是,与Java和C#等现代编程语言相比,C++在程序运行的效率、内存使用的可控性和编程的灵活性上具有优势。因此本设计使用Microsoft Visual C++ 6.0作为软件的开发平台。针对程序中要提供软件的选择性,这要通过不同的控件来实现。对不同的控件添加不同的消息响应
PC甚至添加一个新的类或者使用继承的类。本程序运行不需要太高的机器配置,普通的机运行流畅。
2
1 图
出现较严重的问题如下:
1、
CMyscreenDlg::OnInitDialog()函数中:
SetWindowPos(NULL,0,0,s_showW,s_showH,SWP_NOZORDER);
1背景不能填充全屏,不美观,如图。
更改后:
SetWindowPos(NULL,-20,0,s_showW+25,s_showH,SWP_NOZORDER);
2、弄错了图像的尺寸大小,导致图像不能居中显示
3、在增加下雪效果时没有增加定时器,代码无语法错误,但运行时逻辑错误,
21更正方法:增加一个定时器,作为雪点变换的定时器,独立于图片流动的定时器,雪点一定要画出图片之后开始画,在最外层。
2图
32、雪点的大小和速度不美观(如图),多次调整后参数设置为:CPen lPen(PS_SOLID, Size+1, RGB(255,255,255));
Snow[i].y += Snow[i].speed;//雪点纵坐标与速度相关
if (Snow[i].y > s_showH)
{
Snow[i].x = rand() % s_showW;
Snow[i].y = -Snow[i].speed;
Snow[i].speed =rand()%10;
}
Point(&dc,Snow[i].x,Snow[i].y,int(Snow[i].speed/4)+1);
4photoshop、更换和调整图片,用到软件作图,图片的大小应适合屏幕尺寸。3
.bmp.wav本程序只能载入格式为的图片文件和格式为的音频文件,这两种格式的文件
.jpg.mp3很大,占用相对多的磁盘空间,可以更改成能载入格式图片和格式的音频文件就
10可以节省相比下的大约倍空间,这是最不足的地方。
4
本程序的功能相对简单,可以增加调整雪花速度和数量、多张图片载入以及音乐的开关和调整功能。可以在做一个控件对话框,为用户提供选择和调整权力。另外,可以把鼠标的右键作为在屏保运行时的音乐开关键,这样会使屏保更加友好。
1
debug.exe.scr在下生成的可执行文件更改后缀个格式为,然后把此文件连同音频文
myscreen,1min,件一并拷入系统屏保所在的文件夹里,设定系统的屏保为时间设定为则在1min后看屏保是否可正常流畅运行。
2
3 图
3屏保运行时的截图如图所示。
debug.exe.scr在下生成的可执行文件更改后缀个格式为,然后把此文件连同音频文件
C:\WINDOWS\system32一并拷入系统屏保所在的文件夹里,路径为。在桌面右击——属性,4然后调整如图所示。时间到了以后,屏保自动运行。
4 图
开始不懂得如何让程序全屏显示,只知道-屏保的基本思想是基于对话框的,就是一个满屏显示的对话框,在对话框上自动进行一些动画之类的东西。理论视乎简单,但在真正动手去做的时候,就遇到了很多困难。电脑屏幕窗口是各异的,不是简简单单对于自己的机器屏幕尺寸去设计对话框的大小,经过查阅网上资料,才得知需要用到一个获得显示器屏幕尺寸的系统函数:GetSystemMetrics(SM_CXSCREEN)和GetSystemMetrics(SM_CYSCREEN),最容易忽略的一点是要隐藏鼠标,屏幕保护如果还有鼠标出现的话是很难看的,不专业的,这是用到一个很简单的库函数ShowCursor(FALSE),就可消去鼠标了。
图片先载入到内存中,然后从内存中读取到屏幕,这样就可以避免后面图片流动不出现闪动现象。设定时器,每个0.1秒屏幕刷新一次,此时要时屏幕上图片显示的区域横坐标减少一个像素,这样就可以是图片每隔0.1秒向左移动一个像素的距离,看上去图片流动起来。设计雪花时也费了不少功夫,查了很多资料,为了不让雪花遮盖图片,选用了粒子知识来设计雪花程序,简练美观。
消息响应也是一个要精心准备的部分。对于CRT的显示器来说,在图形界面的操作系统
下,显示屏上显示的色彩多种多样,当用户停止对电脑进行操作时,屏幕显示就会始终固
定在同一个画面上,即电子束长期轰击荧光层的相同区域,长时间下去,会因为显示屏荧
光层的疲劳效应导致屏幕老化,甚至是显像管被击穿。屏幕保护程序一直作为保护CRT显示
屏的最佳帮手,通过不断变化的图形显示使荧光层上的固定点不会被长时间轰击,从而避免了屏幕的损坏。屏幕保护是在电脑屏幕一定时间处于静止时自动启用的程序,当用户要结束屏保时,只需按任意键或移动鼠标就可以回到原始工作界面的。实现这种机制就是要对消息响应进行处理,还要注意的一点是,要考虑到客观因素,比如鼠标的移动来自于桌面震荡而非用户主观移动,这就需要限制鼠标移动距离(程序中表现为像素)了,一般当鼠标移动范围在200像素内是不做结束屏保程处理的。
对于这次的程序设计,除了熟练了VC知识外,最大的感受就是---“实践大于理论”。平时只是停留在理论上,懒于动手实践,当需要真正做的时候才发现种种问题。这种认识也是此次程序设计的一个大的收获。
[1] 黄维通、姚瑞霞 .Visual C++程序设计
.机械工业出版社,2005.1
[2] 严华峰 .Visual C++课程设计案例精编 .中国水利水电出版社,1999.2
2001.5[3] 第一时间工作室 .Visual C++ 6.0程序设计技能百练 .中国铁道出版社,
[4] (美)H . M . Deitel, P . J . Deitel著,施平安 译 .清华大学出版社,
1999.2
[5] 陈清华. Visual C++课程设计案例精选与编程指导.东南大学出版社,2004.4
myscreen.scr为系统屏保文件
myscreen.exe为可直接执行文件
x.bmp为载入的图片
mycreenmyscreen.dsw文件夹中是此屏保工程的保存文件,其中是此工程的打开文件