基于圆角矩形的自定义控件的非工作抗锯齿

时间:2013-08-21 06:17:33

标签: c# winforms controls rectangles aliasing

我创建了以下一组类来创建自己的控件库。目前,它基于asbtract类ShapeControl:Control。但是,我仍然有一些麻烦,没有一些不良的混叠副作用(特别是圆角矩形),我怎么能摆脱它们? (我已经尝试改变平滑度和像素偏移,并刷新并改变OnPaint()过程中的顺序......没有那么多成功= /)。

是否有任何想法正确使用“SmoothingMode”和“PixelOffset”属性?

public abstract class ShapeControl : Control
{
    public ShapeControl()
    {
        this.SetStyle(ControlStyles.SupportsTransparentBackColor |
                      ControlStyles.DoubleBuffer |
                      ControlStyles.AllPaintingInWmPaint |
                      ControlStyles.UserPaint, true);

        this.PixelOffsetMode = PixelOffsetMode.HighQuality;
        this.SmoothingMode = SmoothingMode.HighQuality;

        this.TextAligmentHorizontal = StringAlignment.Center;
        this.TextAligmentVertical = StringAlignment.Center;

        this.MouseDown += new MouseEventHandler(Shape_MouseDown);
        this.MouseMove += new MouseEventHandler(Shape_MouseMove);

        this.BackColor = Color.FromArgb(0, 255, 255, 255);

        this.GradientColors = new List<Color>();

        this.GradientRadialFocus = 0.5f;
        this.GradientRadialScale = 1.0f;
        this.GradientRadialType = GradientRadialType.SigmaBell;
    }

    protected override void OnResize(EventArgs e)
    {
        this.Region = new Region(this.GraphicsPath);
        this.Invalidate();
        base.OnResize(e);
    }

    public override string Text
    {
        get
        {
            return base.Text;
        }
        set
        {
            base.Text = value;
            this.Invalidate();
        }
    }
    public override Color BackColor
    {
        get
        {
            return base.BackColor;
        }
        set
        {
            base.BackColor = value;
            this.Invalidate();
        }
    }

    protected Point LastMouseDownLocation { get; set;}

