How to draw a semi-transparent rectangle on Panel containing some user controls in it?
Here is an example of using a 2nd Form to overlay the selection.
I am using a TabPage tabPage5
as my container, you should be able to adapt to any other Control or even the whole Form..
I use two class level variables and prepare the overlay Form somwhere at the start..:
Form overlay = new Form();
Point m_Down = Point.Empty;
void prepareOverlay()
{
overlay.BackColor = Color.Fuchsia; // your selection color
overlay.Opacity = 0.2f; // tranparency
overlay.MinimizeBox = false; // prepare..
overlay.MaximizeBox = false;
overlay.Text = "";
overlay.ShowIcon = false;
overlay.ControlBox = false;
overlay.FormBorderStyle = FormBorderStyle.None;
overlay.Size = Size.Empty;
overlay.TopMost = true;
}
These events are needed for the parent container the user will drag over:
private void tabPage5_MouseDown(object sender, MouseEventArgs e)
{
m_Down = e.Location;
overlay.Size = Size.Empty;
overlay.Show();
}
private void tabPage5_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
overlay.Location = tabPage5.PointToScreen(m_Down);
overlay.Size = new Size(e.X - m_Down.X, e.Y - m_Down.Y);
}
}
private void tabPage5_MouseUp(object sender, MouseEventArgs e)
{
// do your stuff and then hide overlay..
overlay.Hide();
}
I have only coded for the standard case of a user dragging from the top left to the bottom right.
For the other cases you will need to do a little juggling with Math.Abs
& Math.Min
, calculating the Size
in absolutes and using the coordinate minima for the Location
..
To collect all covered Controls you will have to revert the overlay.Bounds
to the client coordinates using selectionRect = tabPage5.RectangleToClient (overlay.Bounds);
To collect nested Controls the selection could use a method like this one:
List<Control> controlSelection = new List<Control>();
List<Control> getControls(Control container, Rectangle rect)
{
controlSelection = new List<Control>();
foreach (Control ctl in container.Controls)
if (rect.Contains(ctl.Bounds))
{
controlSelection.Add(ctl);
foreach (Control ct in ctl.Controls) controlSelection.Add(ct); ;
}
return controlSelection;
}
To call it use:
Rectangle grabRect = tabPage5.RectangleToClient (overlay.Bounds);
controlSelection = getControls(tabPage5, grabRect);
Console.WriteLine(controlSelection.Count + " Controls grabbed.");
For multiple levels of nesting you will need a recursive function! For this case it may be better to leave the selectionRectangle
is screen coordinates and to transform the tested controls' bound to screen as well..
And, of course it is up to you to decide if a selection must just hit (Rectangle.IntersectsWith()
) or cover the targets completely; I have coded the latter (Rectangle.Contains()
).
C# winforms transparent form overlay issue
For some reason, the Color.DarkGray BackColor attribute for the transparent form was causing the issue. Changing the BackColor to Color.White fixed this.
Thanks to Patrice Gahide for helping me.
Form overlay showing behind form on move and resize
No matter how many times you call BringToFront()
it will not move your form on top of the active one. BringToFront()
does not make a control a top-level control, and it does not raise the Paint event.
There are too ways to go about fixing it. The best way IMO is to make your loading control a child of the main form instead of them being separate and you having to manually position the control after every move or resize.
The other method that could be done is to change the control window's z-order and activate it after every time a move, resize or maximize/minimize event is raised.
This can be achieved with a little bit of p-invokes:
public void FocusForm()
{
// force window to have focus
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const uint SW_SHOW = 5;
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(this.Handle);
ShowWindow(this.Handle, SW_SHOW);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(this.Handle);
ShowWindow(this.Handle, SW_SHOW);
}
this.Activate();
}
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
I use this to set my main window to be top most when started so you might want to lose the Activate()
call at the end.
I must say that even though this might work for you [I haven't fully tested it for move and resize], I suggest you revise your code and put the loading control form as a child to your main form.
EDIT:
If you need a transparent control then you can check the accepted answer to this SO question. I cannot post the code here as I do not want to make a false claim that it is my code.
Related Topics
Does C# Have Extension Properties
Convert String[] to Int[] in One Line of Code Using Linq
How to Turn an Int into an Array of Ints of Each Digit
Which Tls Version Was Negotiated
Linq - Left Join, Group By, and Count
Deep Null Checking, Is There a Better Way
Lifetime of ASP.NET Static Variable
How to Create a Dynamic Button Click Event on a Dynamic Button
Efficient Way to Remove All Whitespace from String
Copy File(S) from One Project to Another Using Post Build Event...Vs2010
Detecting Usb Drive Insertion and Removal Using Windows Service and C#
Remove Weird Characters ( a with Hat) from SQL Server Varchar Column
Why File.Readalllinesasync() Blocks the UI Thread
How to Call an Async Method from a Getter or Setter
Httpwebrequest Using Basic Authentication
Split a String with Delimiters But Keep the Delimiters in the Result in C#
Why Is It Bad to Use an Iteration Variable in a Lambda Expression