1. 放肆雷特 - 锋哥的博客首页
  2. 程序生涯
  3. .NET

C#制作高仿360安全卫士窗体(二)- 普通按钮

继上次C#制作高仿360安全卫士窗体<一>发布之后响应还不错,我的博客放肆雷特也来了不少的新朋友,在这里先谢谢大家的支持!我自己也反复看了一下觉得对不起大家,写的非常乱而且很少文字介绍。在这里先说明一下,我是一个纯粹想搞技术的,文笔较差。我也想锻炼自己所以才会慢慢的将自己的所学分享出来。一来可以锻炼自己的文笔,二来可以分享知识留给像我一样喜欢这些东西的朋友。所以以后如果缺少介绍和说明,请大家多多补充指正,相互提高。下面进入主题。
上一篇主要讲的如何绘制一个按钮,那么今天讲解如何绘制窗体。之前也说过,先制作按钮的作用是可以将按钮用到窗体上面那些系统按钮如最大化、最小化、关闭、还原等。首先我们对按钮的不同状态的图片进行提取,在上一篇提出来皮肤文件之后,将按钮的文件sys_button_max.png,sys_button_min.png,sys_button_close.png,sys_button_max.png,sys_button_restore.png这几个图片文件进行提取。在这里说明,可以直接使用,也可以自己进行加工。以下是我加工过的(如果需要可以直接右键另存为)

一、嵌入资源
图片素材准备好之后在解决方案中Images目录里面建立一个FormImages文件夹,将图片素材拷贝进去,并设置图片属性中生成操作选择为“嵌入的资源”。
二、创建窗体
资源嵌入之后再在ControlEx目录中建立一个FormEx文件夹,在该文件夹下创建一个名为BaseForm的窗体。该窗体需要修改的选项很少,大部分可以使用代码来解决。窗体创建完毕后,将创建好的ButtonEx拖进窗体,这里需要拖放5个。为了使内容更好看,还拖一个Panel进来。摆放的位置可以随意,后期通过代码控制,但是为了便于开发我摆放为如下:

BaseForm窗体初始状态

三、编码
控件摆放完了之后就可以开始编码了,窗体编码主要难度在于消息的处理还有一个比较麻烦一点的是窗体中不同状态下按钮的位置处理,我直接上代码不懂的留言询问我再详细解答:

1、变量申明

#region 声明
private int Rgn;
private Graphics g;
private bool _IsResize = true;//是否允许改变窗口大小
private FormSystemBtn _FormSystemBtnSet = FormSystemBtn.SystemAll;
private Bitmap btn_closeImg = ImageObject.GetResBitmap("FANGSI.UI.Images.FormImages.btn_close.png");
private Bitmap btn_maxImg = ImageObject.GetResBitmap("FANGSI.UI.Images.FormImages.btn_max.png");
private Bitmap btn_miniImg = ImageObject.GetResBitmap("FANGSI.UI.Images.FormImages.btn_mini.png");
private Bitmap btn_restoreImg = ImageObject.GetResBitmap("FANGSI.UI.Images.FormImages.btn_restore.png");
private Bitmap _BackImg = ImageObject.GetResBitmap("FANGSI.UI.Images.FormImages.background_mainwnd.jpg");
private Size oldSize;//记录当前窗口大小
private bool _MaximizeBox = true;//是否启用最大化按钮
private int _TopHeight = 100;//窗体头部高度
//枚举系统按钮状态
public enum FormSystemBtn
{
    SystemAll = 0,
    SystemNo = 1,
    btn_close = 2,
    btn_miniAndbtn_close = 3,
    btn_maxAndbtn_close = 4
}
#endregion

2、构建方法,主要将窗体消息的处理以及按钮位置等信息进行设置

