当前位置:   article > 正文

C# Winform 窗体美化(三、不规则窗体)_winform外边框美化

winform外边框美化

三、不规则窗体

概况

之前学习的 LayeredSkin 看到里面有个异形窗口,比较感兴趣,所以就找一下资料研究一下。不规则窗体学习有一个比较好的例子,叫 GoldFishProject,是一条鱼金鱼在屏幕上游。

不规则窗口示例代码
GoldFishProject 游动金鱼的学习代码

如果没有积分,也可以关注我获取哟~
hi

现学习了两种实现方式:

  1. UpdateLayeredWindow
  2. GraphicsPath
1.UpdateLayeredWindow

这种方式实现的不规则窗口很平滑,没有锯齿,可以带半透明的效果,但是不在响应 paint 方法,绘制不了窗体上的控件,效果图:
不规则窗口

代码如下:

窗体代码:

public partial class UpdateLayeredWindowForm : Form
{
    bool haveHandle = false;//窗体句柄创建完成
    public UpdateLayeredWindowForm()
    {
        InitializeComponent();
    }
    private void UpdateLayeredWindowForm_Load(object sender, EventArgs e)
    {
        FormBorderStyle = FormBorderStyle.None;//取消窗口边框
        SetBits(new Bitmap(BackgroundImage));//设置不规则窗体
        FormMovableEvent();//设置拖动窗体移动
    }
    #region 防止窗体闪屏
    private void InitializeStyles()
    {
        SetStyle(
            ControlStyles.UserPaint |
            ControlStyles.AllPaintingInWmPaint |
            ControlStyles.OptimizedDoubleBuffer |
            ControlStyles.ResizeRedraw |
            ControlStyles.SupportsTransparentBackColor, true);
        SetStyle(ControlStyles.Selectable, false);
        UpdateStyles();
    } 
    #endregion
    #region 句柄创建事件
    protected override void OnHandleCreated(EventArgs e)
    {
        InitializeStyles();//设置窗口样式、双缓冲等
        base.OnHandleCreated(e);
        haveHandle = true;
    } 
    #endregion
    #region 设置窗体样式
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cParms = base.CreateParams;
            cParms.ExStyle |= 0x00080000; // WS_EX_LAYERED
            return cParms;
        }
    } 
    #endregion
    #region 设置不规则窗体
    public void SetBits(Bitmap bitmap)
    {
        if (!haveHandle) return;

        if (!Bitmap.IsCanonicalPixelFormat(bitmap.PixelFormat) || !Bitmap.IsAlphaPixelFormat(bitmap.PixelFormat))
            throw new ApplicationException("The picture must be 32bit picture with alpha channel.");

        IntPtr oldBits = IntPtr.Zero;
        IntPtr screenDC = Win32.GetDC(IntPtr.Zero);
        IntPtr hBitmap = IntPtr.Zero;
        IntPtr memDc = Win32.CreateCompatibleDC(screenDC);

        try
        {
            Win32.Point topLoc = new Win32.Point(Left, Top);
            Win32.Size bitMapSize = new Win32.Size(bitmap.Width, bitmap.Height);
            Win32.BLENDFUNCTION blendFunc = new Win32.BLENDFUNCTION();
            Win32.Point srcLoc = new Win32.Point(0, 0);

            hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
            oldBits = Win32.SelectObject(memDc, hBitmap);

            blendFunc.BlendOp = Win32.AC_SRC_OVER;
            blendFunc.SourceConstantAlpha = 255;//这里设置窗体绘制的透明度
            blendFunc.AlphaFormat = Win32.AC_SRC_ALPHA;
            blendFunc.BlendFlags = 0;

            Win32.UpdateLayeredWindow(Handle, screenDC, ref topLoc, ref bitMapSize, memDc, ref srcLoc, 0, ref blendFunc, Win32.ULW_ALPHA);
        }
        finally
        {
            if (hBitmap != IntPtr.Zero)
            {
                Win32.SelectObject(memDc, oldBits);
                Win32.DeleteObject(hBitmap);
            }
            Win32.ReleaseDC(IntPtr.Zero, screenDC);
            Win32.DeleteDC(memDc);
        }
    } 
    #endregion
    #region 无标题栏的窗口移动
    private Point mouseOffset; //记录鼠标指针的坐标
    private bool isMouseDown = false; //记录鼠标按键是否按下

    /// <summary>
    /// 窗体移动监听绑定
    /// </summary>
    private void FormMovableEvent()
    {
        //窗体移动
        this.MouseDown += new MouseEventHandler(Frm_MouseDown);
        this.MouseMove += new MouseEventHandler(Frm_MouseMove);
        this.MouseUp += new MouseEventHandler(Frm_MouseUp);
    }

    /// <summary>
    /// 窗体按下时
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Frm_MouseDown(object sender, MouseEventArgs e)
    {
        int xOffset;
        int yOffset;
        //点击窗体时,记录鼠标位置,启动移动
        if (e.Button == MouseButtons.Left)
        {
            xOffset = -e.X;
            yOffset = -e.Y;
            mouseOffset = new Point(xOffset, yOffset);
            isMouseDown = true;
        }
    }

    /// <summary>
    /// 窗体移动时
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Frm_MouseMove(object sender, MouseEventArgs e)
    {
        if (isMouseDown)
        {
            //移动的位置计算
            Point mousePos = Control.MousePosition;
            mousePos.Offset(mouseOffset.X, mouseOffset.Y);
            Location = mousePos;
        }
    }

    /// <summary>
    /// 窗体按下并释放按钮时
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Frm_MouseUp(object sender, MouseEventArgs e)
    {
        // 修改鼠标状态isMouseDown的值
        // 确保只有鼠标左键按下并移动时,才移动窗体
        if (e.Button == MouseButtons.Left)
        {
            //松开鼠标时,停止移动
            isMouseDown = false;
            //Top高度小于0的时候,等于0
            if (this.Top < 0)
            {
                this.Top = 0;
            }
        }
    }
    #endregion
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159