    private void Shape_MouseMove(Object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            this.Left = e.X + this.Left - LastMouseDownLocation.X;
            this.Top = e.Y + this.Top - LastMouseDownLocation.Y;

            this.Invalidate();
        }
    }
    private void Shape_MouseDown(Object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            this.LastMouseDownLocation = e.Location;
        }
    }

    protected DashStyle InternalBorderStyle { get; set; }
    protected UInt32 InternalBorderWidth { get; set; }
    protected Color InternalBorderColor { get; set; }
    protected BackType InternalBackType { get; set; }
    protected List<Color> InternalGradientColors { get; set; }

    protected SmoothingMode InternalSmoothingMode { get; set; }
    protected PixelOffsetMode InternalPixelOffsetMode { get; set; }

    public DashStyle BorderStyle
    {
        get { return this.InternalBorderStyle; }
        set
        {
            if (this.InternalBorderStyle != value)
            {
                this.InternalBorderStyle = value;
                this.Invalidate();
            }
        }
    }
    public UInt32 BorderWidth
    {
        get { return this.InternalBorderWidth; }
        set
        {
            if (this.InternalBorderWidth != value)
            {
                this.InternalBorderWidth = value;
                this.Invalidate();
            }
        }
    }
    public Color BorderColor
    {
        get { return this.InternalBorderColor; }
        set
        {
            if (this.InternalBorderColor != value)
            {
                this.InternalBorderColor = value;
                this.Invalidate();
            }
        }
    }
    public BackType BackType
    {
        get { return this.InternalBackType; }
        set
        {
            if (this.InternalBackType != value)
            {
                this.InternalBackType = value;
                this.Invalidate();
            }
        }
    }
    public List<Color> GradientColors
    {
        get { return this.InternalGradientColors; }
        set
        {
            if (this.InternalGradientColors != value)
            {
                this.InternalGradientColors = value;
                this.Invalidate();
            }
        }
    }

    public SmoothingMode SmoothingMode
    {
        get { return this.InternalSmoothingMode; }
        set
        {
            if (this.InternalSmoothingMode != value)
            {
                this.InternalSmoothingMode = value;
                this.Invalidate();
            }
        }
    }
    public PixelOffsetMode PixelOffsetMode
    {
        get { return this.InternalPixelOffsetMode; }
        set
        {
            if (this.InternalPixelOffsetMode != value)
            {
                this.InternalPixelOffsetMode = value;
                this.Invalidate();
            }
        }
    }

    protected override Size DefaultSize
    {
        get
        {
            return new Size(100, 100);
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = this.SmoothingMode;
        e.Graphics.PixelOffsetMode = this.PixelOffsetMode;

        ProcessBack(e.Graphics);
        ProcessBorder(e.Graphics);
        ProcessText(e.Graphics);

        base.OnPaint(e);
    }

    protected void ProcessBack(Graphics graphics)
    {
        switch (this.BackType)
        {
            case BackType.Solid:
                // Nothing special...
                break;

            case BackType.GradientHorizontal:
            case BackType.GradientVertical:
            case BackType.GradientRadial:

                    Single angle = 42;

                    if (this.BackType == BackType.GradientHorizontal)
                    {
                        angle = 0;
                    }
                    else if (this.BackType == BackType.GradientVertical)
                    {
                        angle = 90;
                    }
                    else
                    {
                        angle = 42;
                    }

                    Brush brushGradient = null;

                    Boolean isALinearBrush = (this.BackType == BackType.GradientHorizontal) || (this.BackType == BackType.GradientVertical);

                    if (isALinearBrush)
                    {
                        LinearGradientBrush linearGradientBrushHorizontal = new LinearGradientBrush(this.ClientRectangle, Color.Black, Color.Black, angle, false);
                        brushGradient = linearGradientBrushHorizontal;
                    }
                    else
                    {
                        PathGradientBrush pathGradientBrush = new PathGradientBrush(this.GraphicsPath);
                        brushGradient = pathGradientBrush;
                    }

                    ColorBlend colorBlend = new ColorBlend();
                    HashSet<Single> positions = new HashSet<Single>();

                    if (this.GradientColors.Count > 1)
                    {
                        for (Single i = 0; i < this.GradientColors.Count; i++)
                        {
                            positions.Add(i / (this.GradientColors.Count - 1));
                        }

                        colorBlend.Colors = this.GradientColors.ToArray();
                    }
                    else
                    {
                        positions.Add(0);
                        positions.Add(1);

                        if (this.GradientColors.Count == 1)
                        {
                            colorBlend.Colors = new Color[2] { this.GradientColors[0], this.GradientColors[0] };
                        }
                        else
                        {
                            colorBlend.Colors = new Color[2] { this.BackColor, this.BackColor };
                        }
                    }

                    colorBlend.Positions = positions.ToArray();

                    if (isALinearBrush)
                    {
                        (brushGradient as LinearGradientBrush).InterpolationColors = colorBlend;
                    }
                    else
                    {
                        PathGradientBrush pathGradientBrush = brushGradient as PathGradientBrush;

                        if (this.GradientRadialType == GradientRadialType.SigmaBell)
                        {
                            pathGradientBrush.SetSigmaBellShape(this.GradientRadialFocus, this.GradientRadialScale);
                        }
                        else
                        {
                            pathGradientBrush.SetBlendTriangularShape(this.GradientRadialFocus, this.GradientRadialScale);
                        }
                        pathGradientBrush.CenterPoint = new PointF(this.ClientRectangle.Right / 2, this.ClientRectangle.Bottom / 2);
                        pathGradientBrush.InterpolationColors = colorBlend;
                    }

                    graphics.FillPath(brushGradient, this.GraphicsPath);
                    break;
        }
    }
    protected void ProcessBorder(Graphics graphics)
    {
        if (this.BorderWidth > 0)
        {
            // Hey wait... * 2, why?
            Pen pen = new Pen(this.BorderColor, this.BorderWidth * 2);
            pen.DashStyle = this.BorderStyle;
            graphics.DrawPath(pen, this.GraphicsPath);
            pen.Dispose();
        }
    }
    protected void ProcessText(Graphics graphics)
    {
        Brush brushText = new SolidBrush(this.ForeColor);
        StringFormat stringFormatText = new StringFormat();
        stringFormatText.Alignment = this.TextAligmentHorizontal;
        stringFormatText.LineAlignment = this.TextAligmentVertical;
        Rectangle rectangleText = new Rectangle(0, 0, this.Width, this.Height);

        graphics.DrawString(this.Text, this.Font, brushText, rectangleText, stringFormatText);
    }

    protected StringAlignment InternalTextAligmentHorizontal { get; set; }
    protected StringAlignment InternalTextAligmentVertical { get; set; }

    public StringAlignment TextAligmentHorizontal
    {
        get { return this.InternalTextAligmentHorizontal; }
        set
        {
            if (this.InternalTextAligmentHorizontal != value)
            {
                this.InternalTextAligmentHorizontal = value;
                this.Invalidate();
            }
        }
    }
    public StringAlignment TextAligmentVertical
    {
        get { return this.InternalTextAligmentVertical; }
        set
        {
            if (this.InternalTextAligmentVertical != value)
            {
                this.InternalTextAligmentVertical = value;
                this.Invalidate();
            }
        }
    }

    protected GradientRadialType InternalGradientRadialType { get; set; }
    public GradientRadialType GradientRadialType
    {
        get { return this.InternalGradientRadialType; }
        set
        {
            if (this.InternalGradientRadialType != value)
            {
                this.InternalGradientRadialType = value;
                this.Invalidate();
            }
        }
    }

    protected Single InternalGradientRadialFocus { get; set; }
    public Single GradientRadialFocus
    {
        get { return this.InternalGradientRadialFocus; }
        set
        {
            if (this.InternalGradientRadialFocus != value)
            {
                if (1.0f < value)
                {
                    this.InternalGradientRadialFocus = 1.0f;
                }
                else if (value < 0.0f)
                {
                    this.InternalGradientRadialFocus = 0.0f;
                }
                else
                {
                    this.InternalGradientRadialFocus = value;
                }

                this.Invalidate();
            }
        }
    }

    protected Single InternalGradientRadialScale { get; set; }
    public Single GradientRadialScale
    {
        get { return this.InternalGradientRadialScale; }
        set
        {
            if (this.InternalGradientRadialScale != value)
            {
                if (1.0f < value )
                {
                    this.InternalGradientRadialScale = 1.0f;
                }
                else if (value < 0.0f)
                {
                    this.InternalGradientRadialScale = 0.0f;
                }
                else
                {
                    this.InternalGradientRadialScale = value;
                }

                this.Invalidate();
            }
        }
    }

    protected abstract GraphicsPath GraphicsPath { get; }
}

