(C# Winforms) Drawing a circle on a TextBox

1

Sorry for my poor English.

I have a user control which includes two text boxes. I wanna draw a circle over that.

I tried to use a transparent panel like below. (This code is from Drawing circles on top of a form)

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void DrawCircle(int x, int y, int transparency, Graphics graphics)
    {
        if (transparency < 0)
            transparency = 0;
        else if (transparency > 255)
            transparency = 255;

        Pen pen = new Pen(Color.Red, 5)

        graphics.DrawEllipse(pen, new Rectangle(x, y, 90, 90));
        pen.Dispose();
        graphics.Dispose();
    }

    private void TransparentPanel1_Paint(object sender, PaintEventArgs e)
    {
        DrawCircle(10, 10, 255, e.Graphics);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        transparentPanel1.Enabled = false;
        transparentPanel1.Paint += TransparentPanel1_Paint;
        transparentPanel1.BringToFront();
    }
}

public class TransparentPanel : Panel
{
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
            return cp;
        }
    }
    protected override void OnPaintBackground(PaintEventArgs e)
    {
        //base.OnPaintBackground(e);
    }
}

However, it doesn't work.

When I use normal panel rather than transparent panel, the background color covers the entire textbox so I can't see the text. I don't want that.

I don't need editing text when the circle appeared, so this textbox can be replaced with label. (But I still need editing text when the circle doesn't exist.)

How can i draw a circle on a textbox? (Circle can be replaced with 'Circle Image file'. But the background of circle still need to be transparent.)

c#
winforms
asked on Stack Overflow Jul 20, 2020 by John • edited Oct 26, 2020 by John

2 Answers

0

I have had a similiar problem and the best solution I came up with was to make a screenshot from the parent panel and show the image in a another panel. This panel was made visible while the other one containing all controls was made invisible. I used this to show a loading screen without using a modal form.

I found the code in an old VB.NET application and hope that the translated code works:

class NativeMethods
{
    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags);

    internal static Image PrintControl(Control ctrl)
    {
        using (Graphics controlGraphics = ctrl.CreateGraphics())
        {
            Bitmap bmp = new Bitmap(ctrl.Size.Width, ctrl.Size.Height, controlGraphics);

            using (Graphics bmpGraphics = Graphics.FromImage(bmp))
            {
                IntPtr dc = bmpGraphics.GetHdc();
                PrintWindow(ctrl.Handle, dc, 0);
                bmpGraphics.ReleaseHdc(dc);
                return bmp;
            }
        }
    }
}

Given you have Panel1 which contains the TextBox controls and Panel2 as a overlay (that contains the screenshot with the red circle) you could use a code like this:

        private void ShowRedCircle()
        {
            Image bmp = NativeMethods.PrintControl(this.panel1);

            using (Graphics bmpGraphics = Graphics.FromImage(bmp))
            using (Pen sPen = new Pen(Color.Red))
            {
                bmpGraphics.DrawEllipse(sPen, new Rectangle(10, 10, 90, 90));
                this.panel2.BackgroundImage = bmp;
            }

            this.panel2.Visible = true;
            this.panel1.Visible = false;
        }

When you want to remove the circle just change the visibility of the panels again. You should consider to dispose the BackgroundImage of panel2 in this case.

answered on Stack Overflow Jul 20, 2020 by keco
0

You can do this by setting the Region property as a ring.

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace WinForm
{
    public partial class Form1 : Form
    {
        TextBox textBox1;
        TextBox textBox2;
        Panel circle;

        public Form1()
        {
            //InitializeComponent();
            textBox1 = new TextBox { Parent = this, Width = 100, Left = 20, Top = 20, Height = 80, AutoSize = false };
            textBox2 = new TextBox { Parent = this, Width = 100, Left = 20, Top = textBox1.Bottom };

            ShowCircle();
        }
        void ShowCircle()
        {
            circle = new Panel
            {
                Parent = this,
                BackColor = Color.Red,
                Top = textBox1.Top,
                Left = textBox1.Left,
                Width = textBox1.Width,
                Height = textBox1.Height + textBox2.Height
            };

            using (var path = new GraphicsPath())
            {
                var rect = new Rectangle(0, 0, circle.Width, circle.Height);
                path.AddEllipse(rect);
                rect.Inflate(-5, -5);
                path.AddEllipse(rect);

                circle.Region = new Region(path);
                circle.BringToFront();
            }
        }
    }
}
answered on Stack Overflow Jul 20, 2020 by Alexander Petrov

User contributions licensed under CC BY-SA 3.0