-1

I've got a WinForms app and I want to programatically draw circles on top of certain areas. I'm running into a couple problems and any insight would be appreciated!

1) I've got code for drawing and clearing the circles (see below), but the circles are being drawn behind all my controls. I want them to be drawn as "top-most" in every case. How do I do this?

2) When my app starts up, I'll have some circles that need to be drawn right away. I tried drawing them on the Form Load event to no avail. But as to here (Form graphics not set when form loads) I'm now drawing it on the Paint event. While this works reasonably well (with a bool to make sure it only does it the first time), It seems to have problems with the this.Invalidate(); (as no circles are getting drawn). Is there a better way? Here's my code (parseText runs on a the index change of a comboBox):

private void parseText()
{
    this.Invalidate();
    List<string> lines = new List<string>(richTextBoxRaw.Text.Split(new string[] { Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries));

    foreach (string s in lines)
    {
        switch (s)
        {
            case "<draw1>":
                drawCircle(107, 26, 25);
                break;
            default:
                break;
        }
    }
}

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

    SolidBrush brush = new SolidBrush(Color.FromArgb(transparency, 255,0,0));
    Graphics graphics = this.CreateGraphics();

    graphics.FillEllipse(brush, new Rectangle(x, y, 25, 25));
    brush.Dispose();
    graphics.Dispose();
}

private void Form1_Paint(object sender, PaintEventArgs e)
{
    if (starting)
        parseText();

    starting = false;
}
Community
  • 1
  • 1
derekantrican
  • 1,891
  • 3
  • 27
  • 57
  • 1
    You need to understand some basics. 1. You need to invoke your code from Paint Event (not from form load) so it is always updated properly when the window needs a screen refresh. 2. Remember, that the form will have controls, which have their own paint routines. which will clear off your ink. You can register for the control's paint event and draw on the control. Now you can also create a usercontrol which overlays all controls on the form (Z-Order of zero) and draw your circle there, but then you need logic to pass your events to controls below your UserControl. There is no simple solution. – Vikhram Oct 22 '16 at 16:26

1 Answers1

2

One of not so complicated and yet working approaches of accomplishing your requirement could be to create custom transparent panel and place it on top of the controls where the red circles will be drawn.

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;

        SolidBrush brush = new SolidBrush(Color.FromArgb(transparency, 255, 0, 0));

        graphics.FillEllipse(brush, new Rectangle(x, y, 25, 25));
        brush.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);
    }
}

enter image description here

ivayle
  • 1,070
  • 10
  • 17
  • So I've implemented your suggestion and it seems to work great except for a tab control that I have - the tab control seems to be overriding the transparentPanel's "BringToFront" (and there doesn't seem to be a paint event for the tabControl that I can put a `transparentPanel.BringToFront();` in) – derekantrican Oct 24 '16 at 19:17
  • You can subscribe to `TabControl.TabPages[0].Paint` and invoke `transparePanel.Refresh();` – ivayle Oct 24 '16 at 20:07