Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Drag/Drop & Line Draw Not Working 1

Status
Not open for further replies.

lucyv

Programmer
Mar 11, 2002
152
US
For one of my applicaitons I am trying to display multiple listboxes onto a form (representing different database tables) and then allow a user to drag a listbox item from one listbox over to another (representing relationships). When the user drops the selected item I want to programmatically draw a line from the selected item from the first listbox over to the dropped item in the second listbox. (For those of you who use SQL Server Enterprise Manager, this functionality is very similiar to when joining multiple tables when creating a view).

I can get the line to appear from the selected item in the first listbox, but I can not seem to get the line to end on the selected item of the second listbox.

I was wondering if someone could review my code to see what I am doing wrong. Please understand that I did not come up with this code on my own; I received it from this forum and from the Microsoft website.

Code:
    ' Private module variables used to hold the X/Y coordinates.
    Private X1 As Integer
    Private Y1 As Integer
    Private X2 As Integer
    Private Y2 As Integer


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

        ' Add items into list boxes, for now.
        With Me.ListBox1
            .Items.Add("Here 01")
            .Items.Add("Here 02")
        End With

        With Me.ListBox2
            .Items.Add("Here 03")
            .Items.Add("Here 04")
        End With

    End Sub


    Private Sub listBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseDown

        ' Determines which item was selected.
        Dim lb As ListBox = CType(sender, ListBox)
        Dim pt As New Point(e.X, e.Y)

        'Retrieve the item at the specified location within the ListBox.
        Dim index As Integer = lb.IndexFromPoint(pt)

        ' Places the X/Y locations of ListBox1 into the starting X1 and Y1 coordinates.
        X1 = Me.ListBox1.Location.X + Me.ListBox1.Width - 5
        Y1 = e.Y + 10

        ' Starts a drag-and-drop operation.
        If index >= 0 Then
            ' Retrieve the selected item text to drag into the RichTextBox.
            lb.DoDragDrop(lb.Items(index).ToString(), DragDropEffects.Copy)
        End If

    End Sub


    Private Sub ListBox2_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragEnter

        ' If the data is text, copy the data to the RichTextBox control.
        If e.Data.GetDataPresent("Text") Then
            e.Effect = DragDropEffects.Copy
        End If

    End Sub


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

        ' Determines which item was selected.
        Dim lb As ListBox = CType(sender, ListBox)
        Dim pt As New Point(e.X, e.Y)
        
        'Retrieve the item at the specified location within the ListBox.
        Dim index As Integer = lb.IndexFromPoint(pt)

        ' Calls the DrawLine function, passing the X/Y coordinates.
        Call DrawLine(X1, Y1, pt.X, pt.Y)

    End Sub


    Private Sub DrawLine(ByVal iX1 As Integer, ByVal iY1 As Integer, ByVal iX2 As Integer, ByVal iY2 As Integer)

        Dim g As Graphics
        Dim oPen As New Pen(Color.Red, 2)

        Try
            g = Me.CreateGraphics
            g.DrawLine(oPen, iX1, iY1, iX2, iY2)
        Finally
            oPen.Dispose()
            oPen = Nothing
            g.Dispose()
            g = Nothing
        End Try

    End Sub

With this code the line starts at the right spot, but it draws a line way past the second listbox. Please help!

Also, at this time I would also like to personally thank EarthAndFire, JonBatts, and Astrodestino for helping me on previous posts this past week.

-lucyv
 
I can see where the problem is, but I can't see a solution for the moment.

(1)
Private Sub ListBox2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragDrop

(2)
Private Sub listBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseDown

(1) e.Y = Screen co-ordinates
(2) e.Y = Listbox1 co-ordinates

The XY values returned in DragEventArgs are the mouse position on the screen - they bear no direct relationship to your form or its controls, whereas the XY values returned in MouseEventArgs relate to the control that is generating the event. Although annoying, this does make sense, because you can drag and drop across applications.

Whilst this is not a solution, hopefully it gives you somewhere to investigate from.






 
I think I've solved it - try this:

