I have a panel which holds many pictureboxes. Each picturebox has registered "contextRightMenu" as their context menu.
What i want when the context menu pops up is to get the current mouseposition.
I have tried getting the mouseposition by using mouseDown and click, but these events happens after one of the items of the context menu is clicked, and that is too late.
the popup event of the context menu does not deliver mouse event args, so i don't know how to get the mouseposition.
If i can get mouse event args it is easy.
Then i just can:
this.contextRightClick.Popup += new System.EventHandler(this.contextRightClick_Popup);
// If EventArgs include mouseposition within the sender
private void contextRightClick_Popup)(object sender, EventArgs e)
{
int iLocationX = sender.Location.X;
int iLocationY = sender.Location.Y;
Point pPosition = new Point(iLocationX + e.X, iLocationY + e.Y); // Location + position within the sender = current mouseposition
}
Can anyone help me either get some mouse event args, or suggest a event that will run before the contextmenu pop ups?
Thanks in advance
Do you want the cursor location relative to the PictureBox that was right clicked or relative to the parent Panel, or the parent Window or possibly just the screen position?
The following might help as a starting point. Here I get the current mouse cooridnates on the entire screen then using the SourceControl from the contextRightMenu, which is a reference to the instance of the control that was right clicked on, we convert the screen coordinates to a point relative to the source control.
void contextRightMenu_Popup(object sender, EventArgs e)
{
ContextMenu menu = sender as ContextMenu;
if (menu != null)
{
// Get cursor position in screen coordinates
Point screenPoint = Cursor.Position;
// Convert screen coordinates to a point relative to the control
// that was right clicked, in your case this would be the relavant
// picture box.
Point pictureBoxPoint = menu.SourceControl.PointToClient(screenPoint);
}
}
Handle the MouseClick of your PictureBox. Something like this (in vb.net):
Sub OnMouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) handles YourPictureBox.mouseclick
If e.Button = Windows.Forms.MouseButtons.Right then
'if you need the screen posistion
PointToScreen(New System.Drawing.Point(e.X, e.Y))
'if you need just the location
e.Location
end if
end sub
You can try the MouseClick event of picturebox and get the location if it is a right click.
you may wantto take a look to ContextMenuStrip Class and Control.ContextMenuStripChanged Event, some exemple here
Related
I want to get the form's coordinates X/Y even if the mouse is inside a control. To be more specific, if I move my mouse inside the form and the point of my mouse's location is (400,400), if I move inside a control I want the point's coordinates to change as if I was still moving my mouse inside the form, instead of changing to something like (15,30). I have tried using PointToClient or PointToScreen but nothing worked.
Edit:
For example, I have this method :
private void PlayScreen_MouseMove_1(object sender, MouseEventArgs e)
{
label1.Text = e.X.ToString() + "," + e.Y.ToString();
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
}
In button1_MouseMove I want to update label1 with the same coordinates before my mouse moved in button1.
I am creating a Word Add-In and in order to allow dragging something from a custom task pane to the document, I have followed the following guide:
http://msdn.microsoft.com/en-us/library/office/hh780901(v=office.14).aspx
There are some real drawbacks using this approach.
First, the transparent Windows Form (or WPF in my case) that catches the drop event is the size of the Window, not the document, and RangeFromPoint always returns a value, even if we aren't over the document (for instance, if we are over the Ribbon). So once you drag something and this form is created, no matter where you drop, it will be placed in the document. There is no graceful way to cancel once you've started.
My question is:
Has anyone done any work with Drag and Drop in a Word Add In, and found a better way to handle it than the supplied example by Microsoft?
It would be nice to either use the current solution, but know when the user is not dragging over the document or have that transparent window only show over the document area.
Hope you already had your answer.
I got a solution for my own.
So, my requirement:
I have a custom pane, which contains a listbox, each item is a normal string. When I drag an item from the listbox into the document, at a specific location, I want to insert a merge field at that location. The name of the merge field is the text of the item.
It was simple at first, then I got a problem just like you describe in your question.
About the code
So, there is a listbox, you need to handle mouseDown and mouseMove, don't worry about mouseUp.
In mouseDown handler, I record the boundary, if the mouse moves out of that boundary, the drag will start.
Then, in listBox_MouseMoveHandler, I check position of the mouse to start the dragdrop. And I have to use DragDropEffects.Copy for the DoDragDrop method.
DoDragDrop((sender as ListControl).SelectedValue, DragDropEffects.Copy);
With that option, SelectedValue will be inserted at the drop position, and after it is inserted, it will also be selected.
Then, I just check if selection is not empty, and replace the selected text with the merge field. Of course, I collapsed the selection before DoDragDrop. And that is the whole trick.
private int _selectedItemIndex;
private Rectangle dragBoxFromMouseDown;
private void CustomizationForListBox(ListBox listBox)
{
listBox.ItemHeight = 25;
listBox.DrawMode = DrawMode.OwnerDrawFixed;
listBox.DrawItem += ListBox_DrawItem;
listBox.MouseDoubleClick += listBox_MouseDoubleClick;
listBox.MouseMove += listBox_MouseMoveHandler;
listBox.MouseUp += listBox_MouseUp;
listBox.MouseDown += (sender, e) =>
{
// Handle drag/drop
if (e.Button == MouseButtons.Left)
{
_selectedItemIndex = listBox.IndexFromPoint(e.Location);
// Remember the point where the mouse down occurred. The DragSize indicates
// the size that the mouse can move before a drag event should be started.
Size dragSize = SystemInformation.DragSize;
// Create a rectangle using the DragSize, with the mouse position being
// at the center of the rectangle.
dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
e.Y - (dragSize.Height / 2)), dragSize);
}
};
}
private void listBox_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// Reset the drag rectangle when the mouse button is raised.
dragBoxFromMouseDown = Rectangle.Empty;
}
}
private void listBox_MouseMoveHandler(object sender, MouseEventArgs e)
{
// Handle drag and drop
// To check if the Mouse left button is clicked
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
// If the mouse moves outside the rectangle, start the drag.
if (dragBoxFromMouseDown != Rectangle.Empty &&
!dragBoxFromMouseDown.Contains(e.X, e.Y))
{
// Collapse current selection, now we know nothing is selected
Globals.ThisAddIn.Application.Selection.Collapse(WdCollapseDirection.wdCollapseEnd);
//Start Drag Drop
DoDragDrop((sender as ListControl).SelectedValue, DragDropEffects.Copy);
if (_selectedItemIndex != -1)
{
// If the drag/drop was successful, there dropped text must be selected
if (!String.IsNullOrWhiteSpace(Globals.ThisAddIn.Application.Selection.Text))
{
// Replace the selected text with a merge field MergeFieldHelper.InsertSingleMergeField(mergeFieldInfos[_selectedItemIndex].Name);
}
}
}
}
}
I have some context menu items that are not clickable. They just report the status of something. I don't like how the cursor still appears like they're clickable though.
Anyway to change this?
There isn't a Cursor Field like one would expect.
Handle the MouseMove event of the whole ToolStrip and check if the current mouse location is between the toolStripItem.Bounds. if so, change ToolStrip.Cursor
Amiram sent me in the right direction. You can't set the Cursor on the "ToolStripMenuItem" you have to set it on the parent ContextMenuStrip.
As for the mouse events, that has to go on the ToolStripMenuItems. As the MouseMove event is not fired when the Mouse is over ToolStripMenuItems.
// Init Code
contextMenuStrip1.Cursor = Cursors.Hand;
recentMessagesToolStripMenuItem.MouseLeave += new EventHandler(SetCursorToHandOn_MouseLeave);
recentMessagesToolStripMenuItem.MouseEnter += new EventHandler(SetCursorToArrowOn_MouseEnter);
private void SetCursorToArrowOn_MouseEnter(object sender, EventArgs e)
{
contextMenuStrip1.Cursor = Cursors.Arrow;
}
private void SetCursorToHandOn_MouseLeave(object sender, EventArgs e)
{
contextMenuStrip1.Cursor = Cursors.Hand;
}
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;
using this event the label just disappears, how shod i do this?
private void label4_MouseMove(object sender, MouseEventArgs e)
{
label4.Location = new Point(Cursor.Position.X, Cursor.Position.Y);
}
handle these three event ...
Control actcontrol;
Point preloc;
void label1_Mousedown(object sender, MouseEventArgs e)
{
actcontrol = sender as Control;
preloc = e.Location;
Cursor = Cursors.Default;
}
void label1_MouseMove(object sender, MouseEventArgs e)
{
if (actcontrol == null || actcontrol != sender)
return;
var location = actcontrol.Location;
location.Offset(e.Location.X - preloc.X, e.Location.Y - preloc.Y);
actcontrol.Location = location;
}
void label1_MouseUp(object sender, MouseEventArgs e)
{
actcontrol = null;
Cursor = Cursors.Default;
}
The location of label4 is relative to the container (Form or parent control), Cursor position may be relative to the screen.
You need to adjust the location. For example, if the container is the Form you can find its location in the screen and calculate by it the location of the cursor relative to screen.
This is only one possibility for the cause, but this one is happens a lot :)
Use the form's PointToClient() function to translate the mouse X/Y coordinates into points that are relative to your form, that should do it.
Edit: Use the mouse event args object properties instead:
Label1.Location = New Point(e.X, e.Y)
PS pardon the VB, no C# on this PC
The location of an element is relative to its parent. In this case though you are using the absolute mouse position as its location.
You'll need to translate the mouse position into the coordinate system of the parent element.
Use the PointToClient method on the label's parent element.