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






4.09/5 (17投票s)
如何在 C# 中使用 GDI+ 创建带有透明阴影效果的面板。
引言
我必须为我正在开发的一个项目创建类似 Windows 应用程序中使用的透明模糊阴影。也想拥有它们吗?那就继续阅读吧!(或者直接下载源码)。
背景
不幸的是,Visual Studio 2005/WinForms 根本不支持这些阴影效果(WPF 中支持!)。幸运的是,我只需要带有阴影的面板。而且矩形形状的阴影很容易。我只是把我用于网页的方法应用到了 WinForms 中。
诀窍如下。通过策略性地放置和倾斜阴影的图片,我们可以模拟一个阴影。当使用透明的 .PNG 时,它看起来就像真的一样。
我们需要的图像部分在下面用红色标出
通常,我会从创建这些图像开始。幸运的是,我实际上已经做了,并且我提供了源码。是时候开始编码了!
项目
文件 > 新建 > 项目,然后选择类库。将其命名为 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.Drawing
和 System.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;
首先,我们将绘制底部和右侧的平铺图像
我认为代码说明了一切。只需在 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
应该会出现在工具箱中。只需将其拖到窗体上并运行它。您将(希望)获得以下结果
顺便说一句,我将窗体的背景颜色设置为白色,因此对您来说看起来可能会有所不同。
引入角
要绘制角落中的小位图,只需添加以下内容
// 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));
几乎太容易了。
填充和边框
我们已经有了 PanelColor
和 BorderColor
属性。现在是时候使用它们了。
// 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);
}
是时候检查我们到目前为止的结果了
好了,差不多就是这样了。我们快完成了。
总结
只是一个形式,用以下内容结束 OnPaint
方法
// Memory efficiency
shadowDownBrush.Dispose();
shadowRightBrush.Dispose();
shadowDownBrush = null;
shadowRightBrush = null;
}
}
}
完成!
关注点
当然,我不会阻止您添加更多功能。请做!如果您喜欢本教程,请告诉我!
历史
- 2007 年 6 月 17 日 - 第一个版本。