Mouse Enter & Mouse Leave on a form - c#

I have a form with child controls.
I want when user move mouse over the form, the form will be closed.
So I catch mouse enter and move leave on the form. But if I move mouse on any controls in form, mouse leave event will be also caught.
Please help me to solve this problem. Thanks.
UPDATE:
When the cursor's position is on the form's caption region (this region is called non-client region). I move mouse out of this region, I can't receive the WM_MOUSELEAVE message as well as WM_NCMOUSELEAVE. Please help me in this problem. I want to receive a message when move mouse out of this region. Thanks.

Essentially you want to check if the cursor is in the scope of the control. Here is the solution:
(1) Add a Panel in the form which is the same size as your Form, and move all controls in the form to the panel. It's easy to change: open MyForm.designer.cs, add the panel, and change all statements like this.Controls.Add(myLabel); to this.myPanel.Controls.Add(myLabel);.
(2) Deal with MouseEnter and MouseLeave events of the panel you added.
myPanel.MouseEnter += (sender, e) =>
{
//enter
};
myPanel.MouseLeave += (sender, e) =>
{
if (Cursor.Position.X < myPanel.Location.X
|| Cursor.Position.Y < myPanel.Location.Y
|| Cursor.Position.X > myPanel.Location.X + myPanel.Width
|| Cursor.Position.Y > myPanel.Location.Y + myPanel.Height)
{
//out of scope
}
};
(3) Why not use Form in step 2? Why do we need a Panel with the same size? Try it yourself. The narrow border of the form will make you crazy.
(4) You can make the if statements in step 2 to an extension method, which is helpful to furthur usage.

this is happening because you have gap between your child Controls on leaving from controls the form_mouseEnter event fires automatically
a way you can do like placing controls with no gap
or
If you don't want user to leave your Control you can set boundary of cursor
use this
Cursor.Clip=Control_name.Bounds;

Related

PointToScreen returning variable results during layout

EDIT:
So far all the answers have pointed out the code as originally written was hacky. I didn't write it, and don't understand fully how it all worked. However, in the general case, it did work. I have tried various tidy-ups, but they don't fix the basic problem, because of the strange behaviour of PointToScreen.
An alternative to explaining that behaviour, which I can see is difficult to explain without understanding the inner working of the rest of the form (and I don't at the moment), is to come up with an alternative way to implement the desired functionality, which is a small dialog appearing on top of a button when the button is pressed. The current implementation is a form which appears on top, and then tracks the original form to maintain its position. Is there a cleaner option?
Original Question:
I'm trying to position a form (form A) on top of a control (button B) on a form (form C) using PointToScreen:
Point buttonCorner = buttonB.Parent.PointToScreen(buttonB.Location);
where buttonB is a button in a FlowLayoutPanel on a form.
Most of the time it works, I get the position I expect. I use this code in a LocationChanged event on the form, so that form A tracks button B. This is working fine.
However, when another action causes the parent form to be resized, I find that the position of buttonCorner is offset, such that form A ends up off the screen (to the right). No part of my form is off the screen before this event.
The only theory I can come up with is that the LocationChanged event is firing while the FlowLayoutPanel is re-arranging, and it returns a bad position during that time. It seems a little far-fetched, but I don't have a better theory.
Suppose you have panelA and panelB. You have to register the LocationChanged of the panelB not of the form:
panelB.LocationChanged += (s,e) => {
Point buttonCorner = PanelControlFlow.PointToScreen(PanelControlFlow.Location);
//...
};
Anyway I can feel that your code has wrong approach, your 2 controls may not need to track each other unless you change their locations at runtime. You should provide more details so that we can find another better approach. Note that the FlowLayoutPanel will compact the controls automatically and positioning controls on it won't have any effect.
UPDATE:
For the reason why your PointToScreen returns some off-screen Point. I've tested this, when the form is minimized, its Location is -32000, -32000. All the PointToScreen will be added with this Location, that means if your control has Left calculated on your form is 300, then its Left calculated on the screen will be approximately -32000 + 300 = -31700. The same for Top. That's why your control's Location goes off screen. So you have to register the LocationChanged of the control you want to track to not the form. Why does the minimized window have Location of -32000,-32000? I think that's how a Window is hidden from screen.
Point buttonCorner = PanelControlFlow.PointToScreen(PanelControlFlow.Location);
That code is definitely wrong, the Location value is relative to the control's Parent. If you want to know where the panel's upper-left corner is located then you must use:
Point panelCorner = PanelControlFlow.PointToScreen(Point.Empty);
or for a button in the panel:
Point buttonCorner = someButtonInPanel.Parent.PointToScreen(someButtonInPanel.Location);
Then to get another button on top:
anotherButton.Location = anotherButton.Parent.PointToClient(buttonCorner);

getting mouse position of different control

I have a panel (panel2) inside another panel (panel1). I want to get mouse position of panel1, but when I move my mouse over panel2, the following code stops working.
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
label1.Text = "Offset: " + e.X + " x " + e.Y;
}
How can I get it to read the mouse arguments, even if the mouse is over panel2? Thanks!
EDIT: panel2 is located at center x=100, y=100 of panel1. if I move my mouse on panel2 left top corner it gives me coordinates for example 1x1, where I need to location on panel1 like 101x101
EDIT 2: I'm not trying to drag it, just read the coordinates of original panel (panel1) so I can calculate the offset for zooming the panel2. So I only need mousemove, nothing else. Thanks
If you only need to do this while a mouse button is being held down (for example, because you are tracking a drag and drop operation or a selection) then you can do the following:
In your MouseDown handler, call this.Capture = true;
Now your MouseMove handler will receive mouse move messages even when the mouse is over another control.
In your MouseUp handler, call this.Capture = false; - Note: If you forget to do this, your other controls in the same process will not receive any mouse messages.
Other than that, it's very tricky to get MouseMove messages from other controls without adding mouse handlers to those other controls.
The main thing about this.Capture is that you need a good time to set it to true and another good time to set it back to false. Generally, that's done in MouseDown and MouseUp as I described.
However, you could also convert the coords from Panel2-relative to Panel1-relative like so:
Convert from Panel2 coords to screen coords:
Point screenCoords = panel2.PointToScreen(mouseCoordInPanel2);
Then convert from screen coords to Panel1-relative coords:
Point mouseCoordInPanel1 = panel1.PointToClient(screenCoords);
To do this you would have to have a MouseMove handler in Panel2 where you did this conversion, and Panel2 would need a reference to Panel1 in order to call panel1.PointToClient()
You must also assign to the event of the other panel.
can't you put the event handler in panel2, then use the left/top properties of panel1 and panel2 to offset the mouse position within panel2 to get your desired location in panel1?
I also think that assigning an event to the second panel would be the best thing. When the mouse is on Panel 1, the coordinates would be provided directly; when it is on Panel 2, they would be converted by accounting for the relative positions between both panels (pretty straightforward: variation in X/Y positions; values which do not need to be hardcoded but updated at runtime).

Removing Windows' ugly Selection marker thing from Splitter in SpitContainer Control

I have a SplitContainer control, and the Splitter in the middle is very ugly. By setting the BackColor of the SplitContainer to (insert color here), then setting the BackColor of Panel1 and Panel2 to white, I can have my splitter looking nice. But by default, Windows puts the selection mark over the Splitter, even before it's selected.
How can I make sure that the selection mark never shows on the Splitter?
I think by "Selection Marker Crap", you mean the fuzzy line that indicates the control is selected. If you don't want this showing up, set some other control to be selected at startup. Something like:
Textbox1.Selected = true;
This should solve your issue if it is just one of it not being selected. However, this will come back if you select the item to resize something. In that case, you could put something in the mouse_up event to move the selection off of the control. That way, the user moves the splitter bar and then when they let go, the selection gets cleared off of the splitter.
Another way would be to make the splitter bar narrow enough that the gray fuzzy line doesn't show up. To do this, you could do the following (tested):
splitContainer1.BorderStyle = BorderStyle.FixedSingle;
splitContainer1.SplitterWidth = 1;
I experienced the same problem, and fixed it by setting TabStop to False in the Properties window for SplitContainer1.
This could annoy people who depend or insist on using the keyboard to operate every aspect of your form, but other than that it will work. Controls inside the SplitContainer will remain tab-able, just not the SplitContainer itself.
This code will move the focus from the splitContainer to TreeView shortly after moved.
private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) {
if(this.splitContainer1.CanFocus) {
this.splitContainer1.ActiveControl = this.treeView1;
}
}
You could add an event handler to steal the focus from the container on MouseUp's... It's a little messy but it works. :)
I tried a lot to remove splitter but nothing work. I did some different why we need to use splitter for that we can use picture box control make it width (or) height depend upon your project set 5 or 3 .... after picture box mouse move event write code like...
picturebox property-cursor change the cursor type Hsplit its look like splitter
private void picturebox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)//this for mouse left click its work
{
//write you code here if you use panel set panel height or width it reaches...
Cursor.Position = new Point(e.X, e.Y); // this for mouse cursor position according your //project do some fine tune you will get its work...
}
its work because i tried lot for this and i itself found this method...
I set the TabStop to false and it went away.
Most simple solution i found/made - create a button, select it, and hide it.
All via code. there is not side effects or problems with this, place it in the forms load event.
Button DeSelectButton = new Button();
this.Controls.Add(DeSelectButton);
DeSelectButton.Select();
DeSelectButton.Visible = false;

Is it possible to specify the position of a Windows Form controls relative to another AutoSize'd control?

I have a Windows Form window containing a FlowLayoutPanel, an OK Button, and a Cancel Button. The Form and FlowLayoutPanel both have AutoSize enabled, and the FlowLayoutPanel grows or shinks depending on the items placed in it.
I am trying to figure out how to position the OK and Cancel Buttons in the same row directly below the FlowLayoutPanel. I can't just specify positions for them since the FlowLayoutPanel above them grows and shrinks.
Any ideas on how to solve this?
Anchoring the buttons to the bottom of the form smells like a solution. If not, you can throw more panels at the problem but that's fugly. Simply using the Resize event can do wonders:
private void flowLayoutPanel1_Resize(object sender, EventArgs e) {
OKButton.Top = CancelButton.Top = flowLayoutPanel1.Bottom + 10;
}
Put your two buttons in another panel (anything will do).
Then put these two panels in another FlowLayoutPanel which arranges them top to bottom.

Anchoring a Windows Forms Tooltip to the mouse

I want to show a tooltip when hovering over a button and as long as the mouse is over the button the tooltip should follow the mouse. What is the correct way to achieve that?
When I add a MouseMove event that calls tooltip.Show(...) with the updated mouse position it flickers extremely, and also redraws the tooltip when the mouse rests. And if it is an OwnerDraw tooltip I can see the default system tooltip style "fighting" with the self-drawn tooltip.
Indeed, with .Net 2.0 the ToolTip object has been altered. Before 2.0, there were some inconsistency problems when the ToolTip text was changed while the ToolTip was active, or with some other situations.
Since 2.0, the Tooltip is hidden each time something happens what could affect the currently active Tooltip.
While this solved some problems, it now causes some events being fired right after e.g. a SetToolTip(), even if this function has been called from within this very event, resulting in an endless loop of ToolTip draw/hide until the mouse moves away from the ToolTip area.
My own workaround is to check whether the ToolTip is already the same and omitting the Set ToolTip() if so. (simply omitting the next event by a static flag as suggested above can cause problems as there is no guarantee that there will be a new event right after, e.g. if the mouse has just touched the ToolTip area and moved away already).
Also, using OnMouseHover just to display a Tooltip disables the internal timer functionality of the ToolTip component as well as causing many many unnecessary events and therefore wastes processor time. The Popup Event of the ToolTip component serves well as point of action.
In this special case, however, OnMouse Hover is necessary to track the mouse movement.
Anyways, altering the ToolTip position causes a complete redraw of the Tooltip and therefore flicker. This can be reduced for a motionless mouse by checking whether the mouse position has changed between two events.
Unfortunately, the ToolTip component has no way to change the position of the ToolTip adn is shown always relative to the current mouse position. So the only way to have it follow the mouse is to close and redraw it.
it MAY help to set the UseFading and/or UseAnimation properties to false so the flicker can be further reduced.
OK, this may be complete overkill, and probably not the best solution, but I think a fun little hack nonthless.
Basically, I'm drawing a ListView at the location of the mouse. Some code:
ListView v = new ListView();
public Form1()
{
InitializeComponent();
v.Items.Add("Foo");
v.Height = 30;
v.Width = 50;
this.button1.Controls.Add(v);
v.MouseMove += new MouseEventHandler(v_MouseMove);
v.BackColor = SystemColors.Info;
this.button1.MouseMove += new MouseEventHandler(button1_MouseMove);
}
void v_MouseMove(object sender, MouseEventArgs e)
{
v.Location = new Point(v.Location.X + e.Location.X, v.Location.Y + e.Location.Y);
}
void button1_MouseMove(object sender, MouseEventArgs e)
{
v.Location = e.Location;
}
I've noticed that when manually showing a tooltip with OnMouseHover, OnMouseMove gets called one more time after the tooltip is shown. As a hack, I've ignored the next OnMouseMove call immediately following the tooltip being shown (using a flag). Perhaps a similar phenomenon is occurring?

Categories

Resources