C#窗体皮肤制作(二):创建窗体库项目以及最小化、最大化、关闭按钮的实现
闲话少说,我还是接着上篇博客继续写,上次说明了下如何收集图片资源,这次就以360安全卫士来做示例进行模仿,本来也想过模仿下qq,但是qq的界面不太大众化也比较复杂,由于主要目的是希望让初学者弄明白做皮肤制作的思路,话说"授人以鱼不如授人以渔",因此这套博客的解讲的过程会比较简单易懂,让初学者也能学的明白,并且会将每篇对应的代码上传到我的csdn资源中,感兴趣的可以下载。我相信只要明白了思路,加上自己努力,qq之类的界面也是可以搞定的。
这一篇博客主要是讲自定义窗体的实现大体思路,以及最小化、最大化、关闭按钮的实现。总体思路是去掉窗体的默认边框,用其他的控件来替代最小化、最大化、关闭按钮的默认实现。第一讲不会考虑太多的细节,待功能开发的差不多时再进行一些代码的重构。由于是第一篇关于代码的,所以会从项目的创建、图片资源的引入开始,一步步讲解。
第一步:资源图片的选择
资源图片下载地址:[http://download.csdn.net/detail/bbirdsky/6923955]找到压缩包中的360safe.zip;
这一讲主要使用到的图片资源有:./MainFrame/Image/
background_mainwnd.jpg // 这张做为窗体的背景,为了命名简单更名为img_bg
sys_button_***.jpg //这4张分别对应最小化、最大化(还原)、关闭按钮的图片,更名为btn_***。
第二步:创建解决方案(MySkins)
并添加一个Window窗体控件库项MySkins目用于做自定皮肤,另外添加一个Window窗体应用程序项目MySkinsTest用于做测试,并将MySkinsTest做为默认启动项目,并为MySkinsTest添加引用项目MySkins步骤如图:
第三步:创建目录结构
创建Contorl、Entity、Frame、Util用于存放对应的类文件,以及将图片资源添加进项目的图片资源中去,最终的项目结构如图:
第四步:测试代码
先在MySkins项目中添加一个BaseForm窗体,并在MySkinsTest测试项目中让默认的Form1窗体继承自BaseForm,测试项目只是用于测试MySkins项目的效果,注意一定要先添加MySkins依赖项目,不然会找不到BaseForm这个类!
namespace MySkinsTest { public partial class Form1 : BaseForm { public Form1() { InitializeComponent(); } } }第五步:皮肤代码(BaseForm)
1、此篇的核心就是BaseForm窗体基类,首先在Frame目录下创建一个普通的Form窗体,并做如下属性设置:
1>将FormBorderStyle设置为None,此时Form窗体就没有边框以及最大小、最小化、关闭按钮了;
将BackgroundImage设置为img_bg,并将DoubleBuffered双缓冲设置为true。
2>添加三个PictureBox分别用于替代最小化、最大化、关闭按钮,也可以尝试使用Button替代;
将PictureBox的BackColor设置为Transparent透明,默认是灰色;
将三个PictureBox的定位设置为Anchor:Top,Right,这样最大化后的按扭位置后按右上保持不变;
绑定鼠标点击、移入移出、按下抬起事件,建议是相同事件用同一个事件方法处理。
3>添加一个ToolTip控件,用于显示提示信息,设置完的效果如下图:
2、代码分析:本讲主要包含ControlState控件状态和ResUtils资源帮助类。
1>由于图片的背景图片是4个为一组的,因此定义状态枚举类:ControlState,代码如下:
/// <summary> /// 控件状态 /// </summary> public enum ControlState { Normal = 1,//控件默认时 MouseOver = 2,//鼠标移上控件时 MouseDown = 3,//鼠标按下控件时 Disable = 4 //当控件不可用时 }
2>由于需要从资源中获取图片以及需要对获取的图片按状态进行切分,因些需要帮助类:ResUtils,代码如下:
/// <summary> /// 资源辅助类 /// </summary> class ResUtils { /// <summary> /// 根据资源名称获取图像 /// </summary> /// <param name="name">资源名称</param> /// <returns>图像</returns> public static Bitmap GetResAsImage(string name) { if (name == null || name == "") { return null; } return (Bitmap)Properties.Resources.ResourceManager.GetObject(name); } /// <summary> /// 图片按钮的背景图是4个,根据状态获取其中背景图 /// </summary> /// <param name="name">图片名称</param> /// <param name="state">状态</param> /// <returns></returns> public static Bitmap GetResWithState(String name, ControlState state) { Bitmap bitmap = (Bitmap)GetResAsImage(name); if (bitmap == null) { return null; } int block = 0; switch (state) { case ControlState.Normal: block = 0; break; case ControlState.MouseOver: block = 1; break; case ControlState.MouseDown: block = 2; break; case ControlState.Disable: block = 3; break; } int width = bitmap.Width / 4; Rectangle rect = new Rectangle(block * width, 0, width, bitmap.Height); return bitmap.Clone(rect, bitmap.PixelFormat); } }
3>对于最小化、最大化、关闭的实现代码如下:
this.WindowState = FormWindowState.Maximized; // 最大化
this.WindowState = FormWindowState.Minimized; // 最小化
this.WindowState = FormWindowState.Normal; // 一般状态
this.Close(); // 关闭
3、第一讲最终的效果实现了一个比较简单自定义窗体,具有最大化、最小化以及关闭功能。
不具备的功能:没有窗体小图标、标题,不能对窗体进行拖动、调整窗体大小,这是下一节要实现的功能。
小图标和标题比较简单好实现 ,窗体拖动、调整大小不使用win32Api也可以实现,但是效果不是太好,下节将使用win32Api进行实现!
对Win32不了解的可以看看这个文档:http://download.csdn.net/detail/bbirdsky/6910413
最后,我将继续保持更新。本篇对应代码下载:http://download.csdn.net/detail/bbirdsky/7366791。