FSA7
asked on
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.Mouse EventArgs) 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.Mouse EventArgs) Handles MyBase.MouseUp
If chkline.Checked Then
coor.x2 = e.X
coor.y2 = e.Y
Call Refresh()
End If
End Sub
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.Mouse
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.Mouse
If chkline.Checked Then
coor.x2 = e.X
coor.y2 = e.Y
Call Refresh()
End If
End Sub
Take a look at the solution I posted in this PAQ:
https://www.experts-exchange.com/questions/21035266/How-can-I-create-a-component-that-draws-a-line-in-runtime.html
I have developed more complex applications using this approach that can handle boxes, polygons, curves, etc.
~IM
https://www.experts-exchange.com/questions/21035266/How-can-I-create-a-component-that-draws-a-line-in-runtime.html
I have developed more complex applications using this approach that can handle boxes, polygons, curves, etc.
~IM
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
Can you please give me a tip,
Thanks
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.
ASKER
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!
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!
Are you working with persistent graphics (using the Graphics object from the Paint event) or non-persistent graphics (CreateGraphics method)?
Bob
Bob
ASKER
I am working with the Paint event
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.ICon tainer
'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.Check Box
Friend WithEvents Panel1 As System.Windows.Forms.Panel
<System.Diagnostics.Debugg erStepThro ugh()> Private Sub InitializeComponent()
Me.chkline = New System.Windows.Forms.Check Box
Me.Panel1 = New System.Windows.Forms.Panel
Me.SuspendLayout()
'
'chkline
'
Me.chkline.Checked = True
Me.chkline.CheckState = System.Windows.Forms.Check State.Chec ked
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.Fo rms.Anchor Styles.Top Or System.Windows.Forms.Ancho rStyles.Bo ttom) _
Or System.Windows.Forms.Ancho rStyles.Le ft) _
Or System.Windows.Forms.Ancho rStyles.Ri ght), System.Windows.Forms.Ancho rStyles)
Me.Panel1.BorderStyle = System.Windows.Forms.Borde rStyle.Fix edSingle
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.Mouse EventArgs) 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.DrawReversibl eLine(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.Mouse EventArgs) 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.DrawReversibl eLine(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.DrawReversibl eLine(sp1, sp2, Panel1.BackColor)
End If
End Sub
Private Sub Panel1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.Mouse EventArgs) 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.Paint EventArgs) 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
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.ICon
'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.Check
Friend WithEvents Panel1 As System.Windows.Forms.Panel
<System.Diagnostics.Debugg
Me.chkline = New System.Windows.Forms.Check
Me.Panel1 = New System.Windows.Forms.Panel
Me.SuspendLayout()
'
'chkline
'
Me.chkline.Checked = True
Me.chkline.CheckState = System.Windows.Forms.Check
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.Fo
Or System.Windows.Forms.Ancho
Or System.Windows.Forms.Ancho
Me.Panel1.BorderStyle = System.Windows.Forms.Borde
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.Mouse
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.DrawReversibl
' 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,
End If
End Sub
Private Sub Panel1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.Mouse
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,
Dim sp2 As Point = Panel1.PointToScreen(New Point(coords(newIndex).x2,
ControlPaint.DrawReversibl
' 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,
ControlPaint.DrawReversibl
End If
End Sub
Private Sub Panel1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.Mouse
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.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
ASKER
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.Mouse EventArgs) 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.Mouse EventArgs) 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.Paint EventArgs) 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
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.Mouse
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.Mouse
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.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
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.Mouse EventArgs) 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.Mouse EventArgs) 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.DrawReversibl eLine() 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
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.Mouse
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.Mouse
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.DrawReversibl
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
ASKER
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.Mouse EventArgs) 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
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.Mouse
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
ASKER
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.Mouse EventArgs) 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
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.Mouse
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
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks for your help, Idle Mind!
Here is an example of using a GraphicsPath for drawing:
http://www.codeproject.com/vb/net/Freehand_Drawing.asp
Bob