#region 方法
protected void SystemBtnSet()
{
    int btnTop = 0;
    int btnRight = 6;
    int panelMargin = 2;
    if (WindowState == FormWindowState.Maximized &amp;&amp; FormBorderStyle != System.Windows.Forms.FormBorderStyle.None)
    {
        btnTop = 10;
        btnRight = 16;
        panelMargin = 10;
    }
    this.ContentPanel.Location = new Point(panelMargin, _TopHeight);
    this.ContentPanel.Size = new Size(ClientRectangle.Width - (panelMargin * 2), ClientRectangle.Height - _TopHeight - panelMargin);

    switch ((int)_FormSystemBtnSet)
    {
        case 0:
            btn_close.BackImg = btn_closeImg;
            btn_close.Location = new Point(this.Width - 32, btnTop);
            btn_mini.BackImg = btn_miniImg;
            btn_mini.Location = new Point(this.Width - 86, btnTop);
            btn_max.BackImg = btn_maxImg;
            btn_restore.BackImg = btn_restoreImg;
            if (WindowState == FormWindowState.Normal)
            {
                btn_max.Location = new Point(this.Width - 59, btnTop);
                btn_restore.Location = new Point(this.Width - 59, -22);
            }
            else
            {
                btn_max.Location = new Point(this.Width - 59, -22);
                btn_restore.Location = new Point(this.Width - 59, btnTop);
            }
            break;
        case 1:
            btn_close.BackImg = btn_closeImg;
            btn_close.Location = new Point(this.Width - 32, -22);
            btn_max.BackImg = btn_maxImg;
            btn_max.Location = new Point(this.Width - 59, -22);
            btn_mini.BackImg = btn_miniImg;
            btn_mini.Location = new Point(this.Width - 86, -22);
            btn_restore.BackImg = btn_restoreImg;
            btn_restore.Location = new Point(this.Width - 59, -22);
            break;
        case 2:
            btn_close.BackImg = btn_closeImg;
            btn_close.Location = new Point(this.Width - 32, btnTop);
            btn_max.BackImg = btn_maxImg;
            btn_max.Location = new Point(this.Width - 59, -22);
            btn_mini.BackImg = btn_miniImg;
            btn_mini.Location = new Point(this.Width - 86, -22);
            btn_restore.BackImg = btn_restoreImg;
            btn_restore.Location = new Point(this.Width - 59, -22);
            break;
        case 3:
            btn_close.BackImg = btn_closeImg;
            btn_close.Location = new Point(this.Width - 32, btnTop);
            btn_max.BackImg = btn_maxImg;
            btn_max.Location = new Point(this.Width - 59, -22);
            btn_mini.BackImg = btn_miniImg;
            btn_mini.Location = new Point(this.Width - 59, 0);
            btn_restore.BackImg = btn_restoreImg;
            btn_restore.Location = new Point(this.Width - 59, -22);
            break;
        case 4:
            btn_close.BackImg = btn_closeImg;
            btn_close.Location = new Point(this.Width - 32, btnTop);
            btn_mini.BackImg = btn_miniImg;
            btn_mini.Location = new Point(this.Width - 86, -22);
            btn_max.BackImg = btn_maxImg;
            btn_restore.BackImg = btn_restoreImg;
            if (WindowState == FormWindowState.Normal)
            {
                btn_max.Location = new Point(this.Width - 59, btnTop);
                btn_restore.Location = new Point(this.Width - 59, -22);
            }
            else
            {
                btn_max.Location = new Point(this.Width - 59, -22);
                btn_restore.Location = new Point(this.Width - 59, btnTop);
            }
            break;
    }
}

private void WM_NCHITTEST(ref Message m)
{
    int wparam = m.LParam.ToInt32();
    Point point = new Point(Win32.LOWORD(wparam), Win32.HIWORD(wparam));
    point = PointToClient(point);
    if (_IsResize)
    {
        if (point.X &lt;= 8)
        {
            if (point.Y &lt;= 8)                 m.Result = (IntPtr)Win32.HTTOPLEFT;             else if (point.Y &gt; Height - 8)
                m.Result = (IntPtr)Win32.HTBOTTOMLEFT;
            else
                m.Result = (IntPtr)Win32.HTLEFT;
        }
        else if (point.X &gt;= Width - 8)
        {
            if (point.Y &lt;= 8)                 m.Result = (IntPtr)Win32.HTTOPRIGHT;             else if (point.Y &gt;= Height - 8)
                m.Result = (IntPtr)Win32.HTBOTTOMRIGHT;
            else
                m.Result = (IntPtr)Win32.HTRIGHT;
        }
        else if (point.Y &lt;= 8)         {             m.Result = (IntPtr)Win32.HTTOP;         }         else if (point.Y &gt;= Height - 8)
            m.Result = (IntPtr)Win32.HTBOTTOM;
        else
            m.Result = (IntPtr)Win32.HTCAPTION;
    }
    else
    { m.Result = (IntPtr)Win32.HTCAPTION; }
}

