Library tutorials & articles

Drag and Drop in Windows Forms - A Primer

Dragging a Control around

I wondered about this one purely because of the design side of VB. i.e. dropping controls onto a form and sizing them or moving them when you are creating a form in VS.Net for example. This is pretty nifty but try as I might I could not find an example or any help at all on how to do this until I visited www.planetsourcecode.com. I found some code that did something similar to what I wanted but more importantly it answered the only problem I had with my own implementation of the idea. To explain I had decided the only way to do this was to go back to the basic idea I mentioned at the beginning of this article, that is the idea of using a boolean to indicate when the user is dragging and applying this to the mousedown, mousemove and mouseup events. This is because the control has to move with the mouse not show an effect as in normal D&D. I had gotten to the point where I could move the control around a form but it was not smooth movement. I was having problems calculating the difference in mouseposition every time the mousemove event fired. The solution was the Offset method of a Point. So here's the code. I'm using a button as an example. I'll endeavour to explain it in due course:-

Private Sub btnMove_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnMove.MouseDown
    If e.Button = MouseButtons.Left Then
        Dragging = True
        mousex = -e.X
        mousey = -e.Y
        Dim clipleft As Integer = Me.PointToClient(MousePosition).X - btnMove.Location.X
        Dim cliptop As Integer = Me.PointToClient(MousePosition).Y - btnMove.Location.Y
        Dim clipwidth As Integer = Me.ClientSize.Width - (btnMove.Width - clipleft)
        Dim clipheight As Integer = Me.ClientSize.Height - (btnMove.Height - cliptop)
        Cursor.Clip = Me.RectangleToScreen(New Rectangle(clipleft, cliptop, clipwidth, clipheight))
        btnMove.Invalidate()
    End If
End Sub

Private Sub btnMove_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnMove.MouseMove
    If Dragging Then
         'move control to new position
        Dim MPosition As New Point()
        MPosition = Me.PointToClient(MousePosition)
        MPosition.Offset(mousex, mousey)
        'ensure control cannot leave container
        btnMove.Location = MPosition
    End If
End Sub

Private Sub btnMove_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnMove.MouseUp
     If Dragging Then
        'end the dragging
        Dragging = False
        Cursor.Clip = Nothing
        btnMove.Invalidate()
    End If
End Sub

AddThis

