Question

I'm drawing some glyphs in a WinForms application. Each glyph is defined by a graphics path, basically is a rectangle with rounder corners.

Now I fill the graphics path with a single color, but I need to fill with two colors. The following example explains what I need:

enter image description here

I would like to avoid creating a new GraphicsPath because the performance of the application could be affected.

Is there any tricky option to draw the second fill color without creating a new graphics path?

Here is the code of my graphics path:

public class RoundedRectangle
{
    public static GraphicsPath Create(int x, int y, int width, int height)
    {
        int radius = height / 2;
        int xw = x + width;
        int yh = y + height;
        int xwr = xw - radius;
        int xr = x + radius;
        int r2 = radius * 2;
        int xwr2 = xw - r2;

        GraphicsPath p = new GraphicsPath();

        p.StartFigure();

        // Right arc
        p.AddArc(xwr2, y, r2, r2, 270, 180);

        //Bottom Edge
        p.AddLine(xwr, yh, xr, yh);

        // Left arc
        p.AddArc(x, y, r2, r2, 90, 180);

        //closing the figure adds the top Edge automatically
        p.CloseFigure();

        return p;
    }
}
Was it helpful?

Solution

"Is there any tricky option to draw the second fill color without creating a new graphics path?"

You're splitting the middle area in a non-rectangular fashion so you'll need a GraphicsPath to represent that.

Here's what I came up with:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        this.Paint += new PaintEventHandler(Form1_Paint);
    }

    GraphicsPath rect = RoundedRectangle.Create(100, 100, 100, 35);

    void Form1_Paint(object sender, PaintEventArgs e)
    {
        TwoColorFill(e.Graphics, rect, Color.Yellow, Color.Blue, Color.Gray, 5);
    }

    private void TwoColorFill(Graphics G, GraphicsPath roundRect, Color FillColorLeft, Color FillColorRight, Color BorderColor, float BorderThickness)
    {
        using (SolidBrush RightFill = new SolidBrush(FillColorRight))
        {
            G.FillPath(RightFill, roundRect);
        }

        using (SolidBrush LeftFill = new SolidBrush(FillColorLeft))
        {
            GraphicsPath gp = new GraphicsPath();
            gp.AddPolygon(new Point[] { 
                new Point((int)roundRect.GetBounds().Left, (int)roundRect.GetBounds().Top), 
                new Point((int)roundRect.GetBounds().Right, (int)roundRect.GetBounds().Top), 
                new Point((int)roundRect.GetBounds().Left, (int)roundRect.GetBounds().Bottom)
            });
            G.SetClip(gp);
            G.FillPath(LeftFill, rect);
            G.ResetClip();
        }

        using (Pen p = new Pen(BorderColor, BorderThickness))
        {
            G.DrawPath(p, roundRect);
        }
    }

}

*After further thought, it might be technically possible by clipping using the GraphicsPath itself, translating to its center, performing a rotation, and then drawing a filled rectangle with its edge along the x-axis. You'll have to compute the correct angle somehow, though, and I'm not sure this would really save you anything performance wise over creating the extra GraphicsPath above.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top