zoukankan      html  css  js  c++  java
  • 圆形按钮窗口控制-不断减少的圆圈

    介绍 不久前,我试图找到一个不错的圆形按钮控件。我找不到一本,所以按照由来已久的传统,我决定自己写一本。我“几乎”完成了它,但由于各种原因,它被归入了“以后再看”的类别。在它独特的风格中,“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

  • 相关阅读:
    高维协方差矩阵估计
    互信息
    投资组合模型
    R语言
    sklearn
    Python学习
    swagger使用过程中遇到的坑
    mysql杂文
    2018狗年,半年报
    Springboot 手动搭建项目 --redis配置&日志完善+用户名
  • 原文地址:https://www.cnblogs.com/Dincat/p/13456020.html
Copyright © 2011-2022 走看看