public enum GradientRadialType
{
    SigmaBell,
    Triangular,
}

public enum BackType
{
    Solid,
    GradientHorizontal,
    GradientVertical,
    GradientRadial,
}



public class EllipseControl : ShapeControl
{
    protected override GraphicsPath GraphicsPath
    {
        get 
        { 
            GraphicsPath graphicsPath = new GraphicsPath();
            graphicsPath.AddEllipse(this.ClientRectangle);

            return graphicsPath;
        }
    }
}
public class RectangleControl : ShapeControl
{
    public RectangleControl()
        : base()
    {
        this.Radius = 5;
    }

    protected UInt32 InternalRadius { get; set; }
    public UInt32 Radius
    {
        get { return this.InternalRadius; }
        set
        {
            if (this.InternalRadius != value)
            {
                this.InternalRadius = value;
                this.Invalidate();
            }
        }
    }

    protected RectangleEdgeType InternalRectangleEdge { get; set; }
    public RectangleEdgeType RectangleEdge
    {
        get { return this.InternalRectangleEdge; }
        set
        {
            if (this.InternalRectangleEdge != value)
            {
                this.InternalRectangleEdge = value;
                this.Invalidate();
            }
        }
    }

    protected override GraphicsPath GraphicsPath
    {
        get 
        {
            GraphicsPath graphicsPath = new GraphicsPath();

            if (this.Radius == 0)
            {
                graphicsPath.AddRectangle(new Rectangle(0, 0, this.Width, this.Height));
            }
            else
            {
                Int32 width = this.Width;
                Int32 height = this.Height;
                Single radius = Convert.ToSingle(this.Radius);
                RectangleF rectangleF = this.ClientRectangle;
                Graphics graphics = null;

                graphicsPath = GenerateRoundedRectangle(graphics, rectangleF, radius, RectangleEdgeType.All);
            }

            return graphicsPath;
        }
    }

