[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 284
  • Last Modified:

draw program with struct and arrays

Hi I need to create a drawing program, where user chooses to draw a line, or a box or freehand.

I was advised that best way, would be to create a struct of 2 points, or 4 coordiantes, and then an array of these structs and then with mouse up and down event to store coordinates in the array.

Can anyone please give a start in how to create  an array of the struct and add lines into array ? and also how would paint() method run through the entire array drawing all the lines.

Public Structure coordinates
        Public x1, y1, x2, y2 As Double
    End Structure

    Dim coor As coordinates

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

        Dim myArray() As Double


    End Sub

    Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        If chkline.Checked Then
            coor.x1 = e.X
            coor.y1 = e.Y
        End If

    End Sub

    Private Sub Form1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
        If chkline.Checked Then
            coor.x2 = e.X
            coor.y2 = e.Y
            Call Refresh()
        End If
    End Sub
0
FSA7
Asked:
FSA7
  • 6
  • 4
  • 2
  • +1
1 Solution
 
Bob LearnedCommented:
My suggestion would be to use a GraphicsPath from the GDI+ library.  It can store and draw lines, curves, and rectangles.  The GraphicsPath class has methods, such as AddLine, AddRectangle, AddCurve, AddBezier, AddEllipse, AddPolygon, etc. to make it easier to add the appropriate object to the path.  

Here is an example of using a GraphicsPath for drawing:
http://www.codeproject.com/vb/net/Freehand_Drawing.asp

Bob
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Take a look at the solution I posted in this PAQ:
http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/VB_DOT_NET/Q_21035266.html

I have developed more complex applications using this approach that can handle boxes, polygons, curves, etc.

~IM
0
 
GipsyCommented:
Hi thanks for your replys, sorry for answering late, as i was away. I know that there are a lot of ways to create the drawing programs. And i would like to try the approach of arrays and structs, i just dont know how to make sure  how  to create an array of the structs that store the points and pen details.

Can you please give me a tip,
Thanks
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
GipsyCommented:
FSA7, sorry for asking questions in your post, i am reading the chapter about the drawing in vb.net and am also interested in the answer to your question and unfortunately dont have an answer myself.

0
 
FSA7Author Commented:
That's ok, as i agree with your point that there  hundreds of ways to make a program to do the same thing. Again, i have a condition for using structs and arrays to create to draw lines, boxes and freehand.

Thanks IdleMind and The LearnedOne,The LearnedOne i've seen the solution you sent before posting this question.
The free hand code, works well, but in my program, I d like to  make sure that line and boxes are all remembered  on the panel and not cleared when i will choose to draw smth else. And i believe from what i read that using array, and tracking the lines in the array is a good thing to do, i just need some help, as i never used structs and arrays together before in VB.net.

So, above i posted an example of the structure and wrote  simple mouse up and down events just for drawing the lines, there is an array created as well but not yet tied to the overall picture. Can you please just help me with getting the program to draw lines and get them all displayed on one panel, rather than lines rewriting each other, everytime a new is drawn.

Thanks for your help!


0
 
Bob LearnedCommented:
Are you working with persistent graphics (using the Graphics object from the Paint event) or non-persistent graphics (CreateGraphics method)?

Bob
0
 
FSA7Author Commented:
I am working with the Paint event
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
This is the bare bones code needed to draw lines on a panel:

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 chkline As System.Windows.Forms.CheckBox
    Friend WithEvents Panel1 As System.Windows.Forms.Panel
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.chkline = New System.Windows.Forms.CheckBox
        Me.Panel1 = New System.Windows.Forms.Panel
        Me.SuspendLayout()
        '
        'chkline
        '
        Me.chkline.Checked = True
        Me.chkline.CheckState = System.Windows.Forms.CheckState.Checked
        Me.chkline.Location = New System.Drawing.Point(8, 8)
        Me.chkline.Name = "chkline"
        Me.chkline.Size = New System.Drawing.Size(104, 16)
        Me.chkline.TabIndex = 0
        Me.chkline.Text = "Line"
        '
        'Panel1
        '
        Me.Panel1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
                    Or System.Windows.Forms.AnchorStyles.Left) _
                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.Panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
        Me.Panel1.Location = New System.Drawing.Point(8, 32)
        Me.Panel1.Name = "Panel1"
        Me.Panel1.Size = New System.Drawing.Size(280, 224)
        Me.Panel1.TabIndex = 1
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 266)
        Me.Controls.Add(Me.Panel1)
        Me.Controls.Add(Me.chkline)
        Me.Name = "Form1"
        Me.Text = "Line Example"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private Structure coordinates
        Public x1, y1, x2, y2 As Single
    End Structure

    Private coords() As coordinates
    Private down As Boolean = False
    Private prevClip As Rectangle

    Private Sub Panel1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseDown
        If chkline.Checked And e.Button = MouseButtons.Left Then
            ' build a new set of coordinates
            Dim newIndex As Integer
            If Not (coords Is Nothing) Then
                newIndex = coords.GetLength(0)
            Else
                newIndex = 0
            End If
            ReDim Preserve coords(newIndex)
            coords(newIndex).x1 = e.X
            coords(newIndex).y1 = e.Y
            coords(newIndex).x2 = e.X
            coords(newIndex).y2 = e.Y

            ' draw the new line on the panel
            ' at this juncture, it is just a point
            Dim sp As Point = Panel1.PointToScreen(New Point(e.X, e.X))
            ControlPaint.DrawReversibleLine(sp, sp, Panel1.BackColor)

            ' set our mousedown flag
            down = True

            ' clip the cursor so it stays within the panel
            prevClip = Cursor.Clip
            Cursor.Clip = Me.RectangleToScreen(New Rectangle(Panel1.Location, Panel1.Size))
        End If
    End Sub

    Private Sub Panel1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseMove
        If down Then
            ' erase the old line
            Dim newIndex As Integer = coords.GetUpperBound(0)
            Dim sp1 As Point = Panel1.PointToScreen(New Point(coords(newIndex).x1, coords(newIndex).y1))
            Dim sp2 As Point = Panel1.PointToScreen(New Point(coords(newIndex).x2, coords(newIndex).y2))
            ControlPaint.DrawReversibleLine(sp1, sp2, Panel1.BackColor)

            ' update the coordinates for our new point
            ' and draw the new line
            coords(newIndex).x2 = e.X
            coords(newIndex).y2 = e.Y
            sp2 = Panel1.PointToScreen(New Point(coords(newIndex).x2, coords(newIndex).y2))
            ControlPaint.DrawReversibleLine(sp1, sp2, Panel1.BackColor)
        End If
    End Sub

    Private Sub Panel1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseUp
        If down Then
            ' finalize the coordinates of our new line
            down = False
            Dim newIndex As Integer = coords.GetUpperBound(0)
            coords(newIndex).x2 = e.X
            coords(newIndex).y2 = e.Y
            ' reset cursor clipping
            Cursor.Clip = prevClip
            Panel1.Refresh()
        End If
    End Sub

    Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
        ' draw each line in the array
        If Not (coords Is Nothing) Then
            Dim g As Graphics = e.Graphics
            Dim coord As coordinates

            For Each coord In coords
                g.DrawLine(Pens.Black, coord.x1, coord.y1, coord.x2, coord.y2)
            Next
        End If
    End Sub

End Class
0
 
FSA7Author Commented:
Hi,

Thanks for the code Idle_Mind.  I am not going to use the exact code of yours, in fact i got another idea, and you code helped me with that.

Can you see how this looks and if you think this may work. The counter is the number of items in the array. In mouse-down event, I store the first endpoint in x1, y1 of the current position in the array; in mouse-ups I store the second endpoint in x2, y2 of the current position, then increment the current position, and call
refresh.,

I try running it, but it doesnt draw the line, why ?

Public Structure coordinates
        Public x1, y1, x2, y2 As Integer

    End Structure
    Dim coords() As coordinates
    Dim counter As Integer = 0


    Private Sub panel1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        If chkline.Checked And e.Button = MouseButtons.Left Then
            coords(counter).x1 = e.X
            coords(counter).y1 = e.Y

        End If
    End Sub

    Private Sub panel1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp

        coords(counter).x2 = e.X
        coords(counter).y2 = e.Y
        counter = counter + 1
        Panel1.Refresh()

    End Sub


    Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
        ' draw each line in the array
        If Not (coords Is Nothing) Then
            Dim g As Graphics = e.Graphics
            Dim coord As coordinates
            For Each coord In coords
                g.DrawLine(Pens.Black, coord.x1, coord.y1, coord.x2, coord.y2)
            Next
        End If
    End Sub
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Three things wrong:

1) The panel1_MouseDown and panel1_MouseUp events were handling MyBase.MouseDown instead of Panel.MouseDown
2) You never initialized your coords array
3) You never resize your coords array with Redim Preserve.

Here is how it should look:

    Private Sub panel1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseDown
        If chkLine.Checked And e.Button = MouseButtons.Left Then
            ReDim Preserve coords(counter)
            coords(counter).x1 = e.X
            coords(counter).y1 = e.Y
        End If
    End Sub

    Private Sub panel1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseUp
        coords(counter).x2 = e.X
        coords(counter).y2 = e.Y
        counter = counter + 1
        Panel1.Refresh()
    End Sub

Note that if you want the line to be drawn in realtime as you drag the mouse, you must use the ControlPaint.DrawReversibleLine() function as in my example.

Also, you don't need the counter variable.  Take a close look at my example to learn how to use the GetLength() and GetUpperBound() functions to determine the size and upper limit of an array.

If an array is not actually required, it would make much more sense to use a Class to store your coordinates and then store the instances of your class in an ArrayList.

~IM
0
 
FSA7Author Commented:
Wow, that worked !!! Thank you sooo much ! Plus i've learned new things !
If i add 20 more points can  ask one last qestion please !
I am drawing a rectangle with the use of the array in place, but  in the mouse up, instead of adding one line to the array, i want to add four (like if the mousedown point is x1, y1 and the mouseup point is x2,
y2, i am adding  lines x1, y1 to x2, y1, then x2, y1 to x2, y2, etc.)

So below i have added like described above, but with what i have, it only draws one vertical line. Do you know what i do wrong ?

Private Sub panel1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseUp
        If chkline.Checked And e.Button = MouseButtons.Left Then
            coords(counter).x2 = e.X
            coords(counter).y2 = e.Y
            counter = counter + 1
            Panel1.Refresh()
        End If
        If chkbox.Checked And e.Button = MouseButtons.Left Then
            coords(counter).x2 = e.X
            coords(counter).y2 = coords(counter).y1
            coords(counter).x2 = e.X
            coords(counter).y2 = e.Y
            coords(counter).x2 = coords(counter).x1
            coords(counter).y2 = e.Y
            counter = counter + 1
            Panel1.Refresh()
        End If
0
 
FSA7Author Commented:
Maybe the problem i am experiencing is because of the counter ?
I also tried my freehand code:

in mouse down  x1, y1 are set.  In mouse move  a line from
x1, y1 is added to the current point, then  x1, y1 are set to the current point so that
next line will go from there.

  Private Sub Panel1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseMove
        If chkfreehand.Checked And e.Button = MouseButtons.Left Then
            coords(counter).x2 = e.X
            coords(counter).y2 = e.Y
            coords(counter).x1 = coords(counter).x2
            coords(counter).y1 = coords(counter).y2
            Panel1.Refresh()
        End If
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Your barking up the wrong tree...

Build this project and play with it.

~IM

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 rbLine As System.Windows.Forms.RadioButton
    Friend WithEvents rbRectangle As System.Windows.Forms.RadioButton
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Panel1 = New System.Windows.Forms.Panel
        Me.rbLine = New System.Windows.Forms.RadioButton
        Me.rbRectangle = New System.Windows.Forms.RadioButton
        Me.SuspendLayout()
        '
        'Panel1
        '
        Me.Panel1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
                    Or System.Windows.Forms.AnchorStyles.Left) _
                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.Panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
        Me.Panel1.Location = New System.Drawing.Point(8, 32)
        Me.Panel1.Name = "Panel1"
        Me.Panel1.Size = New System.Drawing.Size(376, 264)
        Me.Panel1.TabIndex = 0
        '
        'rbLine
        '
        Me.rbLine.Checked = True
        Me.rbLine.Location = New System.Drawing.Point(8, 8)
        Me.rbLine.Name = "rbLine"
        Me.rbLine.Size = New System.Drawing.Size(48, 16)
        Me.rbLine.TabIndex = 3
        Me.rbLine.TabStop = True
        Me.rbLine.Text = "Line"
        '
        'rbRectangle
        '
        Me.rbRectangle.Location = New System.Drawing.Point(64, 8)
        Me.rbRectangle.Name = "rbRectangle"
        Me.rbRectangle.Size = New System.Drawing.Size(80, 16)
        Me.rbRectangle.TabIndex = 4
        Me.rbRectangle.Text = "Rectangle"
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(392, 302)
        Me.Controls.Add(Me.rbRectangle)
        Me.Controls.Add(Me.rbLine)
        Me.Controls.Add(Me.Panel1)
        Me.Name = "Form1"
        Me.Text = "Draw program with struct and arrays example"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Public Enum ShapeType
        Line = 0
        Rectangle = 1
    End Enum

    Public Structure coordinates
        Public Shape As ShapeType
        Public x1, y1, x2, y2 As Integer
    End Structure

    Dim coords() As coordinates
    Dim counter As Integer = 0

    Private Sub panel1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseDown
        If (rbLine.Checked Or rbRectangle.Checked) And e.Button = MouseButtons.Left Then
            ReDim Preserve coords(counter)
            If rbLine.Checked Then
                coords(counter).Shape = ShapeType.Line
            ElseIf rbRectangle.Checked Then
                coords(counter).Shape = ShapeType.Rectangle
            End If
            coords(counter).x1 = e.X
            coords(counter).y1 = e.Y
        End If
    End Sub

    Private Sub panel1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseUp
        coords(counter).x2 = e.X
        coords(counter).y2 = e.Y
        If coords(counter).Shape = ShapeType.Rectangle Then
            Dim temp As Integer
            ' normalize the coordinates if necessary
            If coords(counter).x2 < coords(counter).x1 Then
                temp = coords(counter).x1
                coords(counter).x1 = coords(counter).x2
                coords(counter).x2 = temp
            End If
            If coords(counter).y2 < coords(counter).y1 Then
                temp = coords(counter).y1
                coords(counter).y1 = coords(counter).y2
                coords(counter).y2 = temp
            End If
        End If
        counter = counter + 1
        Panel1.Refresh()
    End Sub

    Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
        If Not (coords Is Nothing) Then
            Dim g As Graphics = e.Graphics
            Dim coord As coordinates
            For Each coord In coords
                Select Case coord.Shape
                    Case ShapeType.Line
                        g.DrawLine(Pens.Black, coord.x1, coord.y1, coord.x2, coord.y2)

                    Case ShapeType.Rectangle
                        g.DrawRectangle(Pens.Black, coord.x1, coord.y1, coord.x2 - coord.x1, coord.y2 - coord.y1)

                End Select
            Next
        End If
    End Sub

End Class
0
 
FSA7Author Commented:
Thanks for your help, Idle Mind!
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

  • 6
  • 4
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now