介绍 不久前,我试图找到一个不错的圆形按钮控件。我找不到一本,所以按照由来已久的传统,我决定自己写一本。我“几乎”完成了它,但由于各种原因,它被归入了“以后再看”的类别。在它独特的风格中,“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。 隐藏,复制Code
internal 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方法。没什么特别令人兴奋的,但我把它包括进来作为参考。 隐藏,收缩,复制Code
protected 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方法中再次使用了相同的技术,尽管它创建了更平滑的曲线,但我不知道它是如何或为什么工作的。但是,我们中有多少人真正知道电视是如何工作的? 隐藏,复制Code
protected 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设置为白色,并根据按钮的大小计算一个中心点。 隐藏,复制Code
pgb.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内容对齐到字符串对齐。最后,我检查按钮是否被禁用,如果是,我“灰色”文本。 隐藏,收缩,复制Code
protected 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,并且虚拟光的角度被改变,使按钮的左上方变暗,右下方变亮,从而产生按钮已经退隐到表单表面的印象。当按钮被释放时,值恢复正常。 隐藏,复制Code
protected 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的区域,其中包含了一些乏味的方法,比如: 隐藏,复制Code
protected 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