    private static GraphicsPath GenerateRoundedRectangle(Graphics graphics, RectangleF rectangle, Single radius, RectangleEdgeType filter)
    {
        Single diameter;
        GraphicsPath path = new GraphicsPath();
        {
            if (radius >= (Math.Min(rectangle.Width, rectangle.Height)) / 2.0)
                return GenerateCapsule(graphics, rectangle);

            diameter = radius * 2.0F;
            SizeF sizeF = new SizeF(diameter, diameter);
            RectangleF arc = new RectangleF(rectangle.Location, sizeF);
            if ((RectangleEdgeType.TopLeft & filter) == RectangleEdgeType.TopLeft)
            {
                path.AddArc(arc, 180, 90);
            }
            else
            {
                path.AddLine(arc.X, arc.Y + arc.Height, arc.X, arc.Y);
                path.AddLine(arc.X, arc.Y, arc.X + arc.Width, arc.Y);
            }
            arc.X = rectangle.Right - diameter;
            if ((RectangleEdgeType.TopRight & filter) == RectangleEdgeType.TopRight)
            {
                path.AddArc(arc, 270, 90);
            }
            else
            {
                path.AddLine(arc.X, arc.Y, arc.X + arc.Width, arc.Y);
                path.AddLine(arc.X + arc.Width, arc.Y + arc.Height, arc.X + arc.Width, arc.Y);
            }
            arc.Y = rectangle.Bottom - diameter;
            if ((RectangleEdgeType.BottomRight & filter) == RectangleEdgeType.BottomRight)
            {
                path.AddArc(arc, 0, 90);
            }
            else
            {
                path.AddLine(arc.X + arc.Width, arc.Y, arc.X + arc.Width, arc.Y + arc.Height);
                path.AddLine(arc.X, arc.Y + arc.Height, arc.X + arc.Width, arc.Y + arc.Height);
            }
            arc.X = rectangle.Left;

            if ((RectangleEdgeType.BottomLeft & filter) == RectangleEdgeType.BottomLeft)
            {
                path.AddArc(arc, 90, 90);
            }
            else
            {
                path.AddLine(arc.X + arc.Width, arc.Y + arc.Height, arc.X, arc.Y + arc.Height);
                path.AddLine(arc.X, arc.Y + arc.Height, arc.X, arc.Y);
            }
            path.CloseFigure();
        }
        return path;
    }
    private static GraphicsPath GenerateCapsule( Graphics graphics, RectangleF rectangle)
    {
        Single diameter;
        RectangleF arc;
        GraphicsPath path = new GraphicsPath();

        try
        {
            if (rectangle.Width > rectangle.Height)
            {
                diameter = rectangle.Height;
                SizeF sizeF = new SizeF(diameter, diameter);
                arc = new RectangleF(rectangle.Location, sizeF);
                path.AddArc(arc, 90, 180);
                arc.X = rectangle.Right - diameter;
                path.AddArc(arc, 270, 180);
            }
            else if (rectangle.Width < rectangle.Height)
            {
                diameter = rectangle.Width;
                SizeF sizeF = new SizeF(diameter, diameter);
                arc = new RectangleF(rectangle.Location, sizeF);
                path.AddArc(arc, 180, 180);
                arc.Y = rectangle.Bottom - diameter;
                path.AddArc(arc, 0, 180);
            }
            else
            {
                path.AddEllipse(rectangle);
            }
        }
        catch 
        { 
            path.AddEllipse(rectangle); 
        }
        finally 
        { 
            path.CloseFigure(); 
        }

        return path;
    }
}

public enum RectangleEdgeType
{
    None = 0,
    TopLeft = 1,
    TopRight = 2,
    BottomLeft = 4,
    BottomRight = 8,
    All = TopLeft | TopRight | BottomLeft | BottomRight
}

1 个答案:

答案 0 :(得分:3)

来自PathGradientBrush

  

路径渐变画笔不遵循用于绘制的Graphics对象的SmoothingMode属性。无论平滑模式如何,使用PathGradientBrush对象填充的区域都以相同的方式呈现(别名)。