0

I have here the circle image, what I want to do is to put some color in specific position.. For example, when I click the button1, the left side of the circle will be filled by red, and when I click the button2, the right side will be filled by as well, and when I click the button1 again, the color will be removed, and so on...

I've done some research about it, and found out 2 ways to do it. First is, to layover the circle with another image. Second is to draw, and use the Graphics class in C#..

Now, my question is, is there another possible way to do it? What is the best way?

P.S: The purpose of this is for the tooth chart. :)

enter image description here

Syntax Error
  • 105
  • 1
  • 4
  • 12
  • 1
    Can you show us your code so far? – mjwills Jun 18 '17 at 13:44
  • 1
    Using multiple images is probably the easiest way. – moritzg Jun 18 '17 at 13:49
  • 1
    There are many many ways. The 'best' depends on the specs you have and, no, a 'tooth chart' is not a useful specification for us. One basic question is: Can you describe the shape geometrically? Them (in your case) 5 GraphicsPaths are clearly the best option. If you can't you can implement a floodfill.. Do have a look at [this post](https://stackoverflow.com/questions/38969309/use-fillpath-with-mouse-input-as-flood-fill-between-drawn-paths/38969673#38969673) to see if you suits your situation! Other [posts you might find useful..](https://stackoverflow.com/search?q=user%3A3152130+floodfill) – TaW Jun 18 '17 at 15:41
  • Also look at this, [rather similar post!](https://stackoverflow.com/questions/41659729/how-to-draw-shapes-and-color-them-with-a-button/41660406#41660406) – TaW Jun 18 '17 at 15:47

1 Answers1

4

Here's a Resizable, Clickable, UserControl based on qing`s post. You can click on the regions directly to toggle them, or change them via code.

enter image description here

public partial class ToothChart : UserControl
{

    public ToothChart()
    {
        InitializeComponent();
        this.DoubleBuffered = true;
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        if (this.ParentForm != null)
        {
            this.ParentForm.FormClosing += (s, evt) => { OnHandleDestroyed(new EventArgs()); };
        }
    }

    protected override void OnHandleDestroyed(EventArgs e)
    {
        base.OnHandleDestroyed(e);

        if (this._pathTop != null)
        {
            this._pathTop.Dispose();
            this._pathTop = null;
        }
        if (this._pathRight != null)
        {
            this._pathRight.Dispose();
            this._pathRight = null;
        }
        if (this._pathBottom != null)
        {
            this._pathBottom.Dispose();
            this._pathBottom = null;
        }
        if (this._pathLeft != null)
        {
            this._pathLeft.Dispose();
            this._pathLeft = null;
        }
        if (this._pathCenter != null)
        {
            this._pathCenter.Dispose();
            this._pathCenter = null;
        }
    }

    private GraphicsPath _pathTop = null;
    private GraphicsPath _pathLeft = null;
    private GraphicsPath _pathBottom = null;
    private GraphicsPath _pathRight = null;
    private GraphicsPath _pathCenter = null;

    private bool _TopRegion = false;
    public bool TopRegion
    {
        get
        {
            return _TopRegion;
        }
        set
        {
            if (_TopRegion != value)
            {
                _TopRegion = value;
                this.Invalidate();
            }
        }
    }

    private bool _RightRegion = false;
    public bool RightRegion
    {
        get
        {
            return _RightRegion;
        }
        set
        {
            if (_RightRegion != value)
            {
                _RightRegion = value;
                this.Invalidate();
            }
        }
    }

    private bool _BottomRegion = false;
    public bool BottomRegion
    {
        get
        {
            return _BottomRegion;
        }
        set
        {
            if (_BottomRegion != value)
            {
                _BottomRegion = value;
                this.Invalidate();
            }
        }
    }

    private bool _LeftRegion = false;
    public bool LeftRegion
    {
        get
        {
            return _LeftRegion;
        }
        set
        {
            if (_LeftRegion != value)
            {
                _LeftRegion = value;
                this.Invalidate();
            }
        }
    }

    private bool _CenterRegion = false;
    public bool CenterRegion
    {
        get
        {
            return _CenterRegion;
        }
        set
        {
            if (_CenterRegion != value)
            {
                _CenterRegion = value;
                this.Invalidate();
            }
        }
    }

    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        if (this.IsHandleCreated && this._pathTop != null)
        {
            this.UpdateRegions();
        }
    }

    private void UpdateRegions()
    {
        int diameterBig = Math.Min(this.Width, this.Height) - 10;
        int diameterSmall = Math.Min(this.Width, this.Height) / 3;
        if (diameterBig > 0 && diameterSmall > 0)
        {
            Point _centerPoint = new Point(this.Width / 2, this.Height / 2);
            Rectangle rectangle = new Rectangle(_centerPoint.X - diameterBig / 2, _centerPoint.Y - diameterBig / 2, diameterBig, diameterBig);
            Rectangle rectangle2 = new Rectangle(_centerPoint.X - diameterSmall / 2, _centerPoint.Y - diameterSmall / 2, diameterSmall, diameterSmall);

            _pathTop.Reset();
            _pathTop.AddArc(rectangle, 225, 90);
            _pathTop.AddArc(rectangle2, -45, -90);

            _pathLeft.Reset();
            _pathLeft.AddArc(rectangle, 135, 90);
            _pathLeft.AddArc(rectangle2, -135, -90);

            _pathBottom.Reset();
            _pathBottom.AddArc(rectangle, 45, 90);
            _pathBottom.AddArc(rectangle2, -225, -90);

            _pathRight.Reset();
            _pathRight.AddArc(rectangle, -45, 90);
            _pathRight.AddArc(rectangle2, -315, -90);

            _pathCenter.Reset();
            _pathCenter.AddEllipse(rectangle2);

            this.Invalidate();
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        if (this.IsHandleCreated)
        {
            if (this._pathTop == null)
            {
                this._pathTop = new GraphicsPath();
                this._pathRight = new GraphicsPath();
                this._pathBottom = new GraphicsPath();
                this._pathLeft = new GraphicsPath();
                this._pathCenter = new GraphicsPath();
                this.UpdateRegions();
            }

            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
            if (this.TopRegion)
            {
                e.Graphics.FillPath(Brushes.Blue, _pathTop);
            }
            e.Graphics.DrawPath(Pens.Black, _pathTop);

            if (this.RightRegion)
            {
                e.Graphics.FillPath(Brushes.DarkRed, _pathRight);
            }
            e.Graphics.DrawPath(Pens.Black, _pathRight);

            if (this.BottomRegion)
            {
                e.Graphics.FillPath(Brushes.Teal, _pathBottom);
            }
            e.Graphics.DrawPath(Pens.Black, _pathBottom);

            if (this.LeftRegion)
            {
                e.Graphics.FillPath(Brushes.Yellow, _pathLeft);
            }
            e.Graphics.DrawPath(Pens.Black, _pathLeft);

            if (this.CenterRegion)
            {
                e.Graphics.FillPath(Brushes.LightGreen, _pathCenter);
            }
            e.Graphics.DrawPath(Pens.Black, _pathCenter);
        }         
    }

    protected override void OnMouseClick(MouseEventArgs e)
    {
        base.OnMouseClick(e);

        Point p = new Point(e.X, e.Y);

        if (this._pathTop.IsVisible(p))
        {
            this.TopRegion = !this.TopRegion;
        }
        else if (this._pathRight.IsVisible(p))
        {
            this.RightRegion = !this.RightRegion;
        }
        else if (this._pathBottom.IsVisible(p))
        {
            this.BottomRegion = !this.BottomRegion;
        }
        else if (this._pathLeft.IsVisible(p))
        {
            this.LeftRegion = !this.LeftRegion;
        }
        else if (this._pathCenter.IsVisible(p))
        {
            this.CenterRegion = !this.CenterRegion;
        }
    }

}
Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
  • Hi @Idle_Mind, actually I'm trying to understand your code, but it seems a bit hard to me. I've already tried it and it worked.. Do you mind if I ask, what if in case, I'd like to add a color on circle as well? – Syntax Error Jun 18 '17 at 16:51
  • You mean the inner, middle circle? You want it just colored, or clickable as well? – Idle_Mind Jun 18 '17 at 16:56
  • 1
    Good stuff here. I don't usually upvote answers that spoon-feed with pre-written code and no explanation, but this is fairly high-quality work. The only thing I would suggest is that you override Dispose (Control implements IDisposable) and ensure that you dispose the GraphicsPath objects stored as member variables. This won't happen automatically, and GraphicsPath objects don't derive from System.ComponentModel.Component, so you can't simply add them to the Control's Components collection to have them automatically disposed by the base class's Dispose method, so you need to do it yourself. – Cody Gray - on strike Jun 19 '17 at 08:46
  • @Idle_Mind, I want the circle to be a clickable as well, like the other sides. – Syntax Error Jun 19 '17 at 13:19
  • Updated the code so the center region is now clickable and also included code to handle proper disposal of the GraphicsPath instances as suggested by @CodyGray. – Idle_Mind Jun 19 '17 at 16:02
  • Why not just do it in an override of [IDisposable.Dispose](https://msdn.microsoft.com/en-us/library/system.idisposable.dispose(v=vs.110).aspx)? – Cody Gray - on strike Jun 19 '17 at 16:06
  • @CodyGray Because it was complaining about the code already being in the hidden designer file; I could move the method, but then the code posted here would need extra instructions to make it work. I thought it would be better this way since anyone can copy and paste the code above and it would just work "as is". – Idle_Mind Jun 19 '17 at 16:10
  • Ah, good point. Yes, technically, moving it is what you're supposed to do, and the designer will catch on. I had forgotten all about that. I gave up on the designer a *long* time ago. Anyway, I agree it's best to have an answer that is copy-paste ready, as much as that hurts me to say. – Cody Gray - on strike Jun 19 '17 at 16:12