• 0

[C#] Highlighting a panel and all Controls with a colour


Question

Hi,

I've tried a number of approaches to this and have settled on one that 'sort' of works but seems like a terrible solution.

I have a panel control (UserControl item) that exists on screen with a load of others. As the mouse goes over this panel control it is to have a pale blue background. This panel control also has many Controls within it, whos back colours must also be changed.

Obviously, when the mouse enters the panel, it fires the mouseEnter event of the control and everything can be changed as required. However, when the mouse goes over one of the contained controls, it fires the mouseLeaving event for the parent Control and the mouseEnter for the newly mouse-overed control.

So, at the moment, I have one method for mouseIn, and one for MouseOut which are constantly alternated causing a slight white flicker as it changes between items within being mouse-overed.

I tried to test for the pointer position in the mouseOut code and not run it if it's still within the outer bounds of the main Control but to no avail. Does anyone know how to sort this, and (if possible) code samples would be really useful as I've already messed this up a few times!!!

Thanks,

Chris

12 answers to this question

Recommended Posts

  • 0

Do something like this:

		private void userControl11_MouseEnter(object sender, EventArgs e)
		{
			userControl11.BackColor = Color.LightBlue;
			makeAllOfUserControl1sControlsLightBlueMofo();
		}

		private void Form1_MouseEnter(object sender, EventArgs e)
		{
			userControl11.BackColor = Color.Empty;
			makeAllOfUserControl1sControlsNormalMofo();
		}

In other words, don't use utilize any MouseLeaving events.

  • 0
  boogerjones said:
Do something like this:

		private void userControl11_MouseEnter(object sender, EventArgs e)
		{
			userControl11.BackColor = Color.LightBlue;
			makeAllOfUserControl1sControlsLightBlueMofo();
		}

		private void Form1_MouseEnter(object sender, EventArgs e)
		{
			userControl11.BackColor = Color.Empty;
			makeAllOfUserControl1sControlsNormalMofo();
		}

In other words, don't use utilize any MouseLeaving events.

Sometimes the mouse moves too fast over the form, and the Form_MouseEnter was never fired. Handling MouseLeaving takes care of that (and opens up a different can of worms, as the OP experienced).

@OP If you're experienced with Win32 APIs, there's are some functions you can use. Checking the mouse position point, getting a rectangle definition of a control, then checking whether a point is inside a rectangle. You can then utilise them in your MouseLeaving handler. Sorry, it's been a while, and I can only remember these vaguely...

  • 0

OK, then try this:

		private void userControl11_MouseEnter(object sender, EventArgs e)
		{
			userControl11.BackColor = Color.LightBlue;
		}

		private void userControl11_MouseLeave(object sender, EventArgs e)
		{
			if (AmIStillInsideTheUserControl(userControl11) == false)
				userControl11.BackColor = Color.Empty;
		}

		private bool AmIStillInsideTheUserControl(Control control)
		{
			Point whereTheHellIsMyUserControl = control.PointToScreen(new Point(0, 0));
			return (Cursor.Position.X > whereTheHellIsMyUserControl.X && Cursor.Position.X < (whereTheHellIsMyUserControl.X + control.Width) &&
					Cursor.Position.Y > whereTheHellIsMyUserControl.Y && Cursor.Position.Y < (whereTheHellIsMyUserControl.Y + control.Height));
		}

It checks to see if the mouse is still inside the user control before resetting the color.

Edited by boogerjones
  • 0

Hmm it's all coming back now. I forgot .Net has all these functions built in.

Here's a simpler version:

	
private bool AmIStillInsideTheUserControl(Control control)
{
  Rectangle r = control.RectangleToScreen(control.ClientRectangle);
  Point p = Cursor.Position;
  return r.Contains(p);
}

Although, I just realised that there's still a flaw in this method. It won't work if the container control is partially covered by *another window* and the mouse moved to that window, but still within the rectangle bounds of your container.

  • 0
  GreenMartian said:
Hmm it's all coming back now. I forgot .Net has all these functions built in.

Here's a simpler version:

	
private bool AmIStillInsideTheUserControl(Control control)
{
  Rectangle r = control.RectangleToScreen(control.ClientRectangle);
  Point p = Cursor.Position;
  return r.Contains(p);
}

Although, I just realised that there's still a flaw in this method. It won't work if the container control is partially covered by *another window* and the mouse moved to that window, but still within the rectangle bounds of your container.

Nice simplification, but the rectangle.Contains() method just does the exact calculation that I was doing anyway. The remaining flaw is a pretty picky one, though it would be nice to have a 100% working implementation.
  • 0
  boogerjones said:
Nice simplification, but the rectangle.Contains() method just does the exact calculation that I was doing anyway. The remaining flaw is a pretty picky one, though it would be nice to have a 100% working implementation.

Yeah, it's picky, but a pretty common case :)

Here's one that might work:

Declare this on your form's method declarations:

[DllImport("user32")]
public static extern IntPtr WindowFromPoint(int xPoint, int yPoint);

Then use this:

private bool AmIStillInsideTheUserControl(Control control)
{
  bool insidechild = false;
  Point p = Cursor.Position;
  IntPtr handle = WindowFromPoint(p.X, p.Y);

  foreach (Control child in control.Controls)
	if (child.Handle == handle)
	{
	  insidechild = true;
	  break;
	}
  return insidechild;
}

It will handle the case of leaving to another window covering the container..

EDIT: If you have containers inside the container, you might want to take the child control checking out to a recursive function...

Edited by GreenMartian
  • 0
  boogerjones said:
I almost wonder if this is a bug in the Windows messaging pipeline. Shouldn't the control.MouseLeave event be called if the mouse rolls over an obscuring window?

It is called, but our rectangle-checking method will tell us that the cursor's still inside the rectangle..

  • 0
  GreenMartian said:
Hmm it's all coming back now. I forgot .Net has all these functions built in.

Here's a simpler version:

	
private bool AmIStillInsideTheUserControl(Control control)
{
  Rectangle r = control.RectangleToScreen(control.ClientRectangle);
  Point p = Cursor.Position;
  return r.Contains(p);
}

Although, I just realised that there's still a flaw in this method. It won't work if the container control is partially covered by *another window* and the mouse moved to that window, but still within the rectangle bounds of your container.

  GreenMartian said:
Yeah, it's picky, but a pretty common case :)

Here's one that might work:

Declare this on your form's method declarations:

[DllImport("user32")]
public static extern IntPtr WindowFromPoint(int xPoint, int yPoint);

Then use this:

private bool AmIStillInsideTheUserControl(Control control)
{
  bool insidechild = false;
  Point p = Cursor.Position;
  IntPtr handle = WindowFromPoint(p.X, p.Y);

  foreach (Control child in control.Controls)
	if (child.Handle == handle)
	{
	  insidechild = true;
	  break;
	}
  return insidechild;
}

It will handle the case of leaving to another window covering the container..

EDIT: If you have containers inside the container, you might want to take the child control checking out to a recursive function...

Both of those seem pretty good actually... I'll whack them in to the project in a minute and see if we can't fix what is just so ugly in code.

Thanks so much for all of your efforts!!!

Chris

  • 0
  Mike said:
How about changing the colour on MouseEnter of your control and changing it back on MouseEnter of the parent object of your control (in most cases, the form)?

Because sometimes if you move your mouse just a bit too fast, the form one won't be fired.

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • Cjam 2.0 by Razvan Serea Cjam is a lightweight and fast MP3 editor for Windows that lets you cut, join, and edit MP3 files without re-encoding. This means your audio quality remains untouched, and edits happen instantly. Cjam is ideal for quick, lossless edits—whether you're trimming music, combining tracks, or preparing audio for learning tools or podcasts. It features batch processing, scripting support, cue and playlist file handling, and a simple interface. Cjam is perfect for anyone who needs efficient MP3 editing without the complexity of full audio suites. Cjam requires a PC running Windows 10 or later and Microsoft .NET 6.0 or later. Key features for Cjam: No Re-encoding: Edit MP3 files without losing quality. Cut and Join MP3: Easily cut, trim, and combine MP3 tracks. Batch Processing: Edit multiple files at once for faster workflows. Scriptable Interface: Automate tasks with a custom command language. Cue and Playlist Support: Handle CUE and playlist files for seamless audio management. Fast and Lightweight: Quick processing with minimal system resources. Lossless Audio Editing: Ensure your edits don't affect audio quality. Simple User Interface: Clean, intuitive design for easy navigation. File Format Support: Works with MP3, Cjam-specific file formats (CJAMC, CJAMJ, CJAM). Cjam 2.0.0.0 fixes: Fixed a bug where the folder list was not updating on the vmp3 screen Download: Cjam 2.0 | 1.3 MB (Freeware) Links: Cjam Home Page | Cjam Manual | Screenshot Get alerted to all of our Software updates on Twitter at @NeowinSoftware
    • Honestly, i either don't care, mind, use, or had any problem with those. 11 is really good for me, has a lot of little refinements, looks great, if i wanted to tweak/fix it's behavior i would with a range of tools, and wouldn't come back to the 2010's looking Win 10 even at gunpoint.
    • You dont want a expensive hp laptop either managed to get 3 new zbooks and they all died on me.
    • Nothing inherently wrong, but why buy 2021 tech in 2025? Assuming you were aiming for 6-10 years of usage, better to buy something current.
    • I have begun using Windows 11 native passkey feature. i have four passkeys set up so far. Three work fine, One has never worked. I have removed it and recreated it several times, still no luck. Anyway, on the websites in which it works, it works geat. No more two 2FA.
  • Recent Achievements

    • Dedicated
      Cole Multipass earned a badge
      Dedicated
    • Week One Done
      Alexander 001 earned a badge
      Week One Done
    • Week One Done
      icecreamconesleeves earned a badge
      Week One Done
    • One Year In
      PAC0 earned a badge
      One Year In
    • One Month Later
      PAC0 earned a badge
      One Month Later
  • Popular Contributors

    1. 1
      +primortal
      567
    2. 2
      +FloatingFatMan
      188
    3. 3
      ATLien_0
      186
    4. 4
      Skyfrog
      114
    5. 5
      Som
      109
  • Tell a friend

    Love Neowin? Tell a friend!