private void btn_close_Click(object sender, EventArgs e)
{
    this.Close();
}

private void btn_mini_Click(object sender, EventArgs e)
{
    Win32.PostMessage(base.Handle, Win32.WM_SYSCOMMAND, Win32.SC_MINIMIZE, 0);
}

private void btn_max_Click(object sender, EventArgs e)
{
    Win32.PostMessage(base.Handle, Win32.WM_SYSCOMMAND, Win32.SC_MAXIMIZE, 0);
}

private void btn_restore_Click(object sender, EventArgs e)
{
    Win32.PostMessage(base.Handle, Win32.WM_SYSCOMMAND, Win32.SC_RESTORE, 0);
}

private void btn_close_MouseEnter(object sender, EventArgs e)
{
    toolTip1.SetToolTip(btn_close, "关闭");
}

private void btn_max_MouseEnter(object sender, EventArgs e)
{
    toolTip1.SetToolTip(btn_max, "最大化");
}

private void btn_mini_MouseEnter(object sender, EventArgs e)
{
    toolTip1.SetToolTip(btn_mini, "最小化");
}

private void btn_restore_MouseEnter(object sender, EventArgs e)
{
    toolTip1.SetToolTip(btn_restore, "还原");
}
#endregion

3、属性定义以及方法重写,将扩展属性和窗体重绘等方法结合上一篇的基础类库进行处理

#region 重写方法
protected override void OnInvalidated(InvalidateEventArgs e)
{
    base.OnInvalidated(e);
}

//重绘窗口
protected override void OnPaint(PaintEventArgs e)
{
    try
    {
        g = e.Graphics;
        g.SmoothingMode = SmoothingMode.HighQuality; //高质量
        g.PixelOffsetMode = PixelOffsetMode.HighQuality; //高像素偏移质量
        ImageDrawRect.DrawRect(g, ClientRectangle, base.BackColor, _TopHeight);//绘制白色内容区域
        Brush brush = new SolidBrush(Color.White);//定义画笔
        PointF point = new PointF(10, 10);//定义标题显示坐标
        Font TitleFont = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
        g.DrawString(base.Text, TitleFont, brush, point.X, point.Y);

    }
    catch
    { }
}

//重载WndProc方法
protected override void WndProc(ref Message m)
{
    try
    {
        switch (m.Msg)
        {
            //用户选择最大化按钮,最小化按钮,复原按钮或关闭按钮时,窗口将会接收该消息
            case Win32.WM_SYSCOMMAND:
                #region
                if ((m.WParam != (IntPtr)Win32.SC_MAXIMIZE) &amp;&amp; (m.WParam.ToInt32() != 0xf032))
                {
                    if ((m.WParam == (IntPtr)Win32.SC_RESTORE) || (m.WParam.ToInt32() == 0xf122))
                    {
                        base.Size = this.oldSize;
                    }
                    else if ((m.WParam == (IntPtr)Win32.SC_MINIMIZE) || (m.WParam.ToInt32() == 0xf022))
                    {
                        if (this.oldSize.Width == 0)
                        {
                            this.oldSize = base.Size;
                        }
                    }
                    break;
                }
                this.oldSize = base.Size;

                #endregion
                break;
            //在需要计算窗口客户区的大小和位置时发送。通过处理这个消息,应用程序可以在窗口大小或位置改变时控制客户区的内容
            case Win32.WM_NCCALCSIZE:
            //窗体客户区以外的重绘消息,一般是由系统负责处理
            case Win32.WM_NCPAINT:
                return;
            //鼠标移动,按下或释放都会执行该消息
            case Win32.WM_NCHITTEST:
                WM_NCHITTEST(ref m);
                return;
            //画窗体被激活或者没有被激活时的样子
            case Win32.WM_NCACTIVATE:
                #region
                if (m.WParam == (IntPtr)Win32.WM_FALSE)
                {
                    m.Result = (IntPtr)Win32.WM_TRUE;
                }
                #endregion
                return;
            default:
                base.WndProc(ref m);
                return;
        }
        base.WndProc(ref m);
    }
    catch { }
}

