WinForm not dragging smoothly when moving by client area - c#

Whenever I move a Windows Form by some component (i.e. a Label) in the client area, I end up with a strange mouse offset in which the form does not stay visually underneath the cursor. It will still move according to my mouse location on the screen, but it dramatically shifts southeast of the cursor's position.
I've had to specify a negative offset of my own to counteract this offset; my code is as follows:
private void component_MouseDown(object sender, MouseEventArgs e)
{
if (sender is Label)
{
if (e.Button == MouseButtons.Left)
{
mouseLoc = new Point(-(e.X + OFFSET_X), -(e.Y + OFFSET_Y));
isMouseDown = true;
}
}
}
private void component_MouseMove(object sender, MouseEventArgs e)
{
if (isTitleLabelMouseDown)
{
Point p = Control.MousePosition;
p.Offset(mouseLoc);
Location = p;
}
}
private void component_MouseUp(object sender, MouseEventArgs e)
{
isMouseDown = false;
}
This offset does fix the problem, but what throws me for a loop is why the form's location offsets when I move it by its client area in the first place?
Thanks!

You seem to be translating client coordinates to screen coordinates. There is a better way...
https://msdn.microsoft.com/en-us/library/system.windows.forms.control.pointtoscreen%28v=vs.110%29.aspx
Edit: And of course there's a better way to do this whole thing. Basically, you want to intercept the click higher up the chain and tell Windows that the click is actually in the window title, which will cause Windows to do the dragging for you...
Winforms - WM_NCHITEST message for click on control

Related

Is it possible to implement a function that in C# Winforms that reorganize the elements as Android

I have this menu (Android style), which is in a FlowLayoutPanel that organizes the elements (Bunifu Tile Buttons):
Well, I thought about implementing a drag function where you could reposition the elements in execution time by dragging them with the mouse as it is done in Android.
To do this, I used a FlowLayoutPanel to organize the elements and this code::
...
Interval = 100, Enabled = true;
private void Timer_0_Tick(object sender, EventArgs e)
{
var cursor = Cursor.Position;
if(bunifuTileButton1.DisplayRectangle.Contains(cursor))
{
if(Hector.Framework.Utils.Peripherals.Mouse.MouseButtonIsDown(Hector.MouseButton.Left))
{
bunifuTileButton1.Location = cursor;
}
}
}
But when I drag the elements, they simply return to their original position by releasing the mouse button.
So, my question is:
Is it possible to implement a function that in C # Winforms that reorganize the elements as Android does using a FlowLayoutPanel that automatically organizes the elements in execution time?
Firstly , you need to implement the functionality which will help you drag-and-drop your controls.But before that, you need to store the control's current position in some class-level variables.Consider the following code snippet :
int xloc;
int yloc;
///other codes in-between
private void btn1_Click()
{
xloc = this.btn1.Location.X;
yloc = this.btn1.Location.Y;
}
Now the drag-and-drop feature :
private Point setNewLocation;
private void btn1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
setNewLocation= e.Location;
}
}
private void btn1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
btn1.Left = e.X + btn1.Left - setNewLocation.X;
btn1.Top = e.Y + btn1.Top - setNewLocation.Y;
}
}
This will help you move the control...But what happens when you place a control over another one ? I mean you definitely don't want one control to overlap the other.Rather you may want to,when one control is placed over the other, the other control will change it's position to the previous position of the control that is overlapping it.So, on the MouseUP event of the currently dragged control , use this :
private void btn1_MouseUP()
{
foreach (Control other in FlowlayoutPanel1.Controls)
{
///change control type as required
if (!other.Equals(btn1) && other is Button && btn1.Bounds.IntersectsWith(other.Bounds))
{
other.Location = new Point(xloc, yloc)
}
}
I haven't debugged the code so if you encounter any bug, make sure to leave a comment :)

Detect whether multiple ListView items were selected by dragging

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!
}
}

Unable to set the panel location to the current mouse position inside splitContainer?

I have panel1 in my form, i set the visible property to panel1.Visible=false; I want to show this panel wherever i click on the screen.
I need to grab the current mouse location and then display the panel1 where the top-left corner must be in the same point as the mouse cursor !
Sorry for being so beginner but i really stuck on how to do it.
Code that i tried :
private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
panel1.Location = e.Location;
panel1.Show();
}
It might this will be your guide to your task, just use the .PointToScreen and .GetCellDisplayRectangle Method
private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex == -1) return;
var cellRectangle = dataGridView1.PointToScreen(
dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false).Location);
panel1.Location = new Point(cellRectangle.X + 50, cellRectangle.Y - 175);
panel1.Show();
}
As far I can recognize your problem you should use PointToScreen function - more on this here

Getting Form mouse coordinated on PictureBox on mouse click override - C#

I'm drawing a MyPictureBox which inherits from PictureBox, and i override it's OnMouseClick
I set the arguments to be :(MouseEventArgs e) so i get the mouse coordinated when clicked,
The problem is the coordinates are the MyPictureBox relative coordinates while i need the coordinated from the Form.
How can it be done ?
Thanks
First map the passed mouse coordinate to the screen. Then map it back to the client coordinates of the form. So the typical code would look like this, spelled out for clarity:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
var pbox = (PictureBox)sender;
var form = this;
var screenPos = pbox.PointToScreen(e.Location);
var formPos = form.PointToClient(screenPos);
// etc..
}
Or the short version:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
var formPos = this.PointToClient(pictureBox1.PointToScreen(e.Location));
// etc..
}
The easiest way would be using
this.PointToClient(Cursor.Position);
this will get the position of your mouse cursor relative to your form.

how to move a label on a winform at Runtime

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.

Categories

Resources