下载demo project and source - 83.4 KB
介绍
不久前,我试图找到一个不错的圆形按钮控件。我找不到一本,所以按照由来已久的传统,我决定自己写一本。我“几乎”完成了它,但由于各种原因,它被归入了“以后再看”的类别。在它独特的风格中,“later”终于出现了,并且装备了我闪亮的新Microsoft Visual c# 2005 Express Edition,我决定试着完成它。
虽然我自己说过,但我觉得这些扣子看起来不错——你得自己判断!它们“实际”看起来更好,而不是本文中的jpeg。
背景
在我寻找圆形按钮控件的过程中,我看到了几篇文章(包括伟大的Chris Maunder自己写的一篇),对我和我小小的大脑来说,这些文章似乎包含了太多复杂的数学问题。另外,我一直在学习c#中的图形,并对groovy的一些东西进行了大量的试验,比如PathGradientBrush,从Bob Powell这个非常优秀的站点获得了很多灵感。可能是碰巧,我忘记了是怎么做到的,我偶然发现了一个想法,用线性渐变画笔和路径渐变画笔在不断减少的圆上叠加,来创建一个过得去的3-D按钮。以下图片说明了这一点:
悬停光标以获取描述。
它是如何工作的
实际上,把很多圆一个叠一个地放在另一个上面就是它的工作原理。该控件派生自Button类,并覆盖了OnPaint方法,所有绘图都在该方法中完成。我添加了一些新属性:
RecessDepth -按钮被设置回包含表面的斜面高度的距离-按钮顶部的“外部”斜面深度的大小-“内部”斜面穹顶的大小-按钮是否有一个“圆角”顶部
通过使用适当的属性修饰它们,这些属性都被添加到属性面板的按钮外观类别中。另外,我为RecessDepth属性编写了一个自定义下拉UITypeEditor。我不会管理这个没有克里斯卖的优秀作品Windows窗体在c#编程,我高度推荐它,我不会试图解释UITypeEditor是如何工作的,因为它是覆盖样本在线这一章讨论了设计时IDE集成的各个方面(虽然我也做自己的实际的书!)。
注意:为了使ToolboxBitmap属性正常工作,我必须添加这个虚拟类,这也是Bob Powell在本文中建议的:ToolboxBitmap。
隐藏,复制Codeinternal class resfinder
{
// Trick from Bob Powell
}
.
.
.
.
[Description(“Round (Elliptical) Button Control”),
ToolboxBitmap(typeof(resfinder), “RoundButton.Images.RoundButton.bmp”)]
public class RoundButton : System.Windows.Forms.Button
值得注意的代码部分
这是overridden OnPaint方法。没什么特别令人兴奋的,但我把它包括进来作为参考。
隐藏,收缩,复制Codeprotected override void OnPaint(PaintEventArgs e)
{
buttonColor = this.BackColor;
edgeColor1 = ControlPaint.Light(buttonColor);
edgeColor2 = ControlPaint.Dark(buttonColor);
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle buttonRect = this.ClientRectangle;
edgeWidth = GetEdgeWidth(buttonRect);
FillBackground(g, buttonRect);
if (RecessDepth > 0)
{
DrawRecess(ref g, ref buttonRect);
}
DrawEdges(g, ref buttonRect);
ShrinkShape(ref g, ref buttonRect, edgeWidth);
DrawButton(g, buttonRect);
DrawText(g, buttonRect);
SetClickableRegion();
}
接下来是DrawRecess方法,它创建按钮被设置到表单表面的错觉。混合对象允许你指定在矩形的哪一点,以及在多大程度上,两种颜色在线性渐变画笔混合。我通过反复试验得出了这些参数,直到我认为它们是正确的,所以它们纯粹是主观的。ControlPaint。黑暗和ControlPaint。光线在这里非常有用,因为它们创建了父背景颜色的浅阴影和深阴影。当然,这是假设我们想要创造的错觉是一个由坚实的彩色材料组成的形状,而不是一个仍然是灰色的,但被涂上了不同颜色的材料。如果这是您喜欢的,那么只需更改父级即可。背景色Color.FromKnownColor (KnownColor.Control)。
我发现这里有趣的事情是“使用第二个较小的矩形…”部分。我在BuildGraphicsPath方法中再次使用了相同的技术,尽管它创建了更平滑的曲线,但我不知道它是如何或为什么工作的。但是,我们中有多少人真正知道电视是如何工作的?
隐藏,复制Codeprotected virtual void DrawRecess(ref Graphics g, ref Rectangle recessRect)
{
LinearGradientBrush recessBrush = new LinearGradientBrush(recessRect,
ControlPaint.Dark(Parent.BackColor),
ControlPaint.LightLight(Parent.BackColor),
GetLightAngle(Angle.Up));
// Blend colours for realism
Blend recessBlend = new Blend();
recessBlend.Positions = new float[] {0.0f,.2f,.4f,.6f,.8f,1.0f};
recessBlend.Factors = new float[] {.2f,.2f,.4f,.4f,1f,1f};
recessBrush.Blend = recessBlend;
// Using this second smaller rectangle
// smooths the edges - don't know why...?
Rectangle rect2 = recessRect;
ShrinkShape(ref g, ref rect2, 1);
FillShape(g, recessBrush, rect2);
ShrinkShape(ref g, ref recessRect, recessDepth); //orig
}
您将注意到大量的ShrinkShape(ref g, ref edgeRect, 1);源代码中的语句。这就是创造“不断递减的圆”的方法。我使用了一个ref参数,这样问题中的矩形就会变得越来越小。
为了绘制穹顶,我只需要在DrawButton方法中使用这段代码。cColor的默认值是白色,因此如果我们想要一个圆顶顶部,我们将CenterColor设置为白色,并根据按钮的大小计算一个中心点。
隐藏,复制Codepgb.CenterColor = buttonColor;
if (dome)
{
pgb.CenterColor = cColor;
pgb.CenterPoint =
new PointF(buttonRect.X + buttonRect.Width / 8 + buttonPressOffset,
buttonRect.Y + buttonRect.Height / 8 + buttonPressOffset);
}
FillShape(g, pgb, buttonRect);
在按钮上绘制文本使用DrawText方法完成,如下所示。它使用从基按钮类继承的字体和前面板属性。如果按钮的高度超过其宽度的两倍,我使用我的VerticalString类来编写垂直文本。VerticalString是前面一篇CodeProject文章的主题,为了完整起见,我在项目下载中包含了源代码。我还必须确保在可能的情况下,按钮文本保持在按钮的范围内。作为这个过程的一部分,我必须转换文本fr的对齐方式om内容对齐到字符串对齐。最后,我检查按钮是否被禁用,如果是,我“灰色”文本。
隐藏,收缩,复制Codeprotected void DrawText(Graphics g, Rectangle textRect)
{
labelStrFmt = new StringFormat();
labelBrush = new SolidBrush(this.ForeColor);
labelFont = this.Font; // Get the caller-specified font
vs = new VerticalString();
vs.TextSpread = .75;
// Check for tall button, and write text vertically if necessary
bool verticalText = false;
if (textRect.Height > textRect.Width * 2)
{
verticalText = true;
}
// Convert the text alignment from
// ContentAlignment to StringAlignment
labelStrFmt.Alignment = ConvertToHorAlign(this.TextAlign);
labelStrFmt.LineAlignment = ConvertToVertAlign(this.TextAlign);
// If horizontal text is not horizontally centred,
// or vertical text is not vertically centred,
// shrink the rectangle so that the text doesn't stray outside the ellipse
if ((!verticalText & (labelStrFmt.LineAlignment != StringAlignment.Center)) |
(verticalText & (labelStrFmt.Alignment != StringAlignment.Center)))
{
textRect.Inflate(-(int)(textRect.Width/7.5),
-(int)(textRect.Height/7.5));
}
textRect.Offset(buttonPressOffset, buttonPressOffset);
// Apply the offset if we've been clicked
// If button is not enabled, "grey out" the text.
if (!this.Enabled)
{
//Write the white "embossing effect" text at an offset
textRect.Offset(1, 1);
labelBrush.Color = ControlPaint.LightLight(buttonColor);
WriteString(verticalText, g, textRect);
//Restore original text pos, and set text colour to grey.
textRect.Offset(-1, -1);
labelBrush.Color = Color.Gray;
}
//Write the text
WriteString(verticalText, g, textRect);
}
按钮被按下的错觉是通过下面两个小方法实现的。当用户按下按钮时,buttonPressOffset变量被设置为1,并且虚拟光的角度被改变,使按钮的左上方变暗,右下方变亮,从而产生按钮已经退隐到表单表面的印象。当按钮被释放时,值恢复正常。
隐藏,复制Codeprotected void buttonDown()
{
lightAngle = Angle.Down;
buttonPressOffset = 1;
this.Invalidate();
}
protected void buttonUp()
{
lightAngle = Angle.Up;
buttonPressOffset = 0;
this.Invalidate();
}
最后,几点…
圆形按钮控件只支持FlatStyle.Standard。我为FlatStyle编写了一些代码。平,FlatStyle。弹窗,它工作得很好,但我对代码和结果都不是很满意,所以我把它拿掉了。
如果你看一下源代码,你可能会注意到一个叫做Overrideable shape-specific methods的区域,其中包含了一些乏味的方法,比如:
隐藏,复制Codeprotected virtual void AddShape(GraphicsPath gpath, Rectangle rect)
{
gpath.AddEllipse(rect);
}
protected virtual void DrawShape(Graphics g, Pen pen, Rectangle rect)
{
g.DrawEllipse(pen, rect);
}
为什么不直接调用AddEllipse,而不是AddShape?我还编写了其他一些类,比如TriangleButton和DiamondButton,它们显然没有使用AddEllipse或任何与椭圆有关的东西,所以我希望能够在代码中覆盖其他形状的方法。我没有在这里包括其他形状,部分原因是我认为一些代码有点混乱,需要更多的修改,而不是我现在所能做的,而且坦白地说,它们看起来不如圆形的好!
要在另一个项目中使用按钮,只需添加对RoundButton的引用。,并且圆形按钮图标应该出现在工具箱中。(你可能需要使用工具->选择工具箱项手动添加。)
这就是本文的结尾。我希望你觉得它有趣,喜欢的按钮!
本文转载于:http://www.diyabc.com/frontweb/news689.html
本文介绍了一种自定义的圆形按钮控件的创建过程,作者在找不到满意的圆形按钮控件后,决定自行开发。控件使用C#编程,通过叠加多个圆形并应用渐变效果,实现了3D视觉效果。文章详细解释了控件的工作原理,包括如何通过调整圆的大小和位置来创建凹陷感,以及如何使用线性渐变和路径渐变画笔来增强真实感。

2477

被折叠的 条评论
为什么被折叠?



