I'm trying to accomplish what I thought would be somewhat straight forward, but apparently isn't.
What I'd like to accomplish is as follows. The user presses a button in a toolbar, this allows the state of the UI to change. Now that the state has changed when the user clicks mouse-down they can create a box on the screen by dragging the mouse. Upon the mouse-up I want to return the x,y coord.
So basically something like this
protected void MyUI_MouseDown(object inSender , MouseEventArgs inArgs)
{
switch(myState)
{
case CreateBox:
Rectangle rect = DrawBox();
}
}
public Rectangle DrawBox()
{
myDrawFlag = true;
}
private MyUI_MouseMove(object inSender , MouseEventArgs inArgs)
{
if(myDrawFlag)
{
DrawBox(inArgs.X , inArgs.Y);
}
}
Basically, I'm not sure how to get from point A to point C. The mouse down changes the state of the UI and lets me draw on the screen via the Mouse Move - but I want to return the value upon the Mouse UP.
I know I'm doing something wrong - could someone tell me what?
Edit 1: Yes, there is nothing in DrawBox(). Basically my question is how do I have that method not return UNTIL, I get the mouse-up event?
Edit 2: I am tracking the mouse movement events. As the mouse moves I am updating the start X,Y and the new endpoint X,Y. I still think I'm not asking this question correctly.
I don't want return DrawBox() until the mouse-up event. Mouse-Down should just notify the UI it can draw a box on the screen. Mouse-Move (which I'm using) updates the coordinates. And then Mouse-Up should tell the UI it can't draw anymore and ONLY THEN should DrawBox() return with the points.
The idea to wait inside the MouseDown method until die MouseUp event is fired is not the way to go. You have to think event driven. Better create/save your final object in the MouseUp method.
protected void MyUI_MouseDown(object inSender, MouseEventArgs inArgs)
{
switch(myState)
{
case CreateBox:
Rectangle rect = new Rectangle(inArgs.X, inArgs.Y, 0, 0);
break;
}
}
protected void MyUI_MouseUp(object inSender, MouseEventArgs inArgs)
{
rect.Width = inArgs.X - rect.X;
rect.Height = inArgs.Y - rect.Y;
// now save/draw your object
}
You can store your points in a struct and then fill up the struct in the MouseUp event, and reuse it where you wish.
struct coords
{
int x;
int y;
}
coords my_coords;
protected void MyGui_MouseUp(object sender, MouseEventArgs args)
{
my_coords.x = args.x;
my_coords.y = args.y;
}
//here you can use my_coords to what you need...
You need to handle the MouseUp event. The MouseMove event you are handling will fire every pixel change in distance that the mouse moves so you are in effect calling the DrawBox(int, int) method hundreds of times. If you handle the MouseUp event instead you will get the coordinates when the mouse button is released.
As far as i see it, you have 3 states:
Normal, which doesn require any explanation.
DesignMode, When the button in he toolbar is clicked.
DrawingBox, When you are actually drawing the box
Now you want the following transition:
Normal -> DesigMode -> OnDrawingBox -> AfterDrawingBox.
This can implemented using a state machine or an enum. With the enum, your code will be something like this:
enum DrawBoxState { Normal, DesignMode, DrawingBox }
DrawBoxState _currentState = DrawBoxState.Normal;
Point _startPoint;
Point _endPoint;
void OnToolbarButtonClicked(object sender, EventArgs e)
{
switch (_currentState)
{
case DrawBoxState.Normal:
_currentState = DrawBoxState.DesignMode;
break;
default:
_currentState = DrawBoxState.Normal;
break;
}
}
void OnMouseDown(object sender, MouseEventArgs e)
{
switch (_currentState)
{
case DrawBoxState.DesignMode:
{
_currentState = DrawBoxState.OnDrawingBox;
_startPoint = e.Location; // not sure if this is right
}
break;
}
}
void OnMouseUp(object sender, MouseEventArgs e)
{
switch (_currentState)
{
case DrawBoxState.DrawingBox:
{
_currentState = DrawBoxState.Normal;
_endPoint = e.Location;
}
break;
}
}
Now you can simply, raise an event every time the state changes, and adept changes on that event. e.g. if state changes to normal, check if startPoint and endPoint have been set and therefore do something with the value's.
Related
I have a ListView with the View set to LargeIcon.
I specifically need to detect when multiple items were selected by dragging a selection box around them with the mouse.
(For example I don't want to know when items were selected by CTRL + Click)
I thought I could simply do it by keeping track of whether the mouse was down while it was moving which would indicate dragging, then on mouse up if it was a drag then I can set another variable to indicate this.
In my example below mouseDown is set to true, but when I keep the mouse down and move it isDrag is never set to true and I can't see what I'm doing wrong.
(Edit: isDrag becomes true if I remove the if clause which is weird because as I said mouseDown is definitely true).
I realise the code is a little longer than it needs to be but it's for clarity.
bool mouseDown;
bool isDrag;
bool wasDrag;
private void listView1_MouseDown(object sender, MouseEventArgs args)
{
wasDrag = false;
mouseDown = true;
}
private void listView1_MouseMove(object sender, MouseEventArgs args)
{
if (mouseDown)
isDrag = true; // <-- Never becomes true, even though mouseDown is true
}
private void listView1_MouseUp(object sender, MouseEventArgs args)
{
if (isDrag)
wasDrag = true;
mouseDown = false;
isDrag = false;
}
I know it'll be something stupid. Please put me out of my misery.
Alternatively if someone knows of a better was to detect a dragging selection (what's the proper term?) then I'm all ears.
Can you try this:
private void listView1_MouseMove(object sender, MouseEventArgs args)
{
isDrag = mouseDown;
}
I think for some reason, your event listView1_MouseUp still fires, which makes your isDrag variable set to other than the intended value. Try to put breakpoints on both MouseMove and MouseUp events to see the sequence with which they are firing.
After further investigation I've discovered that for a ListView control the MouseMove event will not fire while MouseDown is still occurring and fires immediately after releasing the mouse.
I can only assume that the logic built into this control that allows you to select multiple files by dragging a selection is messing with these events and essentially making them synchronous.
I've put together a basic workaround for this. It's not ideal but it does the job so I thought I'd share.
Basically when the mouse goes down I record the position. When the mouse goes up I check to see if it has moved more than a certain distance in any direction. If it has not I consider it a click, if it has I consider it a drag.
// Records the mouse position on mousedown
int beforeMoveX;
int beforeMoveY;
// How far in pixels the mouse must move in any direction
// before we consider this a drag rather than a click
int moveBounds = 20;
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
// Save the mouse position
beforeMoveX = e.X;
beforeMoveY= e.Y;
}
private void listView1_MouseUp(object sender, MouseEventArgs e)
{
// Did we move more than the bounds in any direction?
if (e.X < (beforeMoveX - moveBounds) ||
e.X > (beforeMoveX + moveBounds) ||
e.Y < (beforeMoveY - moveBounds) ||
e.Y > (beforeMoveY + moveBounds))
{
// DRAGGED!
}
else
{
// NOT DRAGGED!
}
}
I have a program that uses OpenTk.GLControl. Now on my listener, every time the mouse hovers to the said control, say "glControl1", I want to get the mouse coordinates.
Is that possible? sample code below.
private void glControl1_MouseHover(object sender, EventArgs e)
{
// get the current mouse coordinates
// .........
}
OpenTK.GLControl inherits from System.Windows.Forms.Control. You can use the following code snippet to get the mouse position:
private void glControl1_MouseHover(object sender, EventArgs e)
{
Control control = sender as Control;
Point pt = control.PointToClient(Control.MousePosition);
}
Please refer to the MSDN WinForms documentation for more information.
The problem is that you're using the wrong event. Many UI actions in WinForms trigger multiple events per action; Hover is used for things like popping up tooltips. You don't get a coordinate in Hover because it's unnecessary.
What you want is the MouseMove event. This is used to track the mouse position:
private void glControl1_MouseMove(object sender, MouseEventArgs e)
{
foo = e.X;
bar = e.Y;
}
I dont know, what is OpenTk.GLControl, but:
I was handling swipe events on Windows Phone and did this:
private void PhoneApplicationPage_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//string to save coordinates of tap
TapCoordinatesXBegin = e.GetPosition(LayoutRoot).X.ToString();
TapCoordinatesYBegin = e.GetPosition(LayoutRoot).Y.ToString();
}
And i dont remember such event MouseHover - maybe MouseEnter?
I have the following problem: I have a panel which has a specific color, say red.
When the user presses his mouse, the color of this panel gets stored in a variable. Then the user moves, his mouse still pressed, over to another panel. When he releases the mouse there, this panel should get the background color of the first that had been stored in the variable. My code looks something like this:
public Color currentColor;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
private void AttempsColorChanger(object sender, MouseEventArgs e)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
}
I need to identify the sender first because there are many possible panels that can trigger this event. The first MouseDown method works totally fine, the color is stored nicely in the variable. The secon one however doesn't even get triggered when the user does what I described above. When the ser clicks on the second panel, it works (there is an MouseUp part in a click aswell I guess).
What's wrong here? Why is the event not triggered when the user holds the mouse key down before?
(This answer assumes you are using Windows Forms.)
It could be that you need to capture the mouse by setting this.Capture = true in the MouseDown of the source control. (See Control.Capture)
If you did that, the source window would get the MouseUp event, and it would be the source window that had to determine the destination window under the mouse coords. You can do that using Control.GetChildAtPoint() (see this answer on Stack Overflow).
Use Windows Forms Drag and Drop Support Instead! <- Click for more info
I'm going to suggest you bite the bullet and use the .Net Drag and Drop methods to do this. It requires some reading up, but it will be much better to use it.
You start a drag in response to a MouseDown event by calling Control.DoDragDrop().
Then you need to handle the Control.DragDrop event in the drop target control.
There's a few more things you might need to do to set it up; see the Control.DoDragDrop() documentation for an example.
(For WPF drag and drop support, see here.)
when your mouse enter the target control , mouse down triggerd ang get target BackColor! you need add an boolean flag to your code :
public Color currentColor;
bool flag=false;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
if(flag==false)
{
flag=true
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
}
//assume mouse up for panles
private void AttempsColorChanger(object sender, MouseEventArgs e)
{
if(flag==true)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
flag=flase;
}
}
and also you need change your flag in mouseMove( if )
As I mentioned in my comment Mouse Events are captured by the originating control, You would probably be better off using the DragDrop functionality built into Windows Forms. Something like this should work for you. I assigned common event handlers, so they can be assigned to all of your panels and just work.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void panel_MouseDown(object sender, MouseEventArgs e)
{
((Control)sender).DoDragDrop(((Control)sender).BackColor,DragDropEffects.All);
}
private void panel_DragDrop(object sender, DragEventArgs e)
{
((Control)sender).BackColor = (Color)e.Data.GetData(BackColor.GetType());
}
private void panel_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
}
I know it's an old question but I had the same issue and none of the above answers worked for me. In my case I had to handle the MouseMove event in the target control and check for the mouse to be released. I did set 'BringToFront' on my target panel just in case that helped at all.
public Color currentColor;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
private void panelTarget_MouseMove(object sender, MouseEventArgs e)
{
//the mouse button is released
if (SortMouseLocation == Point.Empty)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
}
}
I am trying to change my mouse cursor at certain point when I'm dragging my mouse around in a wpf listview. However, when I set my mouse, it quickly gets overridden by something else, and get changed back to the drag cursor.
I am not sure where the cursor change comes from, it is certainly not from my code, so it has to be system. If it is system, then I have to intercept the event for cursor change, and handle the event in order for the cursor to show what I want right?
So is there a WPF equivalent of this Control.CursorChanged event? Or perhaps there's some other way to approach this problem?
Edit:
here's part of my code
private void SetDragCursor()
{
if (_badDragLoc)
{
Mouse.OverrideCursor = Cursors.No;
}
else
{
Mouse.OverrideCursor = Cursors.Arrow;
}
}
private void listView_DragOver(object sender, DragEventArgs e)
{
if (at a bad drag location)
{
_badDragLoc = true;
SetDragCursor();
}
}
I also have a drag leave event handler, in which I also have the SetDragCursor() method as well. When I step by step go through each line of code in debugger, the mouse turned into the drag cursor from the no cursor right after it enters the drag leave handler. Which is why I think it has to be the system.
If it indeed is the system, then if I can capture the event firing, I can then handle those event myself and not let it bubble through.
Thank you!
Just does not work like that, the way to set the cursor during a DragOver event is the following:
void listView__DragOver(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent("Images"))
{
e.Effects = DragDropEffects.None;
e.Handled = true;
}
}
depending on the value of DragDropEffects enum you assign to e.Effects the mouse will change cursor.
do not call Mouse.OverrideCursor because is not the right way.
I have a winform on which i want to allow the user to move a control.
The control is (for now) a vertical line : label with border and a width of 1.
The context is not very important but i'll give it to you anyways. I have a background with some graphics and i'd like the user to be able to slide a guideline above the graphics. The graphics are made with the NPlots library. It looks something like this:
http://www.ibme.de/pictures/xtm-window-graphic-ramp-signals.png
If i can find out how the user can click and drag the label/line control around the screen, i can solve my guideline problem. Please help.
The code for this can get a bit complex, but essentially you will need to capture the MouseDown, MouseMove, and MouseUp events on your form. Something like this:
public void Form1_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button != MouseButton.Left)
return;
// Might want to pad these values a bit if the line is only 1px,
// might be hard for the user to hit directly
if(e.Y == myControl.Top)
{
if(e.X >= myControl.Left && e.X <= myControl.Left + myControl.Width)
{
_capturingMoves = true;
return;
}
}
_capturingMoves = false;
}
public void Form1_MouseMove(object sender, MouseEventArgs e)
{
if(!_capturingMoves)
return;
// Calculate the delta's and move the line here
}
public void Form1_MouseUp(object sender, MouseEventArgs e)
{
if(_capturingMoves)
{
_capturingMoves = false;
// Do any final placement
}
}
In WinForms, you can handle the MouseDown, MouseMove and MouseUp events of a control. On MouseDown, set some bit or reference telling your form what control the mouse was clicked on, and capture the X and Y of the mouse from MouseEventArgs. On MouseMove, if a control is set, adjust its X and Y by the difference between your last captured X and Y and the current coordinates. On MouseUp, release the control.
I would set up an "edit mode" for this; when the user enters this mode, the current event handlers of your form's controls should be detached, and the movement handlers attached. If you want to persist or revert these changes (like you're making a custom form designer your client can use to customize window layouts), you'll also need to be able to take some sort of snapshot of the before and after layouts of the controls.
I wrote a component to do exactly that: move a control on a form (or move a borderless form on the screen). You can even use it from the designer, without writing any code.
http://www.thomaslevesque.com/2009/05/06/windows-forms-automatically-drag-and-drop-controls-dragmove/
Here's an extension method that you can use for any control. It uses Rx and is based on the A Brief Introduction to the Reactive Extensions for .NET, Rx post and sample by Wes Dyer.
public static class FormExtensions
{
public static void EnableDragging(this Control c)
{
// Long way, but strongly typed.
var downs =
from down in Observable.FromEvent<MouseEventHandler, MouseEventArgs>(
eh => new MouseEventHandler(eh),
eh => c.MouseDown += eh,
eh => c.MouseDown -= eh)
select new { down.EventArgs.X, down.EventArgs.Y };
// Short way.
var moves = from move in Observable.FromEvent<MouseEventArgs>(c, "MouseMove")
select new { move.EventArgs.X, move.EventArgs.Y };
var ups = Observable.FromEvent<MouseEventArgs>(c, "MouseUp");
var drags = from down in downs
from move in moves.TakeUntil(ups)
select new Point { X = move.X - down.X, Y = move.Y - down.Y };
drags.Subscribe(drag => c.SetBounds(c.Location.X + drag.X, c.Location.Y + drag.Y, 0, 0, BoundsSpecified.Location));
}
}
Usage:
Button button1 = new Button();
button1.EnableDragging();
Well in all honesty there is a simpler way where by you initialize a global boolean variable called whatever you like, in this case, isMouseClicked. On your control you wish to allow dragging you go to its mouse down event,
Make sure these event are your control events not your forms event.
if (e.button == MouseButtons.left)
//this is where you set the boolean to true
Then go to its mouse move event
if (isMouseClicked == true)
//You then set your location of your control. See below:
Button1.Location = new Point(MousePosition.X, MousePosition.Y);
On your mouse up make sure to set your isMouseClicked to false;