Drag'n'drop code - Similar to card game

Posted on 2005-04-29
Last Modified: 2008-02-01
Hi i'm trying to assemble a program and i've come across a need for the code similar to in the card game Solitaire for instance.. I need to be able to drag and drop an object (preferably with a picture) to a destination and be able to pull it off the object again.  I'm not quite so sure where to start, any ideas?
Question by:mortar
    LVL 85

    Accepted Solution

    There are several differents ways to go about "drag and drop" operations.

    (1) A traditional drag and drop does not actually move the object while you are dragging...but instead leaves it in place.  The cursor changes to show where a drop can or cannot occur.  Here is an example of this kind of drag and drop:
    It is possible to define custom cursors instead of using the standard move, copy, no drop, etc...

    (2) The drag and drop in most solitare games usually involves actually moving the source control as you drag it.  Then when it is dropped, you check its coordinates against those of the valid drop areas and see if it should be dropped or "snapped" to one those locations.  There are soooooooooo many ways to go about this...

    Below is an example of one way to do it.  In the app there are six pictureboxes...three across the top and three across the bottom.  Double click each of the three top boxes and select an image for it.  Then drag each of those boxes in turn onto one of the bottom three boxes.  They should snap down onto them.  If more than one box is a candidate, the one with the largest area covered by the source picturebox will be selected.  You can pull the pictureboxes off again by dragging them back into the open space at the top of the form.  If one of the bottom target pictureboxes already has a picture on it then it no longer becomes a valid drop location until it is emptied again:

    Public Class Form1
        Inherits System.Windows.Forms.Form

    #Region " Windows Form Designer generated code "

        Public Sub New()

            'This call is required by the Windows Form Designer.

            'Add any initialization after the InitializeComponent() call

        End Sub

        'Form overrides dispose to clean up the component list.
        Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
                If Not (components Is Nothing) Then
                End If
            End If
        End Sub

        'Required by the Windows Form Designer
        Private components As System.ComponentModel.IContainer

        'NOTE: The following procedure is required by the Windows Form Designer
        'It can be modified using the Windows Form Designer.  
        'Do not modify it using the code editor.
        Friend WithEvents PictureBox1 As System.Windows.Forms.PictureBox
        Friend WithEvents PictureBox2 As System.Windows.Forms.PictureBox
        Friend WithEvents PictureBox3 As System.Windows.Forms.PictureBox
        Friend WithEvents PictureBox4 As System.Windows.Forms.PictureBox
        Friend WithEvents PictureBox5 As System.Windows.Forms.PictureBox
        Friend WithEvents PictureBox6 As System.Windows.Forms.PictureBox
        Friend WithEvents OpenFileDialog1 As System.Windows.Forms.OpenFileDialog
        <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
            Me.PictureBox1 = New System.Windows.Forms.PictureBox
            Me.PictureBox2 = New System.Windows.Forms.PictureBox
            Me.PictureBox3 = New System.Windows.Forms.PictureBox
            Me.PictureBox4 = New System.Windows.Forms.PictureBox
            Me.PictureBox5 = New System.Windows.Forms.PictureBox
            Me.PictureBox6 = New System.Windows.Forms.PictureBox
            Me.OpenFileDialog1 = New System.Windows.Forms.OpenFileDialog
            Me.PictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
            Me.PictureBox1.Location = New System.Drawing.Point(16, 8)
            Me.PictureBox1.Name = "PictureBox1"
            Me.PictureBox1.Size = New System.Drawing.Size(120, 120)
            Me.PictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage
            Me.PictureBox1.TabIndex = 0
            Me.PictureBox1.TabStop = False
            Me.PictureBox2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
            Me.PictureBox2.Location = New System.Drawing.Point(192, 8)
            Me.PictureBox2.Name = "PictureBox2"
            Me.PictureBox2.Size = New System.Drawing.Size(120, 120)
            Me.PictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage
            Me.PictureBox2.TabIndex = 1
            Me.PictureBox2.TabStop = False
            Me.PictureBox3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
            Me.PictureBox3.Location = New System.Drawing.Point(368, 8)
            Me.PictureBox3.Name = "PictureBox3"
            Me.PictureBox3.Size = New System.Drawing.Size(120, 120)
            Me.PictureBox3.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage
            Me.PictureBox3.TabIndex = 2
            Me.PictureBox3.TabStop = False
            Me.PictureBox4.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
            Me.PictureBox4.Location = New System.Drawing.Point(16, 240)
            Me.PictureBox4.Name = "PictureBox4"
            Me.PictureBox4.Size = New System.Drawing.Size(120, 120)
            Me.PictureBox4.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage
            Me.PictureBox4.TabIndex = 3
            Me.PictureBox4.TabStop = False
            Me.PictureBox5.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
            Me.PictureBox5.Location = New System.Drawing.Point(192, 240)
            Me.PictureBox5.Name = "PictureBox5"
            Me.PictureBox5.Size = New System.Drawing.Size(120, 120)
            Me.PictureBox5.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage
            Me.PictureBox5.TabIndex = 4
            Me.PictureBox5.TabStop = False
            Me.PictureBox6.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
            Me.PictureBox6.Location = New System.Drawing.Point(368, 240)
            Me.PictureBox6.Name = "PictureBox6"
            Me.PictureBox6.Size = New System.Drawing.Size(120, 120)
            Me.PictureBox6.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage
            Me.PictureBox6.TabIndex = 5
            Me.PictureBox6.TabStop = False
            Me.AllowDrop = True
            Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
            Me.ClientSize = New System.Drawing.Size(506, 376)
            Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog
            Me.MaximizeBox = False
            Me.MinimizeBox = False
            Me.Name = "Form1"
            Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
            Me.Text = "PictureBox Drag & Drop"

        End Sub

    #End Region

        Private startX As Single
        Private startY As Single
        Private sourcePBs As New ArrayList
        Private targetPBs As New ArrayList

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

            Dim pb As PictureBox

            For Each pb In sourcePBs
                AddHandler pb.DoubleClick, AddressOf Me.PictureBox_DoubleClick
                AddHandler pb.MouseDown, AddressOf Me.PictureBox_MouseDown
                AddHandler pb.MouseMove, AddressOf Me.PictureBox_MouseMove
                AddHandler pb.MouseUp, AddressOf Me.PictureBox_MouseUp
        End Sub

        Private Sub PictureBox_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs)
            If OpenFileDialog1.ShowDialog = DialogResult.OK Then
                    sender.Image = Image.FromFile(OpenFileDialog1.FileName)
                Catch ex As Exception
                End Try
            End If
        End Sub

        Private Sub PictureBox_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
            If e.Button = MouseButtons.Left Then
                startX = e.X
                startY = e.Y
            End If
        End Sub

        Private Sub PictureBox_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
            If e.Button = MouseButtons.Left Then
                sender.Location = New Point(sender.Location.X + e.X - startX, sender.Location.Y + e.Y - startY)
                If Not (sender.tag Is Nothing) Then
                    Dim pb As PictureBox = CType(sender.tag, PictureBox)
                    pb.Tag = Nothing
                    sender.tag = Nothing
                    pb.Visible = True
                End If
            End If
        End Sub

        Private Sub PictureBox_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
            Dim r1 As Rectangle = New Rectangle(sender.location, sender.size)
            Dim pb As PictureBox
            Dim r2 As Rectangle
            Dim r3 As Rectangle
            Dim area As Integer
            Dim largestArea As Integer = -1
            Dim selectedPB As PictureBox = Nothing

            For Each pb In targetPBs
                If pb.Tag Is Nothing Then
                    r2 = New Rectangle(pb.Location, pb.Size)
                    If r1.IntersectsWith(r2) Then
                        r3 = Rectangle.Intersect(r1, r2)
                        area = r3.Width * r3.Height
                        If area > largestArea Then
                            largestArea = area
                            selectedPB = pb
                        End If
                    End If
                End If

            If Not (selectedPB Is Nothing) Then
                sender.location = selectedPB.Location
                sender.tag = selectedPB
                selectedPB.Tag = sender
                selectedPB.Visible = False
            End If
        End Sub

    End Class
    LVL 4

    Author Comment

    Very awesome code.  I had a quick look into the first one but preferred the code you posted here as I wanted the 'picture drag' as well, not just the boxed outline.  I added pictures in and it does exactly what I need although the double click function didn't work properly for me, I had to add the pictures in design mode?

    I'm still getting used to the new version of VB.Net as I was using VB6 before, they've changed the shortcut key to the step-into function from F8 to F11, and the feature itself also doesn't seem to function the way i'm used to..  i.e. in VB6 if you stepped through your code then hovered over a 'mouse over' event, it would pause and drop back into the code design window to show you what event/code has taken place.  Although if I step into the code in this project, nothing happens when I double click the above picture boxes or drag them around the form to tell me what code is being processed in the background..

    Ultimately I want to be able to tell which picture has been put in which box.. I've also noticed you can't drop more then one picture on a box at any one time which is perfect for what I want although I noticed although additional pictures cannot be 'snapped' as such they can be placed anywhere on or around the form, getting in the way of the other pictures.

    Point increased to 400 ;)
    LVL 85

    Expert Comment

    by:Mike Tomlinson
    That's weird about the double clicking not working for you.  Did you create a completely new project and add ALL of the code I posted over the default code for the form?

    You can determine which picture was put into which box by using the tag property of the pbs in the targetPBs arraylist.  If a picture is currently positioned on a target pb then that pbs tag property will have a reference to the corresponding picture...otherwise it will have Nothing to indicate it is empty.

    As a side note, you can place ANYTHING in the tag property so you could create a more complex class to track more things at once and then place an instance of that class into the tag propety instead of a single reference to a pb.

    It shouldn't be too difficult to make a snapping feature for the open area of the form.  Describe to me a little about you want it to work and perhaps I can give more suggestions or code.

    LVL 4

    Author Comment

    Sorry my bad..

    This message came up:
    The project location is not fully trusted by the .NET runtime. This is usually because it is either a network share or pmapped to a network share not on the local machine. If the output path is under the project location, your code will not execute as fully trusted and you may receive unexpected security exceptions. Click OK to ignore and continue. Click CANCEL to choose a different project location.

    It works ok if I save it on the local machine.  I'm running gentoo with an emulated Windows XP installation, so i'd prefer to save it to a 'network share' if possible.. Is there anyway to add it as a trusted location?
    LVL 4

    Author Comment

    Ok basically the program that I want to create is the one described here but i've had more ideas since..

    As described in the link, i'm trying to make a program to schedule game times for a volleyball centre and I was just trying to work out the easiest way to interface it..

    From what you've given me here, I thought of making pictures of all the team names, and having them in a source pool, and being able to dragging 2 teams to a destination box (or 2 different boxes on the same court,time etc) to signify that they were playing each other.


    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Threat Intelligence Starter Resources

    Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

    I think the Typed DataTable and Typed DataSet are very good options when working with data, but I don't like auto-generated code. First, I create an Abstract Class for my DataTables Common Code.  This class Inherits from DataTable. Also, it can …
    Microsoft Reports are based on a report definition, which is an XML file that describes data and layout for the report, with a different extension. You can create a client-side report definition language (*.rdlc) file with Visual Studio, and build g…
    Migrating to Microsoft Office 365 is becoming increasingly popular for organizations both large and small. If you have made the leap to Microsoft’s cloud platform, you know that you will need to create a corporate email signature for your Office 365…
    how to add IIS SMTP to handle application/Scanner relays into office 365.

    760 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    9 Experts available now in Live!

    Get 1:1 Help Now