以文本方式查看主题 - 计算机科学论坛 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- VC# 2005 Screen Saver Starter kit的主窗体分析 (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=56712) |
-- 作者:卷积内核 -- 发布时间:12/13/2007 2:32:00 PM -- VC# 2005 Screen Saver Starter kit的主窗体分析 首先我们来看一下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的作用是封装了每一个Item的Description的显示方式。
接下来我们看一下主窗体: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.17M的bmp文件,然后让程序显示我们新添加的这张默认图片 在Properties.Resources添加如下语句(图片文件名为_7) internal static System.Drawing.Bitmap SSaverBackground3 { get { object obj = ResourceManager.GetObject("_7", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } 然后在ScreenSaverForm的LoadDefaultBackgroundImages()方法添加语句 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) { // 只有在这个事件第一次调用的时候才设置IsActive和MouseLocation 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; }
|
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
78.125ms |