C# WinForm窗体四周阴影效果

原创 2017年09月08日 21:04:43

一、起因

关于winform窗体无边框的问题很简单,只需要设置winform的窗体属性即可:

FormBorderStyle = FormBorderStyle.None;

但是这中无边框窗口实现的效果和背景完全没有层次的感觉,所以能加上阴影,突出窗口显示的感觉。

二、网上搜索的解决方案

方法 1

首先,发现了使用 user32.dll 中方法实现的方案:
C# WinForm无边框窗体设置阴影效果

缺点:这种方法只能实现右边和下边的阴影效果,效果不是很好。

效果如图:
方法一效果图

方法 2

然后发现了使用双层窗体,底层窗体贴阴影的PNG来实现的方式:
教你实现Winform窗体的四边阴影效果

缺点:PNG格式特点是,支持alpha通道半透明,但是放大会失真

效果如图:
方法二效果图

三、最终解决方案

我使用的方法是绘制阴影到bitmap上,然后使用双层窗体的原理把bitmap绘制到背景层上去。

其中比较重要的是:

1、绘制圆角矩形

public static void DrawRoundRectangle(Graphics g, Pen pen, Rectangle rect, int cornerRadius)
{
    using (GraphicsPath path = CreateRoundedRectanglePath(rect, cornerRadius))
    {
        g.DrawPath(pen, path);
    }
}
public static void FillRoundRectangle(Graphics g, Brush brush, Rectangle rect, int cornerRadius)
{
    using (GraphicsPath path = CreateRoundedRectanglePath(rect, cornerRadius))
    {
        g.FillPath(brush, path);
    }
}
internal static GraphicsPath CreateRoundedRectanglePath(Rectangle rect, int cornerRadius)
{
    GraphicsPath roundedRect = new GraphicsPath();
    roundedRect.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
    roundedRect.AddLine(rect.X + cornerRadius, rect.Y, rect.Right - cornerRadius * 2, rect.Y);
    roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
    roundedRect.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height - cornerRadius * 2);
    roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
    roundedRect.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom);
    roundedRect.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
    roundedRect.AddLine(rect.X, rect.Bottom - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2);
    roundedRect.CloseFigure();
    return roundedRect;
}

2、绘制阴影

internal void DrawShadow()
{
    Bitmap bitmap = null;
    Graphics g = null;
    try
    {
        bitmap = new Bitmap(Width, Height);
        g = Graphics.FromImage(bitmap);
        g.SmoothingMode = SmoothingMode.AntiAlias;

        Color c = Color.FromArgb(0, 0, 0, 0);
        Pen p = new Pen(c, 3);

        for (int i = 0; i < Main.ShadowWidth; i++)
        {
            p.Color = Color.FromArgb((255 / 10 / Main.ShadowWidth) * i, c);
            DrawRoundRectangle(g, p, new Rectangle(i, i, Width - (2 * i) - 1, Height - (2 * i) - 1), Main.ShadowWidth - i);
        }
        SetBits(bitmap);
    }
    catch { }
    finally
    {
        g?.Dispose();
        bitmap?.Dispose();
    }
}

3、绘制半透明bitmap到窗口上

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cParms = base.CreateParams;
        cParms.ExStyle |= 0x00080000; // WS_EX_LAYERED
        return cParms;
    }
}
public void SetBits(Bitmap bitmap)
{
    if (!Image.IsCanonicalPixelFormat(bitmap.PixelFormat) || !Image.IsAlphaPixelFormat(bitmap.PixelFormat))
        throw new ApplicationException("图片必须是32位带Alhpa通道的图片。");
    IntPtr oldBits = IntPtr.Zero;
    IntPtr screenDC = FormStyleAPI.GetDC(IntPtr.Zero);
    IntPtr hBitmap = IntPtr.Zero;
    IntPtr memDc = FormStyleAPI.CreateCompatibleDC(screenDC);

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

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

        blendFunc.BlendOp = FormStyleAPI.AC_SRC_OVER;
        blendFunc.SourceConstantAlpha = Byte.Parse(((int)(Main.Opacity * 255)).ToString());
        blendFunc.AlphaFormat = FormStyleAPI.AC_SRC_ALPHA;
        blendFunc.BlendFlags = 0;

        FormStyleAPI.UpdateLayeredWindow(Handle, screenDC, ref topLoc, ref bitMapSize, memDc, ref srcLoc, 0, ref blendFunc, FormStyleAPI.ULW_ALPHA);
    }
    finally
    {
        if (hBitmap != IntPtr.Zero)
        {
            FormStyleAPI.SelectObject(memDc, oldBits);
            FormStyleAPI.DeleteObject(hBitmap);
        }
        FormStyleAPI.ReleaseDC(IntPtr.Zero, screenDC);
        FormStyleAPI.DeleteDC(memDc);
    }
}

四、最终方案的效果和源码

源码下载

效果图

版权声明:本文为博主原创文章,未经博主允许不得转载。

C# WinForm无边框窗体设置阴影效果

1、添加引用 using System.Runtime.InteropServices; 2、定义常量值及函数 private const int CS_DropSHADOW =...
  • C_S_D_N_USER
  • C_S_D_N_USER
  • 2015年04月18日 11:48
  • 4776

无边框窗体Winform四周阴影效果C#完美实现

  • 2014年04月25日 15:56
  • 5.83MB
  • 下载

C# 边框阴影窗体效果

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy...
  • yanjiaye520
  • yanjiaye520
  • 2010年12月23日 12:33
  • 4881

教你实现Winform窗体的四边阴影效果

本文转载于CSKIN论坛,地址:http://bbs.cskin.net/thread-61-1-1.html
  • Joyhen
  • Joyhen
  • 2014年11月01日 01:41
  • 4847

C#WinForm窗体四周阴影效果

  • 2017年09月08日 15:31
  • 73KB
  • 下载

实现窗体阴影效果

  • 2016年01月08日 15:52
  • 306KB
  • 下载

无边框窗体Winform四周阴影效果C#实现

  • 2013年08月06日 16:05
  • 2.13MB
  • 下载

c# winform 带阴影的panel vs2008

  • 2011年09月24日 16:01
  • 100KB
  • 下载

C#版可调节的文字阴影特效

        本来春节前不准备写BLOG文章了,可前几天有几个搞C#的朋友来信说,对文章《GDI+ 在Delphi程序的应用 -- 可调节的文字阴影特效》的内容很感兴趣,但苦于对Delphi不熟悉,...
  • maozefa
  • maozefa
  • 2008年01月15日 00:13
  • 7826

C# 实现panel 控件的阴影效果

  • 2009年06月30日 17:07
  • 100KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C# WinForm窗体四周阴影效果
举报原因:
原因补充:

(最多只允许输入30个字)