Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing on top of controls inside a panel (C# WinForms)

Tags:

c#

.net

winforms

I know this question had been asked more than a few times, but so far I haven't been able to find a good solution for it.

I've got a panel with other control on it.
I want to draw a line on it and on top of all the controls in the panel

I came across 3 types of solutions (non of them worked the way I wanted) :

  1. Get the desktop DC and Draw on the screen.
    This will draw on other applications if they overlap the form.

  2. Overriding the panel's "CreateParams":

=

protected override CreateParams CreateParams {     get {       CreateParams cp;       cp = base.CreateParams;       cp.Style &= ~0x04000000; //WS_CLIPSIBLINGS     cp.Style &= ~0x02000000; //WS_CLIPCHILDREN     return cp;     }   }            

//NOTE I've also tried disabling WS_CLIPSIBLINGS

and then drawing the line OnPaint(). But... Since the panel's OnPaint is called before the OnPaint of the controls in it, the drawing of the controls inside simply paints on top of the line.
I've seen someone suggest using a message filter to listen to WM_PAINT mesages, and use a timer, but I don't think this solution is either "good practice" or effective.
What would you do ? Decide that the controls inside have finished drawing after X ms, and set the timer to X ms ?


This screen shot shows the panel with WS_CLIPSIBLINGS and WS_CLIPCHILDREN turned off.
The Blue line is painted at the Panel's OnPaint, and simply being painted on by the textboxes and label.
The Red line is painted on top only because it's not being painted from the panel's OnPaint (It's actually painted as a result of a Button being clicked)
alt text


3rd: Creating a transparent layer and drawing on top of that layer.
I've created a transparent control using:

protected override CreateParams CreateParams {     get {       CreateParams cp = base.CreateParams;       cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT       return cp;     }   } 

The problem is still, putting the transparent control on top of the Panel and all its controls.
I've tried bringing it to the front using: "BringToFront()" , but it didn't seem to help.
I've put it in the Line control's OnPaint() handler.
Should I try putting it somewhere else ??
- This also creates issue with having another control on top of the panel. (catching the mouse clicks etc..)

Any help would be greatly appreciated!

**EDIT: The black line is a sample of what I was trying to do. (used windows paint to paint it)

alt text

like image 230
dtroy Avatar asked Nov 12 '08 02:11

dtroy


People also ask

How do I add controls to my panel?

To create a group of controlsDrag a Panel control from the Windows Forms tab of the Toolbox onto a form. Add other controls to the panel, drawing each inside the panel.

What is panel in C sharp?

Panel creates a group of Controls. This Control provides a simple frame for putting sub-controls inside. These sub-Controls include Buttons and Textboxes. It furthur provides an optional border and ways to change its visibility.

How do you draw a shape in C sharp?

In order to draw shapes in C# a start point and end point coordinates, and a Pen control must be defined first. The value of x is the location of the point along the x-axis, the 0 is at the extreme left. The value of y is the location of the point along the y-axis, the 0 is at the extreme top.


1 Answers

Turns out this is a whole lot easier than I thought. Thanks for not accepting any of my other answers. Here is the two-step process for creating a Fline (floating line - sorry, it's late):

alt text

Step 1: Add a UserControl to your project and name it "Fline". Add the following to the using statements:

using System.Drawing.Drawing2D; 

Step 2: Add the following to the Fline's Resize event:

int wfactor = 4; // half the line width, kinda // create 6 points for path Point[] pts = {     new Point(0, 0),      new Point(wfactor, 0),      new Point(Width, Height - wfactor),     new Point(Width, Height) ,     new Point(Width - wfactor, Height),     new Point(0, wfactor) }; // magic numbers!  byte[] types = {     0, // start point     1, // line     1, // line     1, // line     1, // line     1 }; // line  GraphicsPath path = new GraphicsPath(pts, types); this.Region = new Region(path); 

Compile, and then drag a Fline onto your form or panel. Important: the default BackColor is the same as the form, so change the Fline's BackColor to Red or something obvious (in the designer). One weird quirk about this is that when you drag it around in the designer it shows as a solid block until you release it - not a huge deal.

This control can appear in front of or behind any other control. If you set Enabled to false, it will still be visible but will not interfere with mouse events on the controls underneath.

You'll want to enhance this for your purposes, of course, but this shows the basic principle. You can use the same technique for creating a control of whatever shape you like (my initial test of this made a triangle).

Update: this makes a nice dense one-liner, too. Just put this in your UserControl's Resize event:

this.Region=new Region(new System.Drawing.Drawing2D.GraphicsPath(new Point[]{new Point(0,0),new Point(4,0),new Point(Width,Height-4),new Point(Width,Height),new Point(Width-4,Height),new Point(0,4)},new byte[]{0,1,1,1,1,1})); 
like image 113
MusiGenesis Avatar answered Oct 17 '22 22:10

MusiGenesis