So i searched a little around on google to find some code to drag buttons with the mouse. I found a lot, even though none of these actually worked for me.
So i'm asking you! :-)
The code i'm trying to get working in my form:
bool isDragged = false;
Point ptOffset;
private void button1_MouseDown( object sender, MouseEventArgs e )
{
if ( e.Button == MouseButtons.Left )
{
isDragged = true;
Point ptStartPosition = button1.PointToScreen(new Point(e.X, e.Y));
ptOffset = new Point();
ptOffset.X = button1.Location.X - ptStartPosition.X;
ptOffset.Y = button1.Location.Y - ptStartPosition.Y;
}
else
{
isDragged = false;
}
}
private void button1_MouseMove( object sender, MouseEventArgs e )
{
if ( isDragged )
{
Point newPoint = button1.PointToScreen(new Point(e.X, e.Y));
newPoint.Offset(ptOffset);
button1.Location = newPoint;
}
}
private void button1_MouseUp( object sender, MouseEventArgs e )
{
isDragged = false;
}
I of course changed the pictureBox1 to button1.
But i just can't get this to work.
Anyone who might know why?
Oh, and i want to use this at all my buttons, so what should i replace button1 with to make it work at all of the buttons?
-Btw, i use Visual studio Express.
Thank you in advance!
even though i'm really just copy pasting when it comes to windows
forms
The code you posted won't actually do anything by itself!
To work, the MouseDown() and MouseMove() events of the control have to be wired up to those methods:
Select the control on the form (pictureBox1).
In the Properties Pane (bottom right by default), click the
"Lightning Bolt" icon to get a list of the events for that control.
Find the MouseDown entry and change the dropdown to the right of
it to pictureBox1_MouseDown.
Find the MouseMove entry and change the dropdown to the right of
it to pictureBox1_MouseMove.
Now run it and drag the pictureBox1 around.
EDIT: Here is how to make the code work for multiple controls, as outlined in my comment below.
bool isDragged = false;
Point ptOffset;
private void button1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isDragged = true;
Button btn = (Button)sender;
ptOffset = new Point(btn.Location.X - Cursor.Position.X, btn.Location.Y - Cursor.Position.Y);
}
else
{
isDragged = false;
}
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (isDragged)
{
Point newPoint = Cursor.Position;
newPoint.Offset(ptOffset);
Button btn = (Button)sender;
btn.Location = newPoint;
}
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
isDragged = false;
}
Ok, the good news: hopefully we'll have a CSI desktop layout once you're done.
The not so good news: I think you're trying to do the wrong thing.
I'm assuming you're using WinForms, but the idea should be the same for WPF.
When you run your program, the layout is set (either dynamically, for example it changes when you resize the window, or statically, for example when you set it with absolute X,Y position).
What you want to do is kind of: I want to get the benefits of them creating all the boiler plate code, but then, I want to dynamically change it at run time ...
I think you need to rethink your approach, and take this one step at a time (after all, it took Microsoft years to get the GUI to where it's at at the moment ... It'll take some time to get the cool futuristic GUI's out).
Take baby steps, but keep in mind the big picture:
Start with having a Canvas defined.
Then you can place a button on it.
Then fool around with moving that button on the canvas. (The code you have in your question should work for an object on a canvas).
From there, keep taking steps that will get you closer to your destination ...
Related
I have an old WinForms app written in C# with custom drag and drop capabilities. And this app has an issue when it is run on a touch screen device, such as the Surface Pro 3.
Basically there is a treeview control that allows the items to be dragged to a different area of the app and have some calculations done. If I use the mouse or the stylus the custom drag image is drawn on the screen. If I drag an item using touch the image is not displayed but the code is executed properly, including the drawing of a custom cursor.
It seems that the custom drag image is not displayed because the mouse cursor is hidden by the O.S. during a touch drag operation. How do I get the drag image to display?
UPDATE
Here is some code to demonstrate what I am trying to fix. Create a new WinForms app, add a treeview to it and wire up the events. You'll notice that if you use a stylus or the mouse the drag operation will show an icon. If you touch-drag an item, nothing shows.
public Form1()
{
InitializeComponent();
TreeNode node = new TreeNode("welp");
treeView1.Nodes.Add(node);
treeView1.Nodes.Add(node);
treeView1.Nodes.Add(node);
treeView1.Nodes.Add(node);
treeView1.Nodes.Add(node);
treeView1.Nodes.Add(node);
treeView1.Nodes.Add(node);
treeView1.Nodes.Add(node);
treeView1.Nodes.Add(node);
treeView1.Nodes.Add(node);
}
private void treeView1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void treeView1_GiveFeedback(object sender, GiveFeedbackEventArgs e)
{
e.UseDefaultCursors = true;
}
private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
{
((TreeView)sender).DoDragDrop(e.Item, DragDropEffects.Move);
}
Ok, So I got this working exactly the way that I want it to. Wasn't easy and it's probably not the preferred way to go about it but it does what I want and I was on a time crunch to get this finished.
First, I found this article Shell Style Drag and Drop. It worked, for the most part, but it was written about 7 years ago and doesn't take into consideration how the O.S. has changed. Too much to go into the details about that and why it didn't work for me.
The main issue I was trying to fix was that my original drag and drop code used the old school way of drawing a new cursor in the GiveFeedback event of a drag and drop operation. Worked great except on touch devices because the Windows O.S. hid the cursor during a touch-drag operation so my custom drawn cursor would never be displayed. A few (used lightly) Google searches revealed that Windows won't allow two pointer devices to be active at the same time, even with calling the native ShowCursor method. Fair enough.
The biggest issue with trying to draw on the screen while in a drag and drop operation is that most of the messages sent to a window, such as WM_MOUSEMOVE and WM_PAINT are suspended. The only way I could draw anything was in the GiveFeedback event.
So, I found this article that covers drawing using a transparent overlay. Again, it didn't do exactly what I wanted but with a little tweaking it worked perfectly. I was able to grab the HDC of the overlay and the HDC of my form and do a nice BitBlt operation to display my custom bitmap on the screen and erase the old drawing by grabbing the underlying image of the form. I also changed the method that draws a custom cursor to a method that draws a custom bitmap.
Here is what I changed in regards to the article above
this.BackColor = Color.White;
this.Opacity = 1; // Tweak as desired
this.TransparencyKey = Color.White;
And what I added to allow the message pump to go through
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= Win32.WS_EX_TRANSPARENT;
return createParams;
}
}
The details of the rest are not overly complex but require a nice blending of the drag and drop operations, the overlay, drawing and erasing and double buffering. And there are situations, like in my case, where I have a TreeView control updating while I am dragging and I have to expand the rectangle of the draw operation so the bitblt image covers the areas outside of my drawing.
If you are interested in this article and want to see what I did and how I accomplished it, let me know in the comments and I will post code.
try this code
hope is helped you
public Form1()
{
InitializeComponent();
TreeNode node;
for (int x = 0; x < 3; ++x)
{
node = treeView1.Nodes.Add(String.Format("Node{0}", x * 4));
for (int y = 1; y < 4; ++y)
{
node = node.Nodes.Add(String.Format("Node{0}", x * 4 + y));
}
}
treeView1.AllowDrop = true;
treeView1.Dock = DockStyle.Fill;
treeView1.ItemDrag += new ItemDragEventHandler(treeView1_ItemDrag);
treeView1.DragEnter += new DragEventHandler(treeView1_DragEnter);
treeView1.DragOver += new DragEventHandler(treeView1_DragOver);
treeView1.DragDrop += new DragEventHandler(treeView1_DragDrop);
}
private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
DoDragDrop(e.Item, DragDropEffects.Move);
}
else if (e.Button == MouseButtons.Right)
{
DoDragDrop(e.Item, DragDropEffects.Copy);
}
}
private void treeView1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = e.AllowedEffect;
}
private void treeView1_DragOver(object sender, DragEventArgs e)
{
Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y));
treeView1.SelectedNode = treeView1.GetNodeAt(targetPoint);
}
private void treeView1_DragDrop(object sender, DragEventArgs e)
{
Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y));
TreeNode targetNode = treeView1.GetNodeAt(targetPoint);
TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
if (!draggedNode.Equals(targetNode) && !ContainsNode(draggedNode, targetNode))
{
if (e.Effect == DragDropEffects.Move)
{
draggedNode.Remove();
targetNode.Nodes.Add(draggedNode);
}
else if (e.Effect == DragDropEffects.Copy)
{
targetNode.Nodes.Add((TreeNode)draggedNode.Clone());
}
targetNode.Expand();
}
}
private bool ContainsNode(TreeNode node1, TreeNode node2)
{
if (node2.Parent == null) return false;
if (node2.Parent.Equals(node1)) return true;
return ContainsNode(node1, node2.Parent);
}
I am trying to move some controls around on a WinForm with the mouse. I am using the code below. To see my issue start a new project in VS add the code below. Set the form BackGroundImage to any image then add any control. Set the control events for MouseUp, MouseDown, and MouseMove. Start debugging and click and move the control. The image in the form starts getting erased. I have tried several different suspend drawing classes and methods I have found on the net but nothing I have found lets me move the controls around without serious flickering or not being able to see the move. Any help would be appreciated.
P.S. If you set the same events to the up, move, and down events of the form, it moves fine with out any flickering.
private bool _mouseDown;
private Point _startPoint;
private void Event_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_mouseDown = true;
_startPoint = new Point(e.X, e.Y);
}
}
private void Event_MouseUp(object sender, MouseEventArgs e)
{
_mouseDown = false;
}
private void Event_MouseMove(object sender, MouseEventArgs e)
{
if (_mouseDown)
{
Control s = sender as Control;
s.Location = new Point(e.X + s.Left - _startPoint.X, e.Y + s.Top - _startPoint.Y);
}
}
I want the same thing as in this Question:
Click and hold on button while dragging mouse to make value bigger/smaller
The only answer there was the Slider but that was not what the Question asker meant. And nor what i meant.
I know something like this is possible in iOs, but i want to use it in a windows app, but i cant seem to figure out how to do it.
I tried doing it with pointerpressed, pointerrelease and pointermoved. And it worked in a way but i stops working when you get out of the range from the textblock so it does only work when you drag on the textblock itself, and i want to do it so that you can drag over the whole screen if necessary.
this is what i have so far:
private void TextBlock_PointerPressed(object sender, PointerRoutedEventArgs e)
{
ystart = e.GetCurrentPoint(this).Position.Y;
clicked = true;
}
private void TextBlock_PointerReleased(object sender, PointerRoutedEventArgs e)
{
clicked = false;
}
private void TextBlock_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if(clicked == true)
{
yend = e.GetCurrentPoint(this).Position.Y;
double difference;
int textgetal = Convert.ToInt32(Block.Text);
difference = ystart - yend;
textgetal = textgetal + (Convert.ToInt32(difference) / 10);
Block.Text = Convert.ToString(textgetal);
}
}
and like i said this works, but only inside the range of the textblock and not the whole screen like i want it.
A good morning to you all!
Yesterday I ran into a problem while trying to implement a custom DragDrop for my own controls in a WinForms application.
I have a form which can dynamically create instances of two of my own controls. These controls consist of some controls themselves, such as buttons, labels and listboxes/treeviews. The controls serve as a representation for a certain dataset. Now, we all know the class diagrams in VS. There you have these boxes representing classes. You can move the boxes around on the canvas by doing - what I would call - dragging them around, much like you would drag around files. To accomplish this with my own controls I have done the following:
public partial class MyControl: UserControl
{
private Control activeControl;
private void GeneralMouseDown(MouseEventArgs e)
{
activeControl = this;
previousLocation = e.Location;
Cursor = Cursors.Hand;
}
private void GeneralMouseMove(Control sender, MouseEventArgs e)
{
if (activeControl == null || activeControl != sender)
return;
var location = activeControl.Location;
location.Offset(e.Location.X - previousLocation.X, e.Location.Y - previousLocation.Y);
activeControl.Location = location;
}
private void GeneralMouseUp()
{
activeControl = null;
Cursor = Cursors.Default;
}
}
The controls on my control which I want to "grab" for dragging MyControl have their MouseDown-, MouseMove- and MouseUp-events pointing to these three methods. As a result I can move my control about on the form freely, just as I want to.
Here comes the tricky bit:
The datasets I have controls for can be in hierarchical dependencies, which means, one control represents detailling of a component of the other, which is why my controls have Listboxes or TreeViews. To establish such a hierarchical dependency I would very much like to DragDrop the lower-order-control on the listbox of my higher-order-control, causing data to be transfered.
I know how to set up my DragEnter and DragDrop methods for the listbox, as I have done so previously with files. Just for completeness:
private void lst_MyControl_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(MyControl)))
e.Effect = DragDropEffects.Move;
else e.Effect = DragDropEffects.None;
}
Here's the problem: As I am moving my control about (which gets repainted at every position, giving a very much wanted effect!), when I "drag" it over the target-listbox, the DragEnter-event does not get fired. I thought I could work around this problem by telling Windows "Hey, I'm, Dragging'n'Dropping here!", thus adding to my GeneralMouseDown-method:
this.DoDragDrop(this, DragDropEffects.Move);
This, on the one hand, gets the DragEnter-event to fire => Yeah! On the other hand is the moving-around-part only working after I release the mouse, causing the control to hang on the mousepointer forever => Anti-Yeah!
Here's the question: Is there a way, to have both actions at the same time? So that I can move my control around, seing it at every position as I do now and fire the DragEnter-event when I get to that area of the other control?
Moving your Control around interferes with the automatic DragDrop handling.
I'd recommend to staying with the normal DragDrop procedures, that is leaving all visuals to the system: It will display a cursor that indicates when a valid target is entered, then change to one that indicates the operation.
You need just 3 lines, no hassle and the user won't seen bulky controls moving around.
Here is a version where I drag a PictureBox onto a ListBox:
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
private void listBox1_DragDrop(object sender, DragEventArgs e)
{
listBox1.Items.Add( e.Data.GetData(DataFormats.Text));
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
pictureBox1.DoDragDrop(pictureBox1.ImageLocation, DragDropEffects.Copy);
}
Obviously you will set up and receive your data in your own ways..
Edit:
Now, if on the other hand you need to move controls around to rearrange them, maybe you should give up on Drag&Drop to handle the additional data transfers and code this portion on your own as well. You could use the MouseEnter event of a receiving control..
After a bit of fiddeling I did it. I switched the level on which the dragging is handled.
First I need just the MouseDown-event
public Point GrabPoint;
private void GeneralMouseDown(MouseEventArgs e)
{
GrabPoint = e.Location;
this.DoDragDrop(this, DragDropEffects.Move);
}
I set the point where I grab the control and initiate a DragDrop. On my form I handle all the dragging:
private void frmMain_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(MyControl1)) || e.Data.GetDataPresent(typeof(MyControl2)) || e.Data.GetDataPresent(typeof(MyControl3)))
e.Effect = DragDropEffects.Move;
else e.Effect = DragDropEffects.None;
}
private void frmMain_DragOver(object sender, DragEventArgs e)
{
Point DragTarget = new Point(e.X, e.Y);
Point GrabPoint = new Point(0, 0);
if (e.Data.GetDataPresent(typeof(MyControl1)))
GrabPoint = ((MyControl1)e.Data.GetData(typeof(MyControl1))).GrabPoint;
else if (e.Data.GetDataPresent(typeof(MyControl2)))
GrabPoint = ((MyControl2)e.Data.GetData(typeof(MyControl2))).GrabPoint;
else if (e.Data.GetDataPresent(typeof(MyControl3)))
GrabPoint = ((MyControl3)e.Data.GetData(typeof(MyControl3))).GrabPoint;
DragTarget.X -= GrabPoint.X;
DragTarget.Y -= GrabPoint.Y;
DragTarget = this.PointToClient(DragTarget);
if (e.Data.GetDataPresent(typeof(MyControl1)))
((MyControl1)e.Data.GetData(typeof(MyControl1))).Location = DragTarget;
else if (e.Data.GetDataPresent(typeof(MyControl2)))
((MyControl2)e.Data.GetData(typeof(MyControl2))).Location = DragTarget;
else if (e.Data.GetDataPresent(typeof(MyControl3)))
((MyControl3)e.Data.GetData(typeof(MyControl3))).Location = DragTarget;
}
At the moment I don't need the DragDrop-event, since nothing should happen when any control is dropped on the form. This way I always paint my control while it is being dragged => Yeah!
The next part is easy: Since I am really dragging the control, this bit of code does DragDrop-handling on my listbox Edit: ListView:
private void lst_SubControls_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(MyControl2)))
e.Effect = DragDropEffects.Move;
else e.Effect = DragDropEffects.None;
}
private void lst_SubControls_DragDrop(object sender, DragEventArgs e)
{
lst_SubControls.Items.Add(((MyControl2)e.Data.GetData(typeof(MyControl2))).SpecificDrive);
((MyControl2)e.Data.GetData(typeof(MyControl2))).DeleteThisControl();
}
This results in an entry added to the list and deletion of the dragged control. At this point there could be a check, wether the ctrl-key is pressed to copy the contents and not to delete the control.
My form doesn't have a title bar, so I am implementing the code to drag
the entire form around the screen. I am using the below code to do it, which works fine.
I have two panels in my form, PanelA and PanelB. During the startup I show
PanelA where the dragging works perfectly. Later when the user clicks
the button in PanelA, I need to make PanelA invisible and show PanelB
However, the dragging does not work when PanelB is shown. What's the
problem here?
private void SerialPortScanner_MouseUp(object sender, MouseEventArgs e)
{
this.drag = false;
}
private void SerialPortScanner_MouseDown(object sender, MouseEventArgs e)
{
this.drag = true;
this.start_point = new Point(e.X, e.Y);
}
private void SerialPortScanner_MouseMove(object sender, MouseEventArgs e)
{
if (this.drag)
{
Point p1 = new Point(e.X, e.Y);
Point p2 = this.PointToScreen(p1);
Point p3 = new Point(p2.X - this.start_point.X,
p2.Y - this.start_point.Y);
this.Location = p3;
}
}
Edit: I've realized that you're not asking about drag and drop, but rather about moving your form around the screen. (Thanks to #Veer.) I've edited your question to help clarify this. Drag and drop is a completely different thing, since it is dragging information from one control to another.
The same principle of my answer still applies though, since mouse events are also handled at the Control level - you might need to handle the mouse events from PanelB as well.