一个简单的 AquaButton






4.57/5 (39投票s)
2005年11月27日
6分钟阅读

207931

4603
一个关于如何使用一些GDI+方法来创建一个简单的Aqua按钮的示例。
引言
这篇文章的主要目的是向您展示如何使用一些GDI+方法来创建Aqua按钮。我之所以想分享这段代码,是因为我曾经花了好长时间在网上搜索关于如何创建Aqua按钮的文章,而我找到的所有文章都依赖于对预先存在的位图的操纵,而不是动态创建按钮。
关于代码
这里提供的代码基本上是一个名为AquaButton
的类。这个类相当简单,我相信还有很多可以改进的地方使其更加健壮。请记住,这篇文章的主要目的是介绍我用来创建Aqua按钮所需特殊效果的GDI+方法。
AquaButton 代码
长时间观察了几个Aqua按钮后,我观察到它们由三部分组成:从按钮的主颜色到白色的线性颜色变化,一个阴影,以及一个气泡效果。所有这些都可以通过类轻松实现,例如LinearGradientBrush
来创建按钮颜色到白色的渐变,PathGradientBrush
来创建阴影效果,然后为了创建气泡,只需调整按钮上方气泡的透明度即可。
按钮的主颜色
为了创建按钮的主颜色,我们可以使用LinearGradientBrush
,如下面的代码所示。
Rectangle rc = new Rectangle(btnOffset,btnOffset,
this.ClientSize.Width-8-btnOffset,
this.ClientSize.Height-8-btnOffset);
GraphicsPath path1 = this.GetPath(rc, 20);
LinearGradientBrush br1 = new LinearGradientBrush(new Point(0, 0),
new Point(0, rc.Height+2), clr, Color.White);
让我们更仔细地看看第三行代码。这一行创建了一个线性渐变,从指定的背景色向白色过渡。请注意,我将第二个点指定在了形状的外部(rc.Height + 2
)。这样做的原因是防止颜色完全变为白色。以下是创建的图像的示例:
按钮的阴影
阴影可以使用PathGradientBrush
创建,它具有与按钮相同的形状,但稍微偏移了一个角度。
Rectangle rc2 = rc;
rc2.Offset(shadowOffset, shadowOffset);
GraphicsPath path2 = this.GetPath(rc2, 20);
PathGradientBrush br2 = new PathGradientBrush(path2);
br2.CenterColor = ControlPaint.DarkDark(Color.Silver);
br2.SurroundColors = new Color[]{Color.White};
在这种情况下,PathGradientBrush
很有帮助,因为它有助于从深银色到白色创建环绕渐变。以下是创建的图像的示例:
请注意,在这个示例中,窗体的背景是白色,所以向白色的渐变非常完美。如果您使用此示例代码,最好先找出父控件的背景色,然后创建一个从父控件的DarkDark
颜色到父控件相同颜色的渐变。
气泡效果
要创建气泡效果,您也可以使用LinearGradientPath
;但是,这次我们不操纵颜色渐变,而是操纵透明度渐变。我说的透明度是什么意思?透明度是Alpha参数,您可以在使用Color.FromArgb()
方法创建颜色时指定它。此方法的一个参数是Alpha参数。当此参数设置为255时,表示颜色是纯色,完全不透明。当您降低此参数时,创建的颜色会变得越来越透明。让我们看看代码,了解如何使用这种效果:
Rectangle rc3 = rc;
rc3.Inflate(-5, -5);
rc3.Height = 15;
GraphicsPath path3 = GetPath(rc3, 20);
LinearGradientBrush br3 =
new LinearGradientBrush(rc3, Color.FromArgb(255, Color.White),
Color.FromArgb(0, Color.White), LinearGradientMode.Vertical);
第五行代码创建一个从白色(Color.FromArgb(255, Color.White)
)到透明(Color.FromArgb(0, Color.White)
)的线性渐变。请注意,Alpha参数从255(不透明)设置为0(完全透明)。
文本描边
最后,按钮显示了不同类型的字体。在这种情况下,我使用了文本的轮廓来为按钮创建不同的文本样式。轮廓是使用GraphicsPath
创建的。此类自动创建显示字符串轮廓所需的点数组。此类在您想要创建更好看的字符串时非常有用。您可以填充路径的内部,也可以为其赋予与上面描述的按钮相同的阴影效果。以下是创建带轮廓文本的最有用的几行代码:
GraphicsPath path4 = new GraphicsPath();
path4.AddString(this.Text, this.Font.FontFamily,
(int)this.Font.Style, this.Font.Size,
rcText, strformat);
Pen txtPen = new Pen(this.ForeColor, 1);
g.DrawPath(txtPen, path4);
一旦您创建了路径(上面显示为path4.AddString
),您可以按照上面所示,使用DrawPath
绘制路径的轮廓,或者用任何类型的画笔填充路径的内部,为您的文本添加一些额外的特殊效果。例如,您可以使用纹理画笔、多色渐变画笔等。
脉冲效果
ByteGhost
提醒我一个很好的建议,就是如何为Aqua按钮添加脉冲效果的功能。我还参考了Dave Peckham的文章,以获得关于脉冲工作原理的好主意。基本上,它是一个平滑的亮度的上下变化。可以通过位图上的Gamma参数来控制亮度。因此,为了实现此功能,我们只需要将按钮存储在Bitmap
对象中,如下所示:
buttonBitmapRectangle = new Rectangle(rc.Location, rc.Size);
buttonBitmap = new Bitmap(buttonBitmapRectangle.Width,
buttonBitmapRectangle.Height);
Graphics g_bmp = Graphics.FromImage(buttonBitmap);
g_bmp.SmoothingMode = SmoothingMode.AntiAlias;
g_bmp.FillPath(br1, path1); //draw the main shape
g_bmp.FillPath(br3, path3); //draw the bubble
g_bmp.DrawPath(txtPen, path4); //draw the text
上面代码中需要注意的是,我没有存储阴影,这样只有按钮具有脉冲效果。
一旦存储了位图,我们就可以随意操纵它,而无需调用Invalidate
方法来调用OnPaint
。以下代码负责调整图像的亮度:
private void pulseTimer_Tick(object sender, EventArgs e)
{
if (this.Focused && pulseOnFocus && buttonBitmap != null)
{
gamma += gammaStep;
if (gamma > this.maxGamma) gammaStep = - gammaStep;
if (gamma < this.minGamma) gammaStep = Math.Abs(gammaStep);
imgAttr.SetGamma(gamma);
this.CreateGraphics().DrawImage(buttonBitmap,
buttonBitmapRectangle, 0, 0, buttonBitmap.Width,
buttonBitmap.Height, GraphicsUnit.Pixel, imgAttr);
}
}
之前我没有提到的一点是,这个类会处理鼠标悬停在按钮上时的颜色变化。当颜色改变时,位图也会改变,因此即使在悬停颜色下,脉冲动作也会继续!
要查看脉冲效果,请在启动演示后按下Tab键。Tab键会将您带到第一个启用了脉冲的按钮。第一列的所有按钮都启用了脉冲功能。
结论
在这篇文章中,我向您展示了一些非常简单但具有强大视觉效果的方法。我在此介绍的AquaButton
类实际上并不够健壮,还需要大量的工作。我只是想分享我关于如何创建Aqua效果的发现,并希望它能在您自定义控件时有所帮助。让我澄清一下,我经常会学到一些在CP上找不到的新东西,并且总是会想“分享出来肯定很酷”;然而,当我创建了一个完全健壮的库时,通常已经没有时间写文章了。所以,代码“原样”呈现,希望它能给您带来一些新想法。
历史
- 2005/11/28 - 首次发布。
- 2005/11/29 - 添加了按钮脉冲功能。