基于C#实现用于显示照片的屏保
摘要
Windows XP已经带了一个屏保程序,让用户可以现实照片,只要你将这些照片放于指定目录。 但是照片不是全屏;本篇基于全屏显示照片;照片位置在注册表中。
实现
1 屏保程序框架
屏保程序有命令行四个参数:
case
"/a": //密码对话框实现代码
MessageBox.Show("passwd not set for this screen saver.");
Application.Exit();
break;
case "/c": //参数设置实现代码
MessageBox.Show("parameter not set for this screen saver.");
Application.Exit();
break;
case "/p": //预览实现代码
Cursor.Hide();
m_ifPrev = true;
startTimer();
break;
case "/s": //正常运行实现代码
Cursor.Hide();
startTimer();
break;
default: stopScreen(); break;
一般而言,预览和正常运行时必须要处理的。
2 可调参数
屏保程序由俩个可调参数:自动播放的间隔时间和照片目录。本程序用注册表处理。
RegistryKey
rkScr = null;
RegistryKey rk = Registry.LocalMachine.OpenSubKey(location);
string[] subkeys = rk.GetSubKeyNames();
foreach (string s in subkeys)
{
if (s == key_name)
{
rkScr = rk.OpenSubKey(s);
m_default_path = (string)rkScr.GetValue(key_path_name);
int interval = (int)rkScr.GetValue(key_interval_name);
m_interal = interval > 1000 ? interval : 1000;
rk.Close();
break;
}
}
if (rkScr == null)
{
rkScr = rk.CreateSubKey(key_name, RegistryKeyPermissionCheck.ReadWriteSubTree);
rkScr.SetValue(key_path_name, m_default_path);
rkScr.SetValue(key_interval_name, m_interal);
rk.Close();
}
3 读取文件信息
图片不能一开始就加载,这样占用太多内存。只能在Timer的回调中处理,释放前一张图片空间,加载新照片。
但是图片信息可以初始化时准备好,主要是图片的路径名。
private
void getAllFile()
{
if (Directory.Exists(m_default_path))
{
DirectoryInfo di = new DirectoryInfo(m_default_path);
try
{
foreach (FileInfo fi in di.GetFiles())
{
if (fi.Extension == ".jpg")
{
m_pics.Add(fi.FullName);
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
特别是对文件过滤的处理要注意,否则会生成一个thumbs.db文件,导致下次运行时抛出OutOfMemory异常。这里不过滤文件也可以,但是必须Image实例创建时捕获一场并处理。
try
{
if (m_ie.MoveNext())
{
m_img = Image.FromFile(m_ie.Current);
m_brush.Interval = m_interal > 2000 ? m_interal - 1000 : m_interal / 2;
m_brush.Tick += new EventHandler(m_brush_Tick);
m_brush.Start();
Invalidate();
}
else
{
m_ie.Reset();
}
}
catch (InvalidOperationException ioe)
{
MessageBox.Show(ioe.Message);
}
catch (OutOfMemoryException ome)
{
MessageBox.Show(ome.Message + " when read file:" + m_ie.Current);
this.m_pics.Remove(m_ie.Current);
m_img.Dispose();
m_ie = m_pics.GetEnumerator();
}
catch (FileNotFoundException fnfe)
{
MessageBox.Show("file " + fnfe.FileName + " not found");
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
//stopScreen();
}
Image类可以参考MSDN。
4 绘图
必须重载Form类的OnPaint函数。
protected
override void OnPaint(PaintEventArgs e)
{
if (!m_ifDrawBg)
{
if (m_img != null)
{
//e.ClipRectangle();
Graphics g = e.Graphics;
Rectangle rect;
if (m_img.Size.Width > m_img.Size.Height)
{
rect = new Rectangle(this.Left, this.Top,
this.Left + this.Width, this.Top + this.Height);
}
else
{
double scale = (double)m_img.Size.Width / (double)m_img.Size.Height;
rect = new Rectangle(this.Width / 4, this.Top,
this.Left + (int)(scale * this.Height), this.Top + this.Height);
}
m_DrawArea = rect;
g.DrawImage(m_img, rect);
}
}
else
{
Graphics g = e.Graphics;
g.FillRectangle(m_blkBrush, m_DrawArea);
m_ifDrawBg = false;
}
base.OnPaint(e);
}
这里根据图片大小,作了一个全屏的处理。
5 全屏
全屏的关键是计算绘图区域,去PrimaryScreen的边界。
this
.Width = Screen.PrimaryScreen.Bounds.Width;
this.Height = Screen.PrimaryScreen.Bounds.Height;
this.Size = new System.Drawing.Size(this.Width, this.Height);
this.Left = 0;
this.Top = 0;
m_DrawArea.X = this.Left;
m_DrawArea.Y = this.Top;
m_DrawArea.Width = this.Width;
m_DrawArea.Height = this.Height;
this.BackColor = Color.Black;
this.FormBorderStyle = FormBorderStyle.None;
this.ShowInTaskbar = false;
6 定时器
为了图片自动浏览效果比较舒服,这里使用了3个定时器:
- 自动播放定时器,播放照片,启动刷屏定时器;
- 延时定时器:接受键盘和鼠标事件,避免屏保启动时立即退出。
- 刷屏定时器:在显示上一幅图后用黑色brush清空屏幕。
结束语
基于C#实现屏保非常方便,主要是图片显示有C#的Image类处理;另外,有了MFC的基础,绘图操作也容易了。