private void BaseForm_Resize(object sender, EventArgs e)
{
    SystemBtnSet();
}

protected override void OnResizeEnd(EventArgs e)
{
    base.OnResizeEnd(e);
    this.oldSize = base.Size;
}

///
/// 重写标题属性
///
public override string Text
{
    set
    {
        if (value != base.Text)
        {
            base.Text = value;
            this.Invalidate();
        }
    }
    get
    {
        return base.Text;
    }
}
#endregion

3、窗体属性的定义

#region 属性

[DefaultValue(true)]
[CategoryAttribute("放肆雷特皮肤扩展属性"), Description("是否允许改变窗口大小")]
public bool IsResize
{
    get { return this._IsResize; }
    set { _IsResize = value; }
}

[DefaultValue(true)]
[CategoryAttribute("放肆雷特皮肤扩展属性"), Description("是否在右上角显示最大化按钮")]
public new bool MaximizeBox
{
    get
    {
        return base.MaximizeBox;
    }
    set
    {
        base.MaximizeBox = value; this.btn_max.Enabled = value;
    }
}

[CategoryAttribute("放肆雷特皮肤扩展属性"), Description("系统按钮设置")]
public FormSystemBtn FormSystemBtnSet
{
    get
    {
        return _FormSystemBtnSet;
    }
    set
    {
        _FormSystemBtnSet = value;
        this.Invalidate();

    }
}

[CategoryAttribute("放肆雷特皮肤扩展属性"), Description("获取或设置窗体图标")]
public new Icon Icon
{
    get
    {
        return base.Icon;
    }
    set
    {
        if (value != base.Icon)
        {
            base.Icon = value;
            this.Invalidate();
        }

    }
}

[CategoryAttribute("放肆雷特皮肤扩展属性"), Description("获取或设置窗体头部高度"), DefaultValue(100)]
public new int TopHeight
{
    get
    {
        return _TopHeight;
    }
    set
    {
        _TopHeight = value;
        this.Invalidate();

    }
}
#endregion

4、窗体构造函数中窗体样式以及动作进行初始化设置

#region 构造函数
public BaseForm()
{
    InitializeComponent();
    this.SetStyle(ControlStyles.UserPaint, true);//自绘
    this.SetStyle(ControlStyles.DoubleBuffer, true);// 双缓冲
    this.SetStyle(ControlStyles.ResizeRedraw, true);//调整大小时重绘
    this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
    this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);// 双缓冲
    this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);   //透明效果
    if (this.BackgroundImage == null)
    {
        this.BackgroundImage = _BackImg;
    }
    SystemBtnSet();
}
#endregion

使用的时候只需要在窗体中继承这个窗体就可以使用窗体的风格了!下面是效果图:
窗体预览
进行到这里窗体和按钮结合的窗体就已经出来了,中间的背景图片是从360安全卫士提取出来的资源中拿到的。如果还有不懂的欢迎进行留言提问。下一篇就开始将文本框的制作敬请期待喔。。

原创文章,作者:锋哥,如若转载,请注明出处:https://www.fangsi.net/435.html

发表评论

登录后才能评论

评论列表(8条)

  • 徐萌萌
    徐萌萌 2014年12月12日 11:22

    需要学习的东西好多撒

  • 没头脑
    没头脑 2014年3月21日 10:27

    必须支持!

  • 新新手
    新新手 2013年8月7日 13:21

    学习下,一直在搞winform,但一直都只关注业务逻辑,页面基本就是几个控件在那里放着。。。。谢谢楼主的知识分享,顶一下

    • 胖子
      锋哥 回复 新新手 2013年8月7日 21:39

      其实关注业务逻辑是最基本的,然后如果想让用户体验度更好,用户黏度增加除了把业务逻辑精简还需要设计出比较友好的界面与易用性的操作方式。一起学习吧!

  • fonlan
    fonlan 2013年8月6日 13:14

    我想知道有没有办法仿Chrome的多标签界面

    • 胖子
      锋哥 回复 fonlan 2013年8月6日 13:37

      应该是可以的,不过我没有研究过。改天有时间研究一下。

联系我们

在线咨询:点击这里给我发消息

邮件:service@fangsi.net

工作时间:周一至周五,9:30-18:30,节假日休息