Code:
  Dim x1, x2, y1, y2 As Integer

  Private Sub ListBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseDown

    ' Determines which item was selected.
    Dim pt As New Point(e.X, e.Y)

    'Retrieve the item at the specified location within the ListBox.
    Dim index As Integer = ListBox1.IndexFromPoint(pt)

    ' Places the X/Y locations of ListBox1 into the starting X1 and Y1 coordinates.
    x1 = ListBox1.Right 'Me.ListBox1.Location.X + Me.ListBox1.Width - 5
    y1 = e.Y + ListBox1.Top 'e.Y + 10

    ' Starts a drag-and-drop operation.
    If index >= 0 Then
      ' Retrieve the selected item text to drag into the ListBox.
      ListBox1.DoDragDrop(ListBox1.Items(index).ToString(), DragDropEffects.Copy)
    End If

  End Sub

  Private Sub ListBox2_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragEnter

    ' If the data is text, copy the data to the ListBox control.
    If e.Data.GetDataPresent("Text") Then
      e.Effect = DragDropEffects.Copy
    End If

  End Sub

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

    ' Determines which item was selected.
    'Dim pt As New Point(e.X, e.Y)

    'Retrieve the item at the specified location within the ListBox.
    'Dim index As Integer = ListBox2.IndexFromPoint(pt)

    ' Calls the DrawLine function, passing the X/Y coordinates.

    x2 = ListBox2.Left
    y2 = e.Y - ListBox2.PointToScreen(New Point(0, 0)).Y + ListBox2.Top
    DrawLine(x1, y1, x2, y2)

  End Sub

  Private Sub DrawLine(ByVal iX1 As Integer, ByVal iY1 As Integer, ByVal iX2 As Integer, ByVal iY2 As Integer)

    Dim g As Graphics
    Dim oPen As New Pen(Color.Red, 2)

    Try
      g = Me.CreateGraphics
      g.DrawLine(oPen, iX1, iY1, iX2, iY2)
    Finally
      oPen.Dispose()
      oPen = Nothing
      g.Dispose()
      g = Nothing
    End Try

  End Sub

Hope this helps.
 
earthandfire,

This works like a charm! I spent hours working on this yesterday and you got it done in a few minutes; in my opinion you deserve two stars for this!!!

On a side note, I noticed you declared the x1, x2, y1, y2 modular variables with the 'Dim' keyword. Is there a difference from using the 'Dim' keyword rather then 'Private'?

Thanks again for your help.

-lucyv
 
lucyv,

I think this sums it up quite well:
VB's default scoping rules are somewhat complicated. If you don't give a scope the declaration can be anything from Public to Private, depending on where you wrote it. When you always write a scope you can't misdefine or misunderstand it. So instead of Dim write Private, instead of Sub write Public or Private Sub, instead of Class write Public/Friend/Private Class. The use of Dim is particularly worth noting. You should use Dim only inside procedures, but never outside of them
This was taken from the following article:



____________________________________________________________

Need help finding an answer?

Try the Search Facility or read FAQ222-2244 on how to get better results.
 
lucyv, I don't think so - its just habit. I normally use Dim unless I'm creating a separate Module or Class in which case I use Public / Private as appropriate. As far as I know, Dim, the way I've used it will take the same scope / visiblity as the class in which it appears, so on second thoughts Private would probably have been better.

Normally I steer clear of graphics based questions, they tend to be fiddly and I don't have the patience for them (having no artistic skills whatsoever). Your question just looked to interesting to ignore.[smile]

By the way, thanks for the star.
 
ca8msm, as you can see I came to pretty much the same conclusion whilst I was replying. Old / bad habits die hard though.[wink]
 
Ca8msm, that's what I thought. I remember learning these scoping rules back in VB6, but I didn't know if they still apply in VB.Net. Although to be honest I still haven't figured out when and why to use the 'Friend' keyword when creating a class. Anyway thanks for the post.


EarthandFire, thanks again for the post.


-lucyv
 
Old / bad habits die hard though
Very true! I definately "overuse" the Dim keyword according to when it should be used in the MSDN article.

Although to be honest I still haven't figured out when and why to use the 'Friend' keyword when creating a class
Again, I'm going to quote another article but I think it describes it quite well:
...let us assume that you want that all the classes from your project should be able to access to your class members but classes external to your project should not be able to do so. In this case neither private nor protected can help. Only your "Friend" can help you out
and that is from:



____________________________________________________________

Need help finding an answer?

Try the Search Facility or read FAQ222-2244 on how to get better results.
 
That makes sense. Thanks ca8msm.

-lucyv
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top