Comments

  1. 05 Jul 2008 at 02:28

    there is problem to select text (text-text example) after you dragged from source textbox it disallows to select some part

  2. 09 Aug 2007 at 21:03

    How to use Drag and Drop to drag a highlighted (or selected) string from a text file and drop it. Thanks.

  3. 27 Jul 2007 at 11:07

    I wanted to write a simple form where the user could add a label to the form, rename it and move the label to where they needed it. Your code was right on the money and I can't thank you enough as it allowed to add a lot more functionality to the process that I never thought of before and it is working a treat.

     

  4. 29 Nov 2006 at 22:15

    If you find a control in VB that has a 'hwnd' property, you can drag it without too much hassle.

    Add the following to the top of the form code:

    Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
    Public Const HTCAPTION = 2
    Public Const WM_NCLBUTTONDOWN = &HA1



    You then, on the mousemove event, check to see if the mouse is pressed. If so, you call:
    SendMessage( [the hwnd of the control], WM_NCLBUTTONDOWN, HTCAPTION, 0& )

    The control should now be movable.

  5. 16 Aug 2006 at 14:52

    I am a self taught newbie (the worse sort) so please go gently.

     

    My son has produce code to display and reorder jpeg thumbnails in a ListView and it works well, however, I would prefer Drop and Drag. I have sort of got it to work based on the example and a suggestion to remove 2 lines of code (see below) but it has 2 main problems. Note I am dragging within the same list (reordering) rather than dragging it somewhere else.

     

    1/ Whenever I drop the thumbnail it always ends up at the bottom of the list.

    2/ There is no indication where its about to be dropped.

     

    Finally is there a way to display / bring into view an thumbnail image that has scrolled outside the window?

     

     

        Private Sub ListViewDragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListView1.DragDrop, ListView1.DragDrop

     

     

            Dim lvItem As ListViewItem

            Dim destItem As ListViewItem

            Dim destLv As ListView = CType(sender, ListView)

            Dim clX As Integer = destLv.PointToClient(New Point(e.X, e.Y)).X

            Dim clY As Integer = destLv.PointToClient(New Point(e.X, e.Y)).Y

            If e.Data.GetDataPresent("System.Windows.Forms.ListViewItem", False) Then

                'dragging a listview item

                lvItem = CType(e.Data.GetData("System.Windows.Forms.ListViewItem"), ListViewItem)

                '#' - destItem = CType(sender, ListView).GetItemAt(clX, clY)

                '#' -            destLv.Items.Insert(destItem.Index, lvItem.Clone)

                lvItem.Remove()

                destLv.Items.Add(lvItem)

            End If

        End Sub

     

    Thanks in advance, Andrew

  6. 05 Jul 2006 at 10:28

    This code works great but lets you drag the button, label etc off the form.

     I've got 3 labels on a 143 by 126 picture box on a form.  I need some code to stop the labels being dragged off of the picture box onto the rest of the form!  At the minute, you can move the labels anywhere on the form and save the position.  I only want to be able to move them in the picture box area.

    Please help!

    Thanks,

    Jimbo.









  7. 11 Jun 2006 at 02:41

    Visual Basic 2005 Professional Edition:

    I need to drag and drop an image from one PictureBox to another PictureBox where:

    1) the image is visible while being dragged
    2) the image can be dropped at any location within the target PictureBox
    3) the image can be rotated within the target PictureBox

     

  8. 19 Jan 2006 at 21:56

    I wanted to be able to add the selected line to the end of the listview.  As written I was not able to.  I modified the initial load routine to add a blank line at the end of the list box, which allowed the addition before the blank line.  Is there a better way to add to the end of a list view?

  9. 29 Nov 2005 at 23:02

    If all you are trying to do is drag a control around a form, here is a simple but effective way to do it.  It is similar to what the author posted, but to me it is easier to understand.


    Code:
     
    'Form level variables
     Dim StartX, StartY As Integer
     Dim Dragging As Boolean


     Private Sub Label1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseDown
       Dragging = True
       StartX = e.X
       StartY = e.Y
     End Sub



     Private Sub Label1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseMove
       If Dragging = True Then
         Label1.Left = (Label1.Left + e.X) - StartX
         Label1.Top = (Label1.Top + e.Y) - StartY
        'Could use a Point here as well if you wish
       End If
     End Sub



     Private Sub Label1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseUp
       Dragging = False
     End Sub




  10. 25 Nov 2005 at 18:32

    I have problem when style of  ListView1.View = View.LargeIcon
    when I drag the icon between others, this icon put in the last position and not in the position where i put this
    help me please, write me to a19992689@pucp.edu.pe

  11. 23 Sep 2005 at 08:06

    hello sir/mam


    i m using vs.net 2003. i m developing a window application where i n i want to drag an image and drop to picturebox control .i m using following code but is not giving me the output.
    please help me...




       Private Sub Pic_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
           Me.PictureBox1.AllowDrop = True
       End Sub


       Private Sub PictureBox1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles PictureBox1.DragEnter
           If (e.Data.GetDataPresent(DataFormats.Bitmap)) Then


               If (e.KeyState And ctrlMask) = ctrlMask Then


                   e.Effect = DragDropEffects.Copy


               Else


                   e.Effect = DragDropEffects.Move


               End If
           Else
               
               e.Effect = DragDropEffects.None


           End If


       End Sub


       Private Sub PictureBox1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles PictureBox1.DragDrop
           PictureBox1.Image = e.Data.GetData(DataFormats.Bitmap)
       End Sub

  12. 25 Aug 2005 at 20:23

    I had problems when i converted this code to C# resetting the clip rectangle in the MouseUp event handler i ended up doing it this way
    Cursor.clip=Screen.Bounds(this);



    This seemed to work but is not ideal anyone have any better suggestions ?



    neil


  13. 06 Dec 2004 at 09:00

    Brian --  Thanks for you examples and thorough explanation.  I'm new to .NET and found your article very useful just now.  I tried your code, and you're right, the clipping was not quite perfect.  I got a little better result after altering the calculations for clipwidth and clipheight.


    Instead of
     Dim clipwidth As Integer = Me.ClientSize.Width - (btnMove.Width - clipleft)
    I tried
     Dim clipwidth As Integer = Me.ClientSize.Width - btnMove.Width - 1
    and then, more generally, in a ProcessMouseDownForAllControls Event
     Dim clipwidth As Integer = Me.ClientSize.Width - CType(sender, Control).Size.Width - 1  


    The same change was done to the clipheight assignment.


    Now to get it all to work with and on container controls ...


    -- Steve

  14. 03 Sep 2004 at 07:01

    Ok I got another response from another forum and the answer is so simple (thank goodness)


    The sender in the drop subroutine is the text box that is being referenced.


    This sure did save me a whole lot of wasted effort.



    Thanks for the responses all the same!


    Cheers


  15. 03 Sep 2004 at 06:36

    Yes musician you are correct...je m'excuse.


    I did finally get the thing to work yesterday however but I ended up using other code. Now a new problem has risen where I have multiple textboxes that are to recieve the different information from the list view.


    The issue is that I am having some trouble with knowing what the testbox name is in relation to the mouse over event. I think I have to compare the x and y of the mouse and the control but I'm not quite sure how this works.


    Any suggestions?


  16. 02 Sep 2004 at 14:02

    If you are dragging to an empty listview then try this:-


    If destItem Is Nothing Then
         destLv.Items.Insert(destLv.Items.Count, lvItem.Clone)
    Else
         destLv.Items.Insert(destItem.Index, lvItem.Clone)
    End If


    Here we can check if we actually found an item in the second listview and if not put the item into the first available index.


    If you are having problems getting at the item being dragged you may not be successfully putting it into the clipboard when dragging. Specifically this event's code:-


    Private Sub ListViewItemDrag(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemDragEventArgs) Handles ListView1.ItemDrag, ListView2.ItemDrag
       DoDragDrop(e.Item, DragDropEffects.Move)
    End Sub


    Be sure to download the example project with the article that contains the complete code. And please folks. Any article is a starting point. To simply write it off as being of no help is a bit harsh.

  17. 02 Sep 2004 at 13:38

    Quote:
    [1]Posted by Saskman on 2 Sep 2004 06:44 AM[/1]
    Well I built the form as directed and even copied the code from the page.


    The dragging from a listview to a listview does not work. So this item though interesting
    is not useful at all.




    I was having some trouble using this code to drag items from one listview to another myself.
    The problem wasn't so much with dragging items from a listview, to a listview with items in it, provided I dropped the new item on one of the existing ones.  However, if i just dropped it into an empty listview, or dropped it at some random point within the listview, the program would crash.


    With a treeview, the exact point at which you are dropping the item is quite important, however, in a listview, we are often only moving items between listviews to populate the initially empty target.


    In my case, I wanted to have a listview with a list of NFL Players, and a second, initially empty one, that I could drag and drop players into, as they were drafted in my fantasy league, leaving me a list of available players.


    After spending some time on it, and taking a break (aka going to bed, then work) I took another look and the fix is rather obvious.


    In Private Sub ListView DragDrop, I removed the following lines of code:


    destItem = CType(sender, ListView).GetItemAt(clX, clY)
    destLv.Items.Insert(destItem.Index, lvItem.Clone)



    There are also now some variables that aren't needed and could be removed.
    Then, after the line:


    lvItem.Remove()


    add a line:


    destLv.Items.Add(lvItem)


    This will drop the item from ListView1 into ListView2, add the bottom of the list (or vice versa)


    Oddly enough, my first several attempt, were almost correct, I was just having a giant brain fart, and tried to add the item to the destination, before removing it from the originating ListView.

  18. 02 Sep 2004 at 06:44

    Well I built the form as directed and even copied the code from the page.


    The dragging from a listview to a listview does not work. So this item though interesting
    is not useful at all.


    I am trying to take an item from a listview and put the text of that item into a textbox. The
    article says how to do this by simply getting the listviewitem.text but this does not work either.


    Perhaps i am missing a step somewhere.


    Clearer info for tis newbie would be geatl appreciated


    G

  19. 01 Sep 2004 at 03:31

    Hi,


    I found your article and source example fantastic - explained exactly what I needed to do, in the right tone too!


    I have a question though. (Naturally)


    I am designing a form that has a varying number of controls created at run time.  Information about these controls will be stored in a database and the form will be generated around this information.


    The question is "Is it possible to assign mouse events to controls created at runtime?"


    For example, I create a label called "Label3" and position it where I want initially.  The user then wants to move that label, which is one of say 500 on the form.


    I have looked for a way to capture the name of the control using onclick and mouse down, and then assigning the name as a variable within the sub - failed on this, but not sure if its the right way.


    Any pointers would be appreciated.


    Regards,


    Dave

Leave a comment

Sign in or Join us (it's free).

Related discussion

Related jobs

Events coming up

  • Dec 9

    VB.NET - The Full Nelson

    Cambridge, United Kingdom

    He may only have scored 600 points on Manic Miner, but when it comes to VB.NET, Microsoft's, Eric Nelson knows his stuff. We'll also be havintg a Christmas pudding pizza and a Nugget.