0

So... I have made an override to my OnPaint event to get rounded corners, and it sorta worked, but it had a huge problem: no antialiasing due to doing it with a Region.

So I dropped that and switched to e.Graphics.DrawPath, which, again, sorta works. It gives me the shape I want and smooth edges. Just one problem... There seems to be a black rectangle behind it (as per the image below)

enter image description here

My code is as follows (and no, I didn't forget base.OnPaint(e), I tried putting that in many spots on this code and it just made things worse):

  public class Button : System.Windows.Forms.Button
  {
    public BorderRadius BorderRadius { get; set; } = new BorderRadius(0);
    public Color BorderColor { get; set; } = Color.Transparent;
    protected override void OnPaint(PaintEventArgs e) {
      e.Graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
      e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
      e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
      e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

      SolidBrush brush = new(BackColor);
      GraphicsPath gp = Transform.BorderRadius(ClientRectangle, new(40));
      gp.CloseFigure();

      StringFormat formatter = new() {
        LineAlignment = StringAlignment.Center,
        Alignment = StringAlignment.Center
      };
      RectangleF rectangle = new(0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);

      e.Graphics.FillRectangle(new SolidBrush(Color.Transparent), ClientRectangle);
      e.Graphics.FillPath(brush, gp);
      e.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), rectangle, formatter);
    }
  }

If you are interested in the Transform and BorderRadius classes they are in the snippet below, but I don't think they are the problem:

  class Transform
  {
    public static GraphicsPath BorderRadius(Rectangle pRect, BorderRadius borderRadius) {
      GraphicsPath gp = new GraphicsPath();

      if (borderRadius.TopLeft > 0) {
        gp.AddArc(
          pRect.X,
          pRect.Y,
          borderRadius.TopLeft,
          borderRadius.TopLeft,
          180,
          90
        );
      } else {
        gp.AddLine(
          pRect.X,
          pRect.Y,
          pRect.X + pRect.Width - borderRadius.TopRight,
          pRect.Y
        );
      }

      if (borderRadius.TopRight > 0) {
        gp.AddArc(
          pRect.X + pRect.Width - borderRadius.TopRight,
          pRect.Y,
          borderRadius.TopRight,
          borderRadius.TopRight,
          270,
          90
        );
      } else {
        gp.AddLine(
          pRect.X + borderRadius.TopLeft,
          pRect.Y,
          pRect.X + pRect.Width,
          pRect.Y
        );
      }

      if (borderRadius.BottomRight > 0) {
        gp.AddArc(
          pRect.X + pRect.Width - borderRadius.BottomRight,
          pRect.Y + pRect.Height - borderRadius.BottomRight,
          borderRadius.BottomRight,
          borderRadius.BottomRight,
          0,
          90
        );
      } else {
        gp.AddLine(
          pRect.X + pRect.Width,
          pRect.Y + pRect.Height,
          pRect.X + borderRadius.BottomLeft,
          pRect.Y + pRect.Height
        );
      }

      if (borderRadius.BottomLeft > 0) {
        gp.AddArc(
          pRect.X,
          pRect.Y + pRect.Height - borderRadius.BottomLeft,
          borderRadius.BottomLeft,
          borderRadius.BottomLeft,
          90,
          90
        );
      } else {
        gp.AddLine(
          pRect.X + pRect.Width - borderRadius.BottomRight,
          pRect.Y + pRect.Height,
          pRect.X,
          pRect.Y + pRect.Height
        );
      }

      return gp;
    }
  }


  public class BorderRadius {
    public int TopLeft { get; init; } = 0;
    public int TopRight { get; init; } = 0;
    public int BottomLeft { get; init; } = 0;
    public int BottomRight { get; init; } = 0;

    public BorderRadius(int all) {
      TopLeft = TopRight = BottomLeft = BottomRight = all;
    }

    public BorderRadius(int topLeftAndBottomRight, int topRightAndBottomLeft) {
      TopLeft = BottomRight = topLeftAndBottomRight;
      TopRight = BottomLeft = topRightAndBottomLeft;
    }

    public BorderRadius(int topLeft, int topRightAndBottomLeft, int bottomRight) {
      TopRight = BottomLeft = topRightAndBottomLeft;
      TopLeft = topLeft;
      BottomRight = bottomRight;
    }

    public BorderRadius(int topLeft, int topRight, int bottomRight, int bottomLeft) {
      TopLeft = topLeft;
      TopRight = topRight;
      BottomLeft = bottomLeft;
      BottomRight = bottomRight;
    }

    public void Deconstruct(out int topLeft, out int topRight, out int bottomRight, out int bottomLeft) {
      topLeft = TopLeft;
      topRight = TopRight;
      bottomRight = BottomRight;
      bottomLeft = BottomLeft;
    }
  }
Gustavo Shigueo
  • 399
  • 3
  • 11
  • 1
    (Custom Rounded Button): [How to make a custom Button responsiveness smoother?](https://stackoverflow.com/a/62778689/7444103), (UserControl) [How to avoid visual artifacts of colored border of zoomable UserControl with rounded corners?](https://stackoverflow.com/a/54794097/7444103) -- (Custom translucent Control): [Translucent circular Control with text](https://stackoverflow.com/a/51435842/7444103), (Custom Shapes) [How to draw a shape using GraphicsPath to create the Region of a Custom Control?](https://stackoverflow.com/a/69075782/7444103) -- All with smooth borders. – Jimi Feb 11 '22 at 22:29
  • 2
    That's the way the code painted it, consider new SolidBrush(Parent.BackColor) – Hans Passant Feb 11 '22 at 23:10
  • Thank you @HansPassant, this worked! Can you post this as an answer so I can mark it as a solution? Also, could clarify for anyone else with this problem that your are refering to the place where I used Color.Transparent? – Gustavo Shigueo Feb 11 '22 at 23:29
  • 1
    You can clear the canvas using the parent's background color `e.Graphics.Clear(Parent.BackColor);` and use the button's `BackColor` to fill the path. Then, you don't need to create a brush to fill the background. Also, you should `Dispose();` the graphics objects (`brush`, `gp`). Always create them in `using` blocks. – dr.null Feb 12 '22 at 02:56
  • 1
    Thanks for the tip @dr.null, the project this is for needs to run on very old PCs and the last thing I want is a memory leak – Gustavo Shigueo Feb 12 '22 at 13:00

0 Answers0