Win32API代码:(从金鱼的例子中引用的代码)

//##########################################################################
//★★★★★★★           http://www.cnpopsoft.com           ★★★★★★★
//★★          VB & C# source code and articles for free !!!           ★★
//★★★★★★★                Davidwu                       ★★★★★★★
//##########################################################################

using System;
using System.Runtime.InteropServices;

/// <summary>
/// Wind32API
/// </summary>
internal class Win32
{
    #region 消息
    public const int MF_REMOVE = 0x1000;

    public const int SC_RESTORE = 0xF120; //还原
    public const int SC_MOVE = 0xF010; //移动
    public const int SC_SIZE = 0xF000; //大小
    public const int SC_MINIMIZE = 0xF020; //最小化
    public const int SC_MAXIMIZE = 0xF030; //最大化
    public const int SC_CLOSE = 0xF060; //关闭 

    public const int WM_SYSCOMMAND = 0x0112;
    public const int WM_COMMAND = 0x0111;

    public const int GW_HWNDFIRST = 0;
    public const int GW_HWNDLAST = 1;
    public const int GW_HWNDNEXT = 2;
    public const int GW_HWNDPREV = 3;
    public const int GW_OWNER = 4;
    public const int GW_CHILD = 5;

    public const int WM_NCCALCSIZE = 0x83;
    public const int WM_WINDOWPOSCHANGING = 0x46;
    public const int WM_PAINT = 0xF;
    public const int WM_CREATE = 0x1;
    public const int WM_NCCREATE = 0x81;
    public const int WM_NCPAINT = 0x85;
    public const int WM_PRINT = 0x317;
    public const int WM_DESTROY = 0x2;
    public const int WM_SHOWWINDOW = 0x18;
    public const int WM_SHARED_MENU = 0x1E2;
    public const int HC_ACTION = 0;
    public const int WH_CALLWNDPROC = 4;
    public const int GWL_WNDPROC = -4;

    public const int WS_SYSMENU = 0x80000;
    public const int WS_SIZEBOX = 0x40000;

    public const int WS_MAXIMIZEBOX = 0x10000;

    public const int WS_MINIMIZEBOX = 0x20000;
    #endregion
    [StructLayout(LayoutKind.Sequential)]
    public struct Size
    {
        public Int32 cx;
        public Int32 cy;

        public Size(Int32 x, Int32 y)
        {
            cx = x;
            cy = y;
        }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct BLENDFUNCTION
    {
        public byte BlendOp;
        public byte BlendFlags;
        public byte SourceConstantAlpha;
        public byte AlphaFormat;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct Point
    {
        public Int32 x;
        public Int32 y;

        public Point(Int32 x, Int32 y)
        {
            this.x = x;
            this.y = y;
        }
    }

    public const byte AC_SRC_OVER = 0;
    public const Int32 ULW_ALPHA = 2;
    public const byte AC_SRC_ALPHA = 1;

    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr CreateCompatibleDC(IntPtr hDC);

    [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr GetDC(IntPtr hWnd);

    [DllImport("gdi32.dll", ExactSpelling = true)]
    public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObj);

    [DllImport("user32.dll", ExactSpelling = true)]
    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern int DeleteDC(IntPtr hDC);

    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern int DeleteObject(IntPtr hObj);

    [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern int UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pptSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);

    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr ExtCreateRegion(IntPtr lpXform, uint nCount, IntPtr rgnData);

    [DllImport("user32")]
    public static extern int SendMessage(IntPtr hwnd, int msg, int wp, int lp);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
2.GraphicsPath

这种方式不能实现半透明效果,有锯齿,好处是能显示出控件,贴个效果图感受下:

删除完全透明区域
只保留不透明区域

代码如下:

public partial class GraphicsPathForm : Form
{
    public GraphicsPathForm()
    {
        InitializeComponent();
    }
    private void GraphicsPathForm_Load(object sender, EventArgs e)
    {
        TopMost = true;//设置为最顶层
        FormBorderStyle = FormBorderStyle.None;//取消窗口边框
        this.Region = new Region(GetWindowRegion(new Bitmap(BackgroundImage)));//设置不规则窗体
        FormMovableEvent();//设置拖动窗体移动
    }
    #region 设置不规则窗体
    private GraphicsPath GetWindowRegion(Bitmap bitmap)
    {
        Color TempColor;
        GraphicsPath gp = new GraphicsPath();
        if (bitmap == null) return null;

        for (int nX = 0; nX < bitmap.Width; nX++)
        {
            for (int nY = 0; nY < bitmap.Height; nY++)
            {
                TempColor = bitmap.GetPixel(nX, nY);
                //if (TempColor.A != 0)//去掉完全透明区域
                if (TempColor.A == 255)//保留完全不透明的区域
                {
                    gp.AddRectangle(new Rectangle(nX, nY, 1, 1));
                }
            }
        }
        return gp;
    } 
    #endregion
    #region 无标题栏的窗口移动
    private Point mouseOffset; //记录鼠标指针的坐标
    private bool isMouseDown = false; //记录鼠标按键是否按下

    /// <summary>
    /// 窗体移动监听绑定
    /// </summary>
    private void FormMovableEvent()
    {
        //窗体移动
        this.MouseDown += new MouseEventHandler(Frm_MouseDown);
        this.MouseMove += new MouseEventHandler(Frm_MouseMove);
        this.MouseUp += new MouseEventHandler(Frm_MouseUp);
    }

    /// <summary>
    /// 窗体按下时
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Frm_MouseDown(object sender, MouseEventArgs e)
    {
        int xOffset;
        int yOffset;
        //点击窗体时,记录鼠标位置,启动移动
        if (e.Button == MouseButtons.Left)
        {
            xOffset = -e.X;
            yOffset = -e.Y;
            mouseOffset = new Point(xOffset, yOffset);
            isMouseDown = true;
        }
    }

    /// <summary>
    /// 窗体移动时
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Frm_MouseMove(object sender, MouseEventArgs e)
    {
        if (isMouseDown)
        {
            //移动的位置计算
            Point mousePos = Control.MousePosition;
            mousePos.Offset(mouseOffset.X, mouseOffset.Y);
            Location = mousePos;
        }
    }

    /// <summary>
    /// 窗体按下并释放按钮时
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Frm_MouseUp(object sender, MouseEventArgs e)
    {
        // 修改鼠标状态isMouseDown的值
        // 确保只有鼠标左键按下并移动时,才移动窗体
        if (e.Button == MouseButtons.Left)
        {
            //松开鼠标时,停止移动
            isMouseDown = false;
            //Top高度小于0的时候,等于0
            if (this.Top < 0)
            {
                this.Top = 0;
            }
        }
    }
    #endregion
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

像第一种不能添加控件的方法要想实现显示控件的话,下一个关键词就是“双层窗体”,使用两层窗体来实现一个不规则窗体的效果,大致步骤如下:

底层是皮肤层,使用第一种方法;
上层是控件层,使用第二种方法。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/137887
推荐阅读
相关标签
  

闽ICP备14008679号