基于C#实现用于显示照片的屏保

来源:互联网 发布:光猪圈健身怎么样 知乎 编辑:程序博客网 时间:2024/04/30 01:19

 

基于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的基础,绘图操作也容易了。