Link to home
Start Free TrialLog in
Avatar of yongyih
yongyihFlag for Malaysia

asked on

Need some advice on how to create a program that can draw data model?

Hi all,

  I would like to know what should I use to create a program that able to draw data model?

E.g. I can add two listboxes (or something else) in Form call ListA, ListB.  Then ListA will list out all the fields from table A and ListB will list out all the fields from table B.  I can drag one of the field in ListA links (draw a line) to one of the field in ListB to show the relationship of two tables.

  What should I use or start from if I want to write a program like this?  Please advice.

regards,
Yong Yih
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

What is the database type?  SQL Server?  Oracle?  Access?

Bob
Avatar of yongyih

ASKER

Hi TheLearnedOne,

  Any type of database will do.  I just want to know how to display a data model in my program.  Data model including some square boxes link together by few lines.

  May be you try to open an Microsoft Access 2000 database, go to Queries, Create query in Design View. Then add two tables for the query.  I believe you can see what I am trying to do.

  If you want to give me an example, use Microsoft Access 2000 if possible but I know Oralce and MS SQL also.

  Thanks for your reply.

regards
Yong Yih



Since SQL Server has Database Diagrams with a design tool, I was wondering why you want to create your own?

Bob
Try this example out:

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        '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
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    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 Panel1 As System.Windows.Forms.Panel
    Friend WithEvents ListBox2 As System.Windows.Forms.ListBox
    Friend WithEvents ListBox1 As System.Windows.Forms.ListBox
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Panel1 = New System.Windows.Forms.Panel
        Me.ListBox2 = New System.Windows.Forms.ListBox
        Me.ListBox1 = New System.Windows.Forms.ListBox
        Me.Panel1.SuspendLayout()
        Me.SuspendLayout()
        '
        'Panel1
        '
        Me.Panel1.AllowDrop = True
        Me.Panel1.Controls.Add(Me.ListBox2)
        Me.Panel1.Controls.Add(Me.ListBox1)
        Me.Panel1.Location = New System.Drawing.Point(8, 8)
        Me.Panel1.Name = "Panel1"
        Me.Panel1.Size = New System.Drawing.Size(336, 112)
        Me.Panel1.TabIndex = 2
        '
        'ListBox2
        '
        Me.ListBox2.AllowDrop = True
        Me.ListBox2.Location = New System.Drawing.Point(224, 0)
        Me.ListBox2.Name = "ListBox2"
        Me.ListBox2.Size = New System.Drawing.Size(112, 108)
        Me.ListBox2.TabIndex = 3
        '
        'ListBox1
        '
        Me.ListBox1.AllowDrop = True
        Me.ListBox1.Location = New System.Drawing.Point(0, 0)
        Me.ListBox1.Name = "ListBox1"
        Me.ListBox1.Size = New System.Drawing.Size(112, 108)
        Me.ListBox1.TabIndex = 2
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(352, 174)
        Me.Controls.Add(Me.Panel1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.Panel1.ResumeLayout(False)
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private Class ListBoxScroll
        Inherits NativeWindow

        Private Const WM_VSCROLL = &H115

        Public Event Scrolled()

        Public Sub New(ByVal lb As ListBox)
            Me.AssignHandle(lb.Handle)
        End Sub

        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
            If m.Msg = WM_VSCROLL Then
                RaiseEvent Scrolled()
            End If

            MyBase.WndProc(m)
        End Sub

    End Class

    Private startPoint As Point
    Private endPoint As Point
    Private startIndex As Integer
    Private connections As New Hashtable
    Private lastIndex As Integer = -1
    Private WithEvents lbs1 As ListBoxScroll
    Private WithEvents lbs2 As ListBoxScroll

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim i As Integer
        Dim str As String

        For i = 1 To 10
            str = "Item" & i
            ListBox1.Items.Add(str)
            ListBox2.Items.Add(str)
        Next
        ListBox2.Height = ListBox1.Height
        Panel1.Height = ListBox1.Height
        lbs1 = New ListBoxScroll(Me.ListBox1)
        lbs2 = New ListBoxScroll(Me.ListBox2)
    End Sub

    Private Sub ListBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseDown
        If e.Button = MouseButtons.Left Then
            Dim pt As New Point(e.X, e.Y)
            startIndex = ListBox1.IndexFromPoint(pt)

            If startIndex >= 0 Then
                Dim itemRc As Rectangle = ListBox1.GetItemRectangle(startIndex)
                startPoint = ListBox1.PointToScreen(New Point(ListBox1.Width, itemRc.Top + (itemRc.Bottom - itemRc.Top) / 2))
                endPoint = startPoint
                lastIndex = -1
                ListBox1.DoDragDrop(ListBox1.Items(startIndex).ToString(), DragDropEffects.Move)
            End If
        End If
    End Sub

    Private Sub ListBox1_QueryContinueDrag(ByVal sender As Object, ByVal e As System.Windows.Forms.QueryContinueDragEventArgs) Handles ListBox1.QueryContinueDrag
        If e.Action = DragAction.Cancel Or e.Action = DragAction.Drop Then
            Panel1.Refresh()
        End If
    End Sub

    Private Sub Panel1_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Panel1.DragOver
        ControlPaint.DrawReversibleLine(startPoint, endPoint, Panel1.BackColor)
        endPoint = New Point(e.X, e.Y)
        ControlPaint.DrawReversibleLine(startPoint, endPoint, Panel1.BackColor)
    End Sub

    Private Sub Panel1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Panel1.DragEnter
        ControlPaint.DrawReversibleLine(startPoint, endPoint, Panel1.BackColor)
    End Sub

    Private Sub Panel1_DragLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Panel1.DragLeave
        Panel1.Refresh()
    End Sub

    Private Sub ListBox2_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragEnter
        e.Effect = DragDropEffects.Move
        Panel1.Invalidate()
        Panel1.Refresh()
    End Sub

    Private Sub ListBox2_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragOver
        Dim lbPoint As Point = ListBox2.PointToClient(New Point(e.X, e.Y))
        Dim index As Integer = ListBox2.IndexFromPoint(lbPoint)
        If index >= 0 Then
            ListBox2.SelectedIndex = index
            Dim itemRc As Rectangle = ListBox2.GetItemRectangle(index)
            Dim key As String
            If lastIndex <> index Then
                If lastIndex <> -1 Then
                    key = startIndex & "|" & lastIndex
                    If Not connections.ContainsKey(key) Then
                        ControlPaint.DrawReversibleLine(startPoint, endPoint, Panel1.BackColor)
                    End If
                End If
                key = startIndex & "|" & index
                If Not connections.ContainsKey(key) Then
                    endPoint = ListBox2.PointToScreen(New Point(0, itemRc.Top + (itemRc.Bottom - itemRc.Top) / 2))
                    ControlPaint.DrawReversibleLine(startPoint, endPoint, Panel1.BackColor)
                End If
                lastIndex = index
            End If
        End If
    End Sub

    Private Sub ListBox2_DragLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox2.DragLeave
        Panel1.Refresh()
        lastIndex = -1
    End Sub

    Private Sub ListBox2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragDrop
        Dim endIndex As Integer = ListBox2.IndexFromPoint(ListBox2.PointToClient(New Point(e.X, e.Y)))
        If endIndex >= 0 Then
            connections.Add(startIndex & "|" & endIndex, Nothing)
        End If
        Panel1.Refresh()
    End Sub

    Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
        Dim de As DictionaryEntry
        Dim indices() As String

        For Each de In connections
            indices = Split(de.Key, "|")
            Dim startRC As Rectangle = ListBox1.GetItemRectangle(indices(0))
            Dim endRC As Rectangle = ListBox2.GetItemRectangle(indices(1))
            Dim List1RC As Rectangle = New Rectangle(New Point(0, 0), ListBox1.Size)
            Dim List2RC As Rectangle = New Rectangle(New Point(0, 0), ListBox2.Size)

            If List1RC.IntersectsWith(startRC) AndAlso List2RC.IntersectsWith(endRC) Then
                Dim startPoint As Point = Panel1.PointToClient(ListBox1.PointToScreen(New Point(ListBox1.Width, startRC.Top + (startRC.Bottom - startRC.Top) / 2)))
                Dim endPoint As Point = Panel1.PointToClient(ListBox2.PointToScreen(New Point(0, endRC.Top + (endRC.Bottom - endRC.Top) / 2)))
                e.Graphics.DrawLine(Pens.Black, startPoint, endPoint)
            End If
        Next
    End Sub

    Private Sub lbs1_Scrolled() Handles lbs1.Scrolled
        Panel1.Refresh()
    End Sub

    Private Sub lbs2_Scrolled() Handles lbs2.Scrolled
        Panel1.Refresh()
    End Sub

End Class
Avatar of yongyih

ASKER

Hi Idle_Mind ,

  Thanks.  Basically that is what I want.  I have two more questions here.

1. Is it possible to click on any line to select it, then press DELETE button to delete it.
2. I have to create the listbox and panel during run time to draw the diagram.  Number of listbox is unlimited based on users need.  Is it possible to do that?  Since VB.NET is Object Oriented, I guess it should be possible.

What do you think?

Thanks.

regards,
Yong Yih

ASKER CERTIFIED SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
2. I have to create the listbox and panel during run time to draw the diagram.  Number of listbox is unlimited based on users need.  Is it possible to do that?  Since VB.NET is Object Oriented, I guess it should be possible.

I recommend you take the code I have given you and create a UserControl from it.  Then you can create as many instances of it as you want.  

You will need to provide a way to populate the ListBoxes with the items to connect and a way to retrieve a list of the "relations" the user has made.

This I will leave as an exercise for you to complete as I believe you need to "sweat" over this code a bit.  A lot can be learned from trying to make something work...

What you do think Bob...is this question sufficiently answered?....

;)

~IM
Avatar of yongyih

ASKER

HI Idle_Mind,

  Thank you very much for your codes.  You really help me a lot and I believe I can learn a lot from your codes.  Haha.. I really save a lot of time and I know where should I start now.

  Yes. You gave me more than my expectation. Haha.. As a reward, I will give you 200 points.

regards,
Yong Yih