小新的技术天地

Make It Works !

博客园 首页 新随笔 联系 订阅 管理

 

首先我们来看一下前面一篇文章提到了一个RssItem类实现了一个IItem接口,我们发现这个接口是存放在UI文件夹下的,这个接口本身很简单:

    public interface IItem

    {

        string Description { get; }

        string Title { get; }

}

它的具体实现是由UI文件夹下的另两个类来实现的。

我们首先考察ItemListView类,这个类的作用就是封装了Item List的显示方式:每一个的description在一个列表中显示,某一个Item处于选中状态。

我们查看代码可以发现它是一个泛型类

public class ItemListView<T> : IDisposable where T : IItem

类本身需要实现IDisposable接口,以释放一些资源,还定义了一个泛型约束,以使我们的T的类型都要实现IItem接口(关于泛型约束请参考我的文章

类具体的内容都是GDI+的编程实现,大家可以自己查看

 

另一个类ItemDescriptionView.cs的作用是封装了每一个ItemDescription的显示方式

接下来我们看一下主窗体:ScreenSaverForm

在类构造器里,初始化组件以后,我们看到第一个方法是SetupScreenSaver(),这个方法的作用是把主窗体设为一个全屏的屏保程序

我们查看一下代码:

            // 使用双倍缓冲增加绘制的表现,其实这里使用的OptimizedDoubleBuffer我查看了VS2003

            //的文档,并没有这个枚举值,只有DoubleBuffer,看样子是2.0新增的

            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);

            //获取鼠标

            this.Capture = true;

 

            // 把应用程序设为全屏,然后隐藏鼠标

            Cursor.Hide();

            Bounds = Screen.PrimaryScreen.Bounds;

            WindowState = FormWindowState.Maximized;

            ShowInTaskbar = false;

            DoubleBuffered = true;

            BackgroundImageLayout = ImageLayout.Stretch;

 

接下来的方法是LoadBackgroundImage()

 

            // 初始化图像

            backgroundImages = new List<Image>();

            currentImageIndex = 0;

 

            if (Directory.Exists(Properties.Settings.Default.BackgroundImagePath))

            {

                try

                {

                    // 尝试载入用户给出的图像

                    LoadImagesFromFolder();

                }

                catch

                {

                    // 如果失败,再入默认图像

                    LoadDefaultBackgroundImages();

                }

            }

 

            // 如果没有图像可载入,就载入默认的

            if (backgroundImages.Count == 0)

            {

                LoadDefaultBackgroundImages();

            }

 

 其实查看Properties.Settings,我们发现BackgroundImagePath刚开始是没有值的,所以肯定会载入默认图像。

这里又涉及到两个方法,第一个是

        private void LoadImagesFromFolder()

        {

            DirectoryInfo backgroundImageDir = new DirectoryInfo(Properties.Settings.Default.BackgroundImagePath);

            // 遍历每一个图片扩展名 (.jpg, .bmp, etc.)

            foreach (string imageExtension in imageExtensions)

            {

                //遍历用户提供的文件夹内的每一个文件

                foreach (FileInfo file in backgroundImageDir.GetFiles(imageExtension))

                {

                    // 尝试载入图像

                    try

                    {

                        Image image = Image.FromFile(file.FullName);

                        backgroundImages.Add(image);

                    }

                    catch (OutOfMemoryException)

                    {

                        // 如果图像无法再入,继续下一个文件

                        continue;

                    }

                }

            }

        }

第二个是

        private void LoadDefaultBackgroundImages()

        {

            //如果背景图像由于任何原因不能被载入

            //使用储存在resources里的图像

            backgroundImages.Add(Properties.Resources.SSaverBackground);

            backgroundImages.Add(Properties.Resources.SSaverBackground2);

        }

 

我们查看Properties.Resources可以看到

        internal static System.Drawing.Bitmap SSaverBackground {

            get {

                object obj = ResourceManager.GetObject("SSaverBackground", resourceCulture);

                return ((System.Drawing.Bitmap)(obj));

            }

        }

       

        internal static System.Drawing.Bitmap SSaverBackground2 {

            get {

                object obj = ResourceManager.GetObject("SSaverBackground2", resourceCulture);

                return ((System.Drawing.Bitmap)(obj));

            }

        }

而这里的SSaverBackgroud是嵌入在资源文件里的图片的名称

 

那么发布出去的屏保文件是否包含着两张图片呢,我们就动手做一个小实验

首先以默认的情况下发布,我们发现生成的exe文件为120K大小,而然后我在资源文件里添加一张1.17Mbmp文件,然后让程序显示我们新添加的这张默认图片

Properties.Resources添加如下语句(图片文件名为_7

        internal static System.Drawing.Bitmap SSaverBackground3

        {

            get

            {

                object obj = ResourceManager.GetObject("_7", resourceCulture);

                return ((System.Drawing.Bitmap)(obj));

            }

        }

然后在ScreenSaverFormLoadDefaultBackgroundImages()方法添加语句

backgroundImages.Add(Properties.Resources._7);

然后编译运行,我们就可以看到我们新添加的默认图片,然后查看生成的exe文件,大小变为1.29M

所以我们可以得知新加入的图片已经嵌入在PE文件里面了。

 

接下来的就是  LoadRssFeed();方法了

        private void LoadRssFeed()

        {

            try

            {

                //尝试从用户的settings或者rssFeed

                rssFeed = RssFeed.FromUri(Properties.Settings.Default.RssFeedUri);

            }

            catch

            {

                //如果载入Rss有问题,则载入一个错误信息

                rssFeed = RssFeed.FromText(Properties.Resources.DefaultRSSText);

            }

        }

这里的RssFeed类在前面已经分析过了

 

后面的是

            // 初始化显示ItemListView来显示RssItem里的Items列表

            // 放在屏幕的左侧   

            rssView = new ItemListView<RssItem>(rssFeed.MainChannel.Title, rssFeed.MainChannel.Items);

            InitializeRssView();

 

InitializeRssView()方法里设置了我们需要的具体数值

        private void InitializeRssView()

        {

            rssView.BackColor = Color.FromArgb(120, 240, 234, 232);

            rssView.BorderColor = Color.White;

            rssView.ForeColor = Color.FromArgb(255, 40, 40, 40);

            rssView.SelectedBackColor = Color.FromArgb(200, 105, 61, 76);

            rssView.SelectedForeColor = Color.FromArgb(255, 204, 184, 163);

            rssView.TitleBackColor = Color.Empty;

            rssView.TitleForeColor = Color.FromArgb(255, 240, 234, 232);

            rssView.MaxItemsToShow = 20;

            rssView.MinItemsToShow = 15;

            rssView.Location = new Point(Width / 10, Height / 10);

            rssView.Size = new Size(Width / 2, Height / 2);

        }

接下来的ItemDescriptionView雷同

 

 

至此,我们的屏保就可以显示出来的,但是作为屏保,我们还缺少一些对鼠标、键盘事件的响应。

        private void ScreenSaverForm_MouseMove(object sender, MouseEventArgs e)

        {

            // 只有在这个事件第一次调用的时候才设置IsActiveMouseLocation

            if (!isActive)

            {

                mouseLocation = MousePosition;

                isActive = true;

            }

            else

            {

                // 在第一次调用以后,如果鼠标发生位置移动,就关闭窗体

                if ((Math.Abs(MousePosition.X - mouseLocation.X) > 10) ||

                    (Math.Abs(MousePosition.Y - mouseLocation.Y) > 10))

                {

                    Close();

                }

            }

        }

当然还有

 

        private void ScreenSaverForm_MouseDown(object sender, MouseEventArgs e)

        {

            Close();

        }

关于键盘事件,可以根据我们的需要定制

 

        private void ScreenSaverForm_KeyDown(object sender, KeyEventArgs e)

        {

            switch (e.KeyCode)

            {

                case Keys.Down:

                    rssView.NextArticle();

                    break;

                case Keys.Up:

                    rssView.PreviousArticle();

                    break;

                default:

                    Close();

                    break;

            }

 

posted on 2005-12-05 18:01  小新0574  阅读(1644)  评论(2编辑  收藏  举报