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 Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

VB Application that performs graphical data mapping

Status
Not open for further replies.

tbtcust

Programmer
Oct 26, 2004
214
0
0
US
Hello everyone. First let me say that there will probably be some silly questions coming from me, as I am not a VB front end developer. I normally work on back end coding.

I'm trying to develop a VB front end application that will perform graphical data mapping. What I want to do is build an application that has a front-end which list items on the left (source) and right (target) sides of a screen. I want the front-end I'm building to give the user the ability to drag an item from the source side and drop it on an item from the target side and create a line between the two. I also want this action to trigger some back-end processing.

See first two sample images at the following link:
Will I need a special VB add-on or is this built-it? If I need an add-on, would some please make a recommendation?

Thanks in advance for any help.
 
There's nothing native to VB that'll do what you are asking. And I'm not sure that there is a suitable add-in. Although I'd be happy to be proved wrong.
 
I agree this sounds like a "roll your own" situation. Easy on the face of it, but growing in complexity as real-world requirements are surfaced: delete a "connection," multiple connectivity (one to many), show "selected" state for a connection line, tab through connection line instances, scroll and zoom to resolve closely-packed dense maps, deal with High DPI scaling scenarios, etc.

Add-in? Do you mean "3rd party control?" There might be/might have once been something like this but I can't recall seeing one.
 
Thank you for the replies. Yes "3rd party control" is indeed what I'm thinking. Have been Googling with no luck.
 
If you had the source data in one table and the target in another table of the same database, you could show them in two datagrids side by side.
You can "insert" an item in the target by creating a new item in a new row then refreshing the table/grid so it resorts to put the new entry in the right place depending on what record you are sorting by (eg Name or ID)

To "insert" an item from the source table you click on the source row and click again on the record in the target where you want ir to insert.

The code to remember and paste the new entry occur when you click on the table.

If you dont want it sorted by namw you would have to sort by an ID number that indicates the place in the table. Assign each record in each table an extra column to show its place in the table. When you insert a record you need to update all the following items by one and call the newly inserted record the number.

To show lines between the entries you can use the line statement and set its coordinates to nmatch the record number

Have fun!
 
Thanks tedsmith.

When you say "line statement" you are talking about the VB Line object. True?

Also, I have never worked with line statement. Do you have a small snipped of code I could look at?

Also, as I scroll either datagrid will I need to reset the coordinates? or will VB resets the coordinates for me?

Thanks in advance for your help.
 
>To "insert" an item from the source table you click on the source row and click again on the record in the target

Not sure this is the goal. The goal appears to be to be able to use drag'n'drop to LINK two items

>set its coordinates to nmatch the record number

Perhaps you could explain how the record number translates to screen coordinates
 
I have only given you an idea of what to do, the actual code resides in the subroutines that you select for the datagrid component such as Sub Datagrid1_Click etc. I assume you know how to use datagrids?

My suggestion would use click on each datagrid to set the start and end of each line rather than drag a line - I find it easier and quicker anyway. I know it will never be like the mapping programs but it will give you the same info in another way.

I am 1000km away from my computer with vb6 for a week or so so I can't test or give you exact code but here is a method -

A line can be drawn anywhere on the screen using the line component in the component toolbox. To create a line, drag one from the toolbox to the screen.
The position of the line is determined by the coordinates of each ends of the line eg
0,0 and 5000,5000 will move it to a diagonal position starting in the ledt top corner.

When you want to "draw" a line, you have to change the coordinates of the line with the index the same as the row number selected.

Example for say row 5 in the source to row 8 target in a small gatagrid -
Firat create as many lines that you may need in the corner of the screen and make them invisible. This should be the same as the number of rows in your left datagrid.

Give them the same name (MyLine) and an index number equal to the linely record number corresponding to the line of the data grid you will be clicking on
Measure the coordinates of the centre of each row in of the datagrids (by placing a frame temporsrily over it and noting its left and top values)
If say the row vertical spacing is 500 then you can position the start of the line by a statement that does in effect -

Click on source row 5
ScVertPosition = 250+ SourceDatagrid row Top+ (SourceDatagrid Row -1) * 500
MyLine(5) left vertical position = ScVertPosition
MyLine(5) left hohizontal position= SourceDatagrid.left + SourceDataGrid.Width 'right edge of source datagrid

This automatically positions the start of the line to the end of the row you click on.
You could set the grid to highlight the whole row clicked on so you know you have clicked on it

Do a similar thing to the TargetDatagrid

Click on Target row 8
TarVertPosition = 250+ TarDatagrid row Top+ (TargetDatagrid Row -1) * 500
MyLine(5) right vertical position = TarVertPosition
MyLine(5) right hohizontal position= TargetDatagrid.left 'left edge of target datagrid
MyLine(5).visible=true

Vb wont reset the coordinates automatically. You need to do this youself and gets a bit more complicated.
One way could be to hide all lines when you are scrolling and show a new set of lines a second afterwards.(in ForNext loops)
The logic of which line went to which row is a matter of adding to or subtracting from the variables ScVertPosition and TarVertPosition before positioning the line. That is why you may need another column with an ID to reference instead of the actual grid row number so the relationship stays correct irrespective of which datagrid you scroll. You stll only need the same number of lines that your visible grid has.
The Source ID should be the control and the Target set to the same as the source Id previously selected when you click on the target. You need each ID column set to unique so you can't double up.
This automaticlaly takes care of changing the relationshio.
Have fun!
I think Vb6 would be too slow to dynamically reposition each line smoothly as you scrolled.
 
>I think Vb6 would be too slow to dynamically reposition each line smoothly as you scrolled

I'd disagree
 
In fact, here's a simple proof of concept.

It requires a form
On the form, two listboxes, a line control and a checkbox

list1 should be to the left of list2
List1 multiselect should be set to simple, list2 multiselect set to none
line control, set Index to 0

Then cut an copy this code (fairly rough, just put it together quickly, and as a result it uses one or two magic numbers):

Code:
[blue]Option Explicit

Private Const LB_GETITEMRECT = &H198
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type

Private InDrag As Boolean
Private TrackX As Single
Private TrackY As Single

Private Sub Check1_Click()
    ' Set whether List2 can be dragged to a new position or whether, instead, an item is selected when we click on List2
    List2.DragMode = Check1
End Sub

Private Sub Form_DragDrop(Source As Control, X As Single, Y As Single)
    Source.Left = TrackX + X
    Source.Top = TrackY + Y
    InDrag = False
    Source.Visible = True
    LineLink
End Sub


Private Sub Form_Load()
    Dim word
    
    ' Set up for example...
    Line1(0).Visible = False
    Form1.ScaleMode = vbPixels
    List1.Clear
    List1.Height = 100
    List2.Clear
    List2.Height = 100
    ' just some random words to populate listboxes
    For Each word In Split("Lorem ipsum dolor sit amet consectetuer adipiscing elit Maecenas porttitor congue massa", " ")
        List1.AddItem word
        List2.AddItem word
    Next
    
    Check1.Caption = "Allow List2 Drag"
    Check1_Click
End Sub

Private Sub List1_Click()
    LineLink
End Sub

Private Sub List1_Scroll()
    LineLink
End Sub


Public Sub LineLink()
    Dim start As RECT
    Dim starttop As Long
    Dim finish As RECT
    Dim finishtop As Long
    Dim lineindex As Long
    
    Static maxlinecount As Long
    
    Dim lp As Long
    
    
    For lp = 1 To maxlinecount
        Line1(lp).Visible = False ' we might prefer to unload unused controls, but you cannot do that in a scroll event
    Next
    
    maxlinecount = 0
    
    For lp = 0 To List1.ListCount - 1
        If List1.Selected(lp) Then
            lineindex = lineindex + 1
            
            On Error Resume Next ' ignore the fact that lines might already be loaded
            Load Line1(lineindex) ' dynamically load line controls
            Load Line1(lineindex + 1)
            Load Line1(lineindex + 2)
            On Error GoTo 0
            
            SendMessage List1.hwnd, LB_GETITEMRECT, lp, start
            SendMessage List2.hwnd, LB_GETITEMRECT, List2.ListIndex, finish
            
            starttop = (start.Top + start.Bottom) / 2
            If starttop < 0 Then starttop = 0
            If starttop > List1.Height Then starttop = List1.Height - 2 ' 2 is magic number for 3d border width
            
            finishtop = (finish.Top + finish.Bottom) / 2
            If finishtop < 0 Then finishtop = 0
            If finishtop > List1.Height Then finishtop = List2.Height - 2
            
            Line1(lineindex).X1 = List1.Left + start.Right + 2 + 18 ' 20 is a magic number for scroll bar width ...
            Line1(lineindex).X2 = Line1(lineindex).X1 + 10 ' 10 is an arbitary width for line stub
            'Line1(lineindex).X2 = List2.Left
            Line1(lineindex).Y1 = List1.Top + starttop + 2
            Line1(lineindex).Y2 = Line1(lineindex).Y1
            
            Line1(lineindex + 1).X2 = List2.Left
            Line1(lineindex + 1).X1 = Line1(lineindex + 1).X2 - 10  '10 is an arbitary width for line stub
            Line1(lineindex + 1).Y2 = List2.Top + finishtop + 2
            Line1(lineindex + 1).Y1 = Line1(lineindex + 1).Y2
            
            Line1(lineindex + 2).X1 = Line1(lineindex).X2
            Line1(lineindex + 2).X2 = Line1(lineindex + 1).X1
            Line1(lineindex + 2).Y1 = Line1(lineindex).Y1
            Line1(lineindex + 2).Y2 = Line1(lineindex + 1).Y2
            

            Line1(lineindex).Visible = True ' and now show lines if not already visble
            Line1(lineindex + 1).Visible = True
            Line1(lineindex + 2).Visible = True
            
            lineindex = lineindex + 2
        End If
        
    Next
    
    If lineindex > maxlinecount Then maxlinecount = lineindex
End Sub

Private Sub List2_Click()
    LineLink
End Sub

Private Sub List2_DragOver(Source As Control, X As Single, Y As Single, State As Integer)
    If Not InDrag Then
        TrackX = -(X / 15) ' twips to pixels
        TrackY = -(Y / 15) ' twips to pixels
        InDrag = True
        Source.Visible = False
    End If
End Sub

Private Sub List2_Scroll()
    LineLink
End Sub[/blue]

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top