So what i have is a panel that's programmatically filled with custom controls using DockStyle.Top.
What i need is for the panel to get focus somehow when mouse cursor enters the panel so that the user can use mousewheel to scroll the panel.
I don't really want to give each control a handler because there could be hundreds of controls.
One way could be checking for mouse position and check if the panel contains it, which would probably require an extra thread or mousehook but perhaps there's a better way?
You may implement the MouseDetector class posted by Amen Ayach as an answer to a similar question and activate the form when the mouse hovers it:
void m_MouseMove(object sender, Point p)
{
Point pt = this.PointToClient(p);
if (this.ClientSize.Width >= pt.X &&
this.ClientSize.Height >= pt.Y &&
pt.X > 0 && pt.Y > 0)
{
this.Activate();
}
}
You should also set the Panel's AutoScroll value to true.
panel.AutoScroll = true;
Related
I've done a mini test program to prototype a way to drag and drop an image (at the right)(using a button as a support) to a panel (left part)(The current panel background letter are only for test purpose) and to move it inside the panel perimeter.
The image on the moving control is manually drawn during the Paint event :
void bouton_Paint( object sender, PaintEventArgs e )
{
Button but = sender as Button;
Bitmap img = new Bitmap(WindowsFormsApplication1.Properties.Resources.triaxe);
img.MakeTransparent(Color.White);
e.Graphics.DrawImage(img, 0, 0, but.Width, but.Height);
}
As you can see below, during the moving process, the background of the moved control is frezzed. So it is not very pretty
Is it to make the progress smoother ?
Thank you.
This is the code to move my triaxe on the form :
void bouton_MouseUp( object sender, MouseEventArgs e )
{
Button button = sender as Button;
button.Tag = false;
button.BackColor = Color.Transparent;
}
void bouton_MouseMove( object sender, MouseEventArgs e )
{
Button button = sender as Button;
if (button.Tag != null && (bool)button.Tag == true)
{
button.Left += e.X - MouseDownLocation.X;
button.Top += e.Y - MouseDownLocation.Y;
}
}
private Point MouseDownLocation;
void bouton_MouseDown( object sender, MouseEventArgs e )
{
Button button = sender as Button;
MouseDownLocation = e.Location;
button.Tag = true;
button.BackColor = SystemColors.Control;
}
Let's assume you do not want to draw the graphics alone but do want a Control with transparency move on top of another Control.
You have to solve two problems:
Winforms doesn't support transparency well; you have two options:
Either let the system fake it for you
Or do the faking yourself.
For the first it is enough to have a control with a transparent backcolor and an Image or BackgroundImage (depending on the control type) with transparency and then nest the moving control in the background control.
For a simplistic test you can add if (button.Parent != panel1) button.Parent = panel1; to your mousedown code. This will look jumpy but should display transparency correctly. (Don't forget to make the Backcolor transparent; in your code your make it SystemColors.Control.
To fake it yourself you would do exactly what the system does:
You get the target suface in a bitmaps (with DrawToBitmap) and then combine the area the mover currently covers with the image; here getting that area is key.
Then you can set that image as backgroundimage or draw it onto the mover.
The other problem is with the moving code. Here the issue is that when you move the mouse the MouseMove event is triggered and you can move the control. But by moving it the mouse will have moved relativly to the new location and the event will be triggered again leading to flicker an jumpiness!
To avoid this you can test the numbers or use a flag or unregister the move event before setting the location and re-register afterwards.
Also setting the location in one go instead of the two coordinates is a good idea..: button.Location = new Point(button.Left + e.X - MouseDownLocation.X, button.Top + e.Y - MouseDownLocation.Y);
Imo you should still consider drawing just the graphics on On panel.MouseMove and panel.Paint. On panel.MouseUp you can still add a Button to the panel.Controls right there. Both issues are avoided and you are free to add the functionality you want as well..
I have a Windows Forms application which is using a FlowLayoutPanel control to display a Picture boxes that are built dynamically. I have enabled the drag drop effect as they may want to reorder them, this works fine with only a few picture boxes (right now the screen shows about 6) but if there are more you try to drag an item below the control it will not scroll, so you cannot put an image that is currently on the screen (say image 4) to an image that is below what is visible (say image 13).
I have seen several posts where the ScrollControllIntoViewMethod should be used, I have tried in a few spots unsuccessfully.
Thanks!
Here is what I ended up doing.
Create the event on the DragLeave event
Getting the position of the control
Calculating the height of the control to get the lower boundary.
check the mouse position and if above the bounds, change the vertical scroll (or horizontal scroll) by a value in a Constant..
private void thumbFlow_DragLeave(object sender, EventArgs e)
{
int BegY_ThumbFlow = this.thumbFlow.FindForm().PointToClient(this.thumbFlow.Parent.PointToScreen(this.thumbFlow.Location)).Y;
int thumbFlowBound_Y = this.thumbFlow.Height + BegY_ThumbFlow;
int mouseY = this.thumbFlow.FindForm().PointToClient(MousePosition).Y;
while (mouseY >= thumbFlowBound_Y)
{
thumbFlow.VerticalScroll.Value = thumbFlow.VerticalScroll.Value + DRAG_DROP_SCROLL_AMT;
mouseY = thumbFlow.FindForm().PointToClient(MousePosition).Y;
thumbFlow.Refresh();
}
while (mouseY <= BegY_ThumbFlow)
{
thumbFlow.VerticalScroll.Value = thumbFlow.VerticalScroll.Value - DRAG_DROP_SCROLL_AMT;
mouseY = thumbFlow.FindForm().PointToClient(MousePosition).Y;
thumbFlow.Refresh();
}
}
Hope this helps others.
I've just finished building a portion of a program which deals with a UI in a table layout panel. This has worked so far but i've noticed that, before i could try my controls (functionality i added) at runtime around the form, but now it is in cells, they can't be moved outside of their container cell. HOWEVER, this is great and exactly what i needed, but im finding that the controls (for example a button) will be correctly contained in the cell on the left, and top boundaries of the cell, but the bottom and right boundaries allow the control to disappear off of it. Heres some screenshots to demonstrate:
Here we see that the button control cannot move past the top and left bounds of the cell.
However here it seems to be able to move past the bottom and right bounds of the cell.
Looking back at how i allow my controls to move, i came across a section where i had set up some variables, shown below:
public static void MouseMove(object sender, MouseEventArgs e)
{
Control control = sender as Control;
Control container = sender as Control;
if (control != null)
{
if (Dragging)
{
if (direction != Direction.Vertical)
{
container.Left = Math.Max(0, e.X + container.Left - DragStart.X);
}
if (direction != Direction.Horizontal)
{
container.Top = Math.Max(0, e.Y + container.Top - DragStart.Y);
}
}
}
}
I figured here i'm not setting a bottom and right container bounds, which would make sense, however upon exploring the intelisense, i can't seem to get container.right and container.bottom as they come with the following tooltip:
"gets the distance, in pixels, between the right edge of the control, and the left edge of it's container's client area"
and the bottom does the same, only for the bottom of the control and top of the container area.
Is there away around this? perhaps an option somewhere which connects the bottom of the control to the bottom bound of the cell, and the same for the right?
edit 1: alternatively perhaps i need to alter my mousemove event to handle collision better, so if anyone has any ideas on this too, that'd be great, i've not really looked at much collision detection before, especially in winforms.
Control.right is a read only property. Try setting
if (direction != Direction.Vertical)
{
container.Left = Math.Max(0, e.X + container.Left - DragStart.X);
container.Left = Math.Min(container.Left, container.Parent.Width - container.Width;
}
if (direction != Direction.Horizontal)
{
container.Top = Math.Max(0, e.Y + container.Top - DragStart.Y);
container.Top = Math.Min(container.Top, container.Parent.Height - container.Height;
}
I am a new C# developer and I want to create a hotspot in an image that I put in my winform application. I followed the solution posted HERE, but I did not know where I should put the coordinates to make this method works:
protected override void OnMouseMove(MouseEventArgs mouseEvent)
{
string X = mouseEvent.X.ToString();
string Y = mouseEvent.Y.ToString();
}
Where should I put the coordinates? I have two coordinates (X,Y): 110, 45
Hotspot I feel should be a small rectangular area rather than just a coordinate. Suppose you want it to be a small square area of width 20 then you would write something like this:
EDIT:
Suppose you have a PictureBox on your form called PictureBox1 and you want that a small rectangle of say 20x20 size starting from Top-Left corner of the picturebox become a hotspot (i.e. when you take mouse over it you would see a HAND cursor) then on the MouSeMove event of the PictureBox write this:
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.X > 0 && e.X < 20 && e.Y > 0 && e.Y < 20)
this.Cursor = Cursors.Hand;
else
this.Cursor = Cursors.Default;
}
Please remember, we are just showing the Hand Cursor to denote a hotspot we have not yet handled a Click for that matter, to make it really a web kind hotspot. If you want to do something on Click, try using the MouseUp event, in the MouseUp event the same IF clause as above would give you the condition that user has clicked on the hotspot region.
I have this Windows Forms application with a simple balloon tooltip. Depending on the application's window location on the desktop and the mouse cursor location, the balloon 'tip' (or balloon pointing arrow) may or may not be pointing to the location I want.
For instance, my app snaps to the desktop sides and when it's snapped to the right side, if the mouse cursor is below 100px of the right side, the balloon 'tip' will point to the wrong place. But if the mouse cursor is anywhere else, it will point to the right place.
In this situation I wanted to fake the mouse cursor position (without actually changing the mouse cursor position) to be somewhere else so the the problem wouldn't occur.
Is this possible? How can I achieve this?
private void noteTitleInput_KeyPress(object sender, KeyPressEventArgs e) {
if(e.KeyChar == Convert.ToChar(Keys.Return, CultureInfo.InvariantCulture) && noteTitleInput.Text.Length > 0) {
e.Handled = true;
noteInputButton_Click(null, null);
} else if(!Char.IsControl(e.KeyChar)) {
if(Array.IndexOf(Path.GetInvalidFileNameChars(), e.KeyChar) > -1) {
e.Handled = true;
System.Media.SystemSounds.Beep.Play();
noteTitleToolTip.Show("The following characters are not valid:\n\\ / : * ? < > |",
groupNoteInput, 25, -75, 2500);
return;
}
}
noteTitleToolTip.Hide(groupNoteInput);
}
I'm not quite sure why do you need to set cursor position, because you can set tool tip to appear where you tell it, and not necessarily where the mouse is.
For example:
tooltip1.Show("My tip", controlOnWhichToShow, 15, 15);
would display the tip at upper left corner of the controlOnWhichToShow, 15 points away from edges.
If I misunderstood you, than please specify at which point in time is the mouse position being used.
If you sync the MouseHover event, you can create the Tooltip as veljkoz describes. In this way you can place the tooltip as you like. The code would look smething like this:
protected override void OnMouseHover(EventArgs e)
{
ToolTip myToolTip = new ToolTip();
myToolTip.IsBalloon = true;
// TODO The x and y coordinates should be what ever you wish.
myToolTip.Show("Helpful Text Also", this, 50, 50);
base.OnMouseHover(e);
}
Hope that helps.
In Windows Forms the mouse is captured by the control when the user presses a mouse button on a control, and the mouse is released by the control when the user releases the mouse button.
The Capture property of the Control class specifies whether a control has captured the mouse. To determine when a control loses mouse capture, handle the MouseCaptureChanged event.
Only the foreground window can capture the mouse. When a background window attempts to capture the mouse, the window receives messages only for mouse events that occur when the mouse pointer is within the visible portion of the window. Also, even if the foreground window has captured the mouse, the user can still click another window, bringing it to the foreground. When the mouse is captured, shortcut keys do not work.
More here. Mouse Capture in Windows Forms
You can do what you say with a Class. You can do it in a very simple way.
one create class and
namespace MousLokasyonbulma
{
class benimtooltip : ToolTip
{
[System.Runtime.InteropServices.DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr h, int x, int y, int width, int height, bool redraw);
public benimtooltip()
{
this.OwnerDraw = true;
this.Draw += Benimtooltip_Draw;
}
private void Benimtooltip_Draw(object sender, DrawToolTipEventArgs e)
{
e.DrawBackground();
e.DrawBorder();
e.DrawText();
var t = (ToolTip)sender;
var h = t.GetType().GetProperty("Handle",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var handle = (IntPtr)h.GetValue(t);
var location = new Point(650, 650);
var ss= MoveWindow(handle, location.X, location.Y, e.Bounds.Width, e.Bounds.Height, false);
}
}
}
full Code MyGithup
Example Project image
https://i.hizliresim.com/1pndZG.png
https://i.hizliresim.com/Lvo3Rb.png