C#窗体皮肤制作(二):创建窗体库项目以及最小化、最大化、关闭按钮的实现

      很高兴有朋友关注这篇博客,同时也十分抱歉让关注的朋友久等了,隔上一篇博客也有3个月没有更新,主要是由于3月份辞职,4月份初离职到期离开了北京高德,来到了上海张江。目前新工作也处于熟悉当中,希望大家能体谅。刚好这周末有点时间,我就接着写写,这篇博客主要是针对初学者,希望给为他们能提供一种较易理解的窗体皮肤制作思路,记得自己当初学习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。

  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
自定义窗体最大化最小化关闭按钮, C#移动无标题栏窗体的三种代码: C#移动无标题栏窗体的三种代码:第一种采用,需注意窗体上的控件是否把窗体覆盖了。。。MouseDown、MouseMove、MouseUp事件应该是鼠标所处位置最顶层的控件的事件 在窗体的类中声明两个变量 private Point mouseOffset; //记录鼠标指针的坐标 private bool isMouseDown = false; //记录鼠标按键是否按下 创建窗体 MouseDown、MouseMove、MouseUp事件的相应处理程序 private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { int xOffset; int yOffset; if (e.Button == MouseButtons.Left) { xOffset = -e.X ; yOffset = -e.Y ; mouseOffset = new Point(xOffset, yOffset); isMouseDown = true; } } private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) { if (isMouseDown) { Point mousePos = Control.MousePosition; mousePos.Offset(mouseOffset.X, mouseOffset.Y); Location = mousePos; } } private void Form1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { // 修改鼠标状态isMouseDown的值 // 确保只有鼠标左键按下并移动时,才移动窗体 if (e.Button == MouseButtons.Left) { isMouseDown = false; } } 第种调用API 未验证 using System.Runtime.InteropServices; [DllImport("user32.dll")] public static extern bool ReleaseCapture(); [DllImport("user32.dll")] public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); public const int WM_SYSCOMMAND = 0x0112; public const int SC_MOVE = 0xF010; public const int HTCAPTION = 0x0002; private void Form1_MouseDown(object sender, MouseEventArgs e) { ReleaseCapture(); SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0); } 第三种未验证 private bool isMouseDown = false; private Point FormLocation; //form的location private Point mouseOffset; //鼠标的按下位置 [DllImport("user32.dll")] public static extern bool ReleaseCapture(); [DllImport("user32.dll")] public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); private const int WM_SYSCOMMAND = 0x0112;//点击窗口左上角那个图标时的系统信息 private const int SC_MOVE = 0xF010;//移动信息 private const int HTCAPTION = 0x0002;//表示鼠标在窗口标题栏时的系统信息 private const int WM_NCHITTEST = 0x84;//鼠标在窗体客户区(除了标题栏和边框以外的部分)时发送的消息 private const int HTCLIENT = 0x1;//表示鼠标在窗口客户区的系统消息 private const int SC_MAXIMIZE = 0xF030;//最大化信息 private const int SC_MINIMIZE = 0xF020;//最小化信息 protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_SYSCOMMAND: if (m.WParam == (IntPtr)SC_MAXIMIZE) { m.WParam = (IntPtr)SC_MINIMIZE; } break; case WM_NCHITTEST: //如果鼠标移动或单击 base.WndProc(ref m);//调用基类的窗口过程——WndProc方法处理这个消息 if (m.Result == (IntPtr)HTCLIENT)//如果返回的是HTCLIENT { m.Result = (IntPtr)HTCAPTION;//把它改为HTCAPTION return;//直接返回退出方法 } break; } base.WndProc(ref m);//如果不是鼠标移动或单击消息就调用基类的窗口过程进行处理 } private void Form1_Load(object sender, EventArgs e) { } ------------------------------- 如何在窗体标题栏左边的控制菜单加入自己的菜单啊? 我们一般在窗口标题栏点右键 或 按Alt+空格 可以弹出那个菜单。 ------解决方案-------------------- using System.Runtime.InteropServices; [DllImport( "user32.dll ")] public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport( "user32.dll ")] public static extern bool InsertMenu(IntPtr hMenu, uint uPosition, uint uFlags, uint uIDNewItem, string lpNewItem); public const int MF_BYCOMMAND = 0; public const int MF_STRING = 0; public const int MF_BYPOSITION = 0x400; public const int MF_SEPARATOR = 0x800; private const uint SC_ABOUT = 0x0001; public const int WM_SYSCOMMAND = 0x0112; private void Form1_Load(object sender, EventArgs e) { IntPtr vMenuHandle = GetSystemMenu(Handle, false); InsertMenu(vMenuHandle, 255, MF_STRING, SC_ABOUT, "About... "); } protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_SYSCOMMAND: if ((uint)m.WParam == SC_ABOUT) { MessageBox.Show( "Zswang 路过! "); } break; } base.WndProc(ref m); }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值