65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 中的透明阴影(GDI+ 和 Windows Forms)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.09/5 (17投票s)

2007年6月18日

CPOL

3分钟阅读

viewsIcon

98999

downloadIcon

4844

如何在 C# 中使用 GDI+ 创建带有透明阴影效果的面板。

Screenshot - dropshadow.png

引言

我必须为我正在开发的一个项目创建类似 Windows 应用程序中使用的透明模糊阴影。也想拥有它们吗?那就继续阅读吧!(或者直接下载源码)。

背景

不幸的是,Visual Studio 2005/WinForms 根本不支持这些阴影效果(WPF 中支持!)。幸运的是,我只需要带有阴影的面板。而且矩形形状的阴影很容易。我只是把我用于网页的方法应用到了 WinForms 中。

诀窍如下。通过策略性地放置和倾斜阴影的图片,我们可以模拟一个阴影。当使用透明的 .PNG 时,它看起来就像真的一样。

我们需要的图像部分在下面用红色标出

Sample Image

通常,我会从创建这些图像开始。幸运的是,我实际上已经做了,并且我提供了源码。是时候开始编码了!

项目

文件 > 新建 > 项目,然后选择类库。将其命名为 ShadowPanel,然后单击“确定”。现在将 class1.cs 重命名为 ShadowPanel.cs。这就是我们将要使用的文件。

创建一个测试项目总是很方便的。因此,右键单击解决方案资源管理器中的解决方案,然后选择添加 > 新建项目。这次选择 Windows 应用程序,并将其命名为 ShadowPanelTest。

属性

首先,我们需要一些属性。至少提供边框和背景颜色会很好。是时候打开 ShadowPanel.cs 并添加以下内容了

using System;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;         

namespace ShadowPanel
{
    public class ShadowPanel : Panel
    {
        private Color _panelColor;         

        public Color PanelColor
        {
            get { return _panelColor; }
            set { _panelColor = value; }
        }         

        private Color _borderColor;         

        public Color BorderColor
        {
            get { return _borderColor; }
            set { _borderColor = value; }
        }

我们不能使用原始的面板 BackgroundColor 属性,因为它是用于整个面板的,包括阴影区域!因此,我创建了一个 PanelColor 属性,用于定义阴影内部区域的颜色。

关于对 System.DrawingSystem.Drawing.Drawing2D 的引用。您可能需要手动添加它们,方法是在解决方案资源管理器中右键单击“引用”,然后在列表中选择它们。

图像

现在是我们可以用来实际绘制阴影的图像。如果您尚未这样做,可以从源代码下载它们。在项目中创建一个名为“Images”的文件夹,然后添加 tshadowXXXX.png 文件。在解决方案资源管理器中选择它们,并将“生成操作”更改为“嵌入的资源”。这样,这些文件将被编译到 .dll 中,您无需将它们与应用程序一起分发。

我将图像作为静态添加到代码中(感谢 Remco Schrijvers 的建议)。我还添加了两个私有成员来描述图像的大小(它们是 5X5 像素的图像)以及阴影从左上方的偏移量(边距)。请将以下代码添加到 ShadowPanel

private int shadowSize = 5;
private int shadowMargin = 2;

// static for good performance
static Image shadowDownRight = new Bitmap(typeof(ShadowPanel), "Images.tshadowdownright.png");
static Image shadowDownLeft = new Bitmap(typeof(ShadowPanel), "Images.tshadowdownleft.png");
static Image shadowDown = new Bitmap(typeof(ShadowPanel), "Images.tshadowdown.png");
static Image shadowRight = new Bitmap(typeof(ShadowPanel), "Images.tshadowright.png");
static Image shadowTopRight = new Bitmap(typeof(ShadowPanel), "Images.tshadowtopright.png");

OnPaint()

一切都已准备好让我们做很酷的事情。创建 GDI+ 绘图代码!让我们覆盖 Panel 基类的 OnPaint 方法

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    // Get the graphics object. We need something to draw with  
    Graphics g = e.Graphics;

首先,我们将绘制底部和右侧的平铺图像

Sample Image

我认为代码说明了一切。只需在 Graphics.g = e.Graphics; 之后添加

// Create tiled brushes for the shadow on the right and at the bottom.
TextureBrush shadowRightBrush = new TextureBrush(shadowRight, WrapMode.Tile);
TextureBrush shadowDownBrush = new TextureBrush(shadowDown, WrapMode.Tile);   

// Translate (move) the brushes so the top or left of the image matches the top or left of the
// area where it's drawed. If you don't understand why this is necessary, comment it out. 
// Hint: The tiling would start at 0,0 of the control, so the shadows will be offset a little.
shadowDownBrush.TranslateTransform(0, Height - shadowSize);
shadowRightBrush.TranslateTransform(Width - shadowSize, 0);   

// Define the rectangles that will be filled with the brush.
// (where the shadow is drawn)
Rectangle shadowDownRectangle = new Rectangle(
    shadowSize + shadowMargin,                      // X
    Height - shadowSize,                            // Y
    Width - (shadowSize * 2 + shadowMargin),        // width (stretches)
    shadowSize                                      // height
    );

Rectangle shadowRightRectangle = new Rectangle(
    Width - shadowSize,                             // X
    shadowSize + shadowMargin,                      // Y
    shadowSize,                                     // width
    Height - (shadowSize * 2 + shadowMargin)        // height (stretches)
    );

// And draw the shadow on the right and at the bottom.
g.FillRectangle(shadowDownBrush, shadowDownRectangle);
g.FillRectangle(shadowRightBrush, shadowRightRectangle);

您可以通过打开 Form1.cs 设计器将 ShadowPanel 添加到测试项目。如果构建一次项目,ShadowPanel 应该会出现在工具箱中。只需将其拖到窗体上并运行它。您将(希望)获得以下结果

Sample Image

顺便说一句,我将窗体的背景颜色设置为白色,因此对您来说看起来可能会有所不同。

引入角

要绘制角落中的小位图,只需添加以下内容

// Now for the corners, draw the 3 5X5 pixel images.
g.DrawImage(shadowTopRight, new Rectangle(Width - shadowSize, 
            shadowMargin, shadowSize, shadowSize));
g.DrawImage(shadowDownRight, new Rectangle(Width - shadowSize, 
            Height - shadowSize, shadowSize, shadowSize));
g.DrawImage(shadowDownLeft, new Rectangle(shadowMargin, 
            Height - shadowSize, shadowSize, shadowSize));

几乎太容易了。

填充和边框

我们已经有了 PanelColorBorderColor 属性。现在是时候使用它们了。

// Fill the area inside with the color in the PanelColor property.
// 1 pixel is added to everything to make the rectangle smaller. 
// This is because the 1 pixel border is actually drawn outside the rectangle.
 Rectangle fullRectangle = new Rectangle(
    1,                                              // X
    1,                                              // Y
    Width - (shadowSize + 2),                       // Width
    Height - (shadowSize + 2)                       // Height
    );

if (PanelColor != null)
{
    SolidBrush bgBrush = new SolidBrush(_panelColor);
    g.FillRectangle(bgBrush, fullRectangle);
} 

// Draw a nice 1 pixel border it a BorderColor is specified
if (_borderColor != null)
{
    Pen borderPen = new Pen(BorderColor);
    g.DrawRectangle(borderPen, fullRectangle);
}

是时候检查我们到目前为止的结果了

Sample Image

好了,差不多就是这样了。我们快完成了。

总结

只是一个形式,用以下内容结束 OnPaint 方法

            // Memory efficiency
            shadowDownBrush.Dispose();
            shadowRightBrush.Dispose(); 

            shadowDownBrush = null;
            shadowRightBrush = null;
        }
    }
}

完成!

关注点

当然,我不会阻止您添加更多功能。请做!如果您喜欢本教程,请告诉我!

历史

  • 2007 年 6 月 17 日 - 第一个版本。
© . All rights reserved.