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 =...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

C# 边框阴影窗体效果

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

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

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

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

C# 系统应用之透明罩MyOpaqueLayer实现360界面阴影效果

在完成“个人电脑使用记录清除软件”中,我设计的winform界面需要应用到类似于"360安全卫士"的透明罩效果,文章主要引述了如何使用自定义组件MyOpaqueLayer,并自定义类OpaqueCom...

在C#中调用系统API使窗体下拥有阴影效果

  2007-12-16 00:09文章来源:http://blog.donews.com/dongshijun//昨天晚上看MSDN看见的一段通过使用SetClassLong函数使窗口下面拥有一个阴...

Delphi7高级应用开发随书源码

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

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