Drawing lines in vb.net problem

I had a similar problem a few months ago, had to accept the answer in order to be able to post a new one.
So i will describe my situation.

There is not really a need to explain what my data is but when an event is held the program reads some data and creates two rectangles. Into those rectangles i am trying to draw a line into each of them, and onto each line some other vertical lines.

It appears that my lines are drawn and then UNdrawn...(??)
I can see what i drew for a split second and then i get the rectangles with their default background color. Moreover if i place a breakpoint i can normally saw my drawn line, exactly as i wanted it to be. What is that all about??

The event i metioned above is a click event on a button...If i move the code of that click event on the form load event, then i dont event get the temporary drawing...What is that all about No2..??

I am posting the code of the line class which contains both the creation of the rectangle and the line. The instances of tr_line are created with the button click.


Public Class tr_line
    Public lineNumber As Integer
    Public name As String
    Public stops(100) As tr_stop
    Public dist As Double
    Public graphicsRect As PictureBox
    Public gMyGraphics As Graphics ' the drawing surface
    Dim pMyPen As Pen ' used to draw the lines
    Dim bMyBrush As SolidBrush = New SolidBrush(Color.White) ' used to draw the background
    Public label As Label

    Public Sub New(ByVal num As Integer, ByVal name As String, ByVal importFileName As String)

        Dim tempStop As tr_stop
        Me.name = name
        Me.lineNumber = num
        Dim srFileReader As System.IO.StreamReader
        Dim sInputLine As String
        srFileReader = System.IO.File.OpenText(importFileName)
        sInputLine = srFileReader.ReadLine()
        Dim tempStopArray() As String
        Dim cnt As Integer = 0
        Do Until sInputLine Is Nothing
            tempStopArray = sInputLine.Split(";")
            tempStop = New tr_stop(tempStopArray(1), CDbl(tempStopArray(2)), CDbl(tempStopArray(3)), CDbl(tempStopArray(4)), cnt + 1)
            Me.stops(cnt) = tempStop
            cnt += 1
            sInputLine = srFileReader.ReadLine()
        Loop
        Me.dist = stops(cnt - 1).dist
        ReDim Preserve stops(cnt - 1)

        Me.addGraphicsBox()
        Me.drawLineAndStops()

    End Sub

    Private Sub addGraphicsBox()

        Me.graphicsRect = New System.Windows.Forms.PictureBox
        Me.graphicsRect.BackColor = System.Drawing.SystemColors.ActiveCaption
        Me.graphicsRect.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
        Me.graphicsRect.Location = New System.Drawing.Point(Form1.drawVars.X, Form1.drawVars.Y)
        Me.graphicsRect.Name = "lineDisplay" & Me.lineNumber
        Me.graphicsRect.Size = New System.Drawing.Size(Form1.drawVars.lineRectWidth, Form1.drawVars.lineRectHeight)
        Me.graphicsRect.TabIndex = 3
        Me.graphicsRect.TabStop = False

        Me.label = New Label
        Me.label.Name = "label" & Me.lineNumber
        Me.label.Location = New System.Drawing.Point(Form1.drawVars.X, Form1.drawVars.Y - 15)
        Me.label.AutoSize = True
        Me.label.Text = Me.lineNumber

        Form1.Controls.Add(Me.graphicsRect)
        Form1.Controls.Add(Me.label)
        'Friend WithEvents graphicsRect As System.Windows.Forms.PictureBox
        Form1.drawVars.oneLineAdded()
    End Sub

    Private Sub drawLineAndStops()
        Dim lineStartMargin As Integer = 10
        Dim lineYpos = CInt(Me.graphicsRect.Height * 0.65)
        Dim lineWidth = Me.graphicsRect.Width - 2 * lineStartMargin
        ' set up the drawing surface to draw in the picturebox
        gMyGraphics = Me.graphicsRect.CreateGraphics

        ' set up a pen with the color ' - this pen will be drawing the lines
        pMyPen = New Pen(Color.Orange, 5)

        ' fill the picturebox with a background color
        bMyBrush.Color = Color.White
        gMyGraphics.FillRectangle(bMyBrush, 0, 0, Me.graphicsRect.Width, Me.graphicsRect.Height)

        'gMyGraphics.DrawLine(pMyPen, 0, 0, 100, 50)
        gMyGraphics.DrawLine(pMyPen, 0 + lineStartMargin, lineYpos, lineWidth + lineStartMargin, lineYpos)

        pMyPen = New Pen(Color.Purple, 3)
        Dim pointXToDraw As Integer
        For Each st As tr_stop In Me.stops
            pointXToDraw = CInt(lineWidth * st.dist / Me.dist) + lineStartMargin
            Dim pointYstart As Integer = lineYpos - 12
            Dim pointYend As Integer = lineYpos + 12
            gMyGraphics.DrawLine(pMyPen, pointXToDraw, pointYstart, pointXToDraw, pointYend)
        Next
    End Sub

End Class

Open in new window

ioustinos_sarrisAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics TeacherCommented:
You need to handle the PAINT() event of your PictureBox and use the supplied "e.Graphics" in that event instead of CreateGraphics().

So move the code in drawLineAndStops() to the Paint() event and change:

    gMyGraphics = Me.graphicsRect.CreateGraphics

To:

    gMyGraphics = e.Graphics

You can either use AddHandler() to wire up the Paint() event or declare graphicsRect as WithEvents so you can use a Handles clause.
bansidharCommented:

Public Class tr_line
    Public lineNumber As Integer
    Public name As String
    Public stops(100) As tr_stop
    Public dist As Double
    Public graphicsRect As PictureBox
    Public gMyGraphics As Graphics ' the drawing surface
    Dim pMyPen As Pen ' used to draw the lines
    Dim bMyBrush As SolidBrush = New SolidBrush(Color.White) ' used to draw the background
    Public label As Label

    Public Sub New(ByVal num As Integer, ByVal name As String, ByVal importFileName As String)

        Dim tempStop As tr_stop
        Me.name = name
        Me.lineNumber = num
        Dim srFileReader As System.IO.StreamReader
        Dim sInputLine As String
        srFileReader = System.IO.File.OpenText(importFileName)
        sInputLine = srFileReader.ReadLine()
        Dim tempStopArray() As String
        Dim cnt As Integer = 0
        Do Until sInputLine Is Nothing
            tempStopArray = sInputLine.Split(";")
            tempStop = New tr_stop(tempStopArray(1), CDbl(tempStopArray(2)), CDbl(tempStopArray(3)), CDbl(tempStopArray(4)), cnt + 1)
            Me.stops(cnt) = tempStop
            cnt += 1
            sInputLine = srFileReader.ReadLine()
        Loop
        Me.dist = stops(cnt - 1).dist
        ReDim Preserve stops(cnt - 1)

        Me.addGraphicsBox()
        'Me.drawLineAndStops()

    End Sub

    Private Sub addGraphicsBox()

        Me.graphicsRect = New System.Windows.Forms.PictureBox
        Me.graphicsRect.BackColor = System.Drawing.SystemColors.ActiveCaption
        Me.graphicsRect.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
        Me.graphicsRect.Location = New System.Drawing.Point(Form1.drawVars.X, Form1.drawVars.Y)
        Me.graphicsRect.Name = "lineDisplay" & Me.lineNumber
        Me.graphicsRect.Size = New System.Drawing.Size(Form1.drawVars.lineRectWidth, Form1.drawVars.lineRectHeight)
        Me.graphicsRect.TabIndex = 3
        Me.graphicsRect.TabStop = False

        Me.label = New Label
        Me.label.Name = "label" & Me.lineNumber
        Me.label.Location = New System.Drawing.Point(Form1.drawVars.X, Form1.drawVars.Y - 15)
        Me.label.AutoSize = True
        Me.label.Text = Me.lineNumber

        Form1.Controls.Add(Me.graphicsRect)
        Form1.Controls.Add(Me.label)
        'Friend WithEvents graphicsRect As System.Windows.Forms.PictureBox
        Form1.drawVars.oneLineAdded()
    End Sub

    Private Sub drawLineAndStops(ByVal gMyGraphics As Graphics)
        Dim lineStartMargin As Integer = 10
        Dim lineYpos = CInt(Me.graphicsRect.Height * 0.65)
        Dim lineWidth = Me.graphicsRect.Width - 2 * lineStartMargin
        ' set up the drawing surface to draw in the picturebox
        'gMyGraphics = Me.graphicsRect.CreateGraphics

        ' set up a pen with the color ' - this pen will be drawing the lines
        pMyPen = New Pen(Color.Orange, 5)

        ' fill the picturebox with a background color
        bMyBrush.Color = Color.White
        gMyGraphics.FillRectangle(bMyBrush, 0, 0, Me.graphicsRect.Width, Me.graphicsRect.Height)

        'gMyGraphics.DrawLine(pMyPen, 0, 0, 100, 50)
        gMyGraphics.DrawLine(pMyPen, 0 + lineStartMargin, lineYpos, lineWidth + lineStartMargin, lineYpos)

        pMyPen = New Pen(Color.Purple, 3)
        Dim pointXToDraw As Integer
        For Each st As tr_stop In Me.stops
            pointXToDraw = CInt(lineWidth * st.dist / Me.dist) + lineStartMargin
            Dim pointYstart As Integer = lineYpos - 12
            Dim pointYend As Integer = lineYpos + 12
            gMyGraphics.DrawLine(pMyPen, pointXToDraw, pointYstart, pointXToDraw, pointYend)
        Next
    End Sub

    Private Sub me_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles graphicsRect.Paint
        drawLineAndStops(e.Graphics)
    End Sub

End Class

Open in new window

bansidharCommented:
you got me there idle mind, didn't see your post
Fundamentals of JavaScript

Learn the fundamentals of the popular programming language JavaScript so that you can explore the realm of web development.

Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics TeacherCommented:
No problem...glad we came to the same conclusion.  =)
ioustinos_sarrisAuthor Commented:
I see.
It seems to be working but i do not get some things.

How could i draw that line based on a event??
For example, i want to draw the rectangle when the program loads and draw the line when the user clicks on a button at any other time.

What should i do? Trigger the paint event for the graphicsRect ?
And what if i have a circle to draw as well in the rectangle as well which should be called by another event? The paint event does not seem to be taking any user define parameters

Thanks for any info you can provide me with!
ioustinos_sarrisAuthor Commented:
Moreover...
I really need to get a hold on how this is working or else i am going to have problems in the fututre

I just tried to add an icon on the container drawing surface through another class.
In order to do that i added this line to the me_paint function
Me.lineGraphics = e.Graphics

Open in new window


and later on i tried to do this through another class that holds an instance of the line object
Me.line.lineGraphics.DrawIcon(Me.theIcon, 20, 20)

Open in new window


I get a weird exception Message="Parameter is not valid."

thanks again
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics TeacherCommented:
There are so many ways to handle this type of thing...see if the below example sparks some ideas:
(Form with PictureBox1, Button1, Button2, Button3)
Public Class Form1

    Private R As New Random
    Private Colors() As Color = {Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Blue, Color.Indigo, Color.Violet}
    Private Things As New List(Of ThingaMaBob)

    Private Sub AllButtons_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click, Button2.Click, Button3.Click
        Dim thing As New ThingaMaBob
        If sender Is Button1 Then
            thing.Style = ThingaMaBob.StyleEnum.Line
        ElseIf sender Is Button2 Then
            thing.Style = ThingaMaBob.StyleEnum.Rectangle
        ElseIf sender Is Button3 Then
            thing.Style = ThingaMaBob.StyleEnum.Circle
        End If
        thing.Color = Colors(R.Next(0, Colors.Length))
        Dim ptA As New Point(R.Next(0, PictureBox1.Width), R.Next(0, PictureBox1.Height))
        Dim ptB As New Point(R.Next(0, PictureBox1.Width), R.Next(0, PictureBox1.Height))
        thing.PointA = New Point(Math.Min(ptA.X, ptB.X), Math.Min(ptA.Y, ptB.Y))
        thing.PointB = New Point(Math.Max(ptA.X, ptB.X), Math.Max(ptA.Y, ptB.Y))
        Things.Add(thing)
        PictureBox1.Refresh()
    End Sub

    Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
        Dim G As Graphics = e.Graphics
        G.DrawRectangle(Pens.Black, New Rectangle(10, 10, 100, 100))
        G.DrawString("Base Drawing", Me.Font, Brushes.Black, New Point(25, 25))

        For Each Thing As ThingaMaBob In Things
            Using P As New Pen(Thing.Color)
                Select Case Thing.Style
                    Case ThingaMaBob.StyleEnum.Line
                        G.DrawLine(P, Thing.PointA, Thing.PointB)

                    Case ThingaMaBob.StyleEnum.Rectangle
                        G.DrawRectangle(P, New Rectangle(Thing.PointA, New Size(Thing.PointB.X - Thing.PointA.X, Thing.PointB.Y - Thing.PointA.Y)))

                    Case ThingaMaBob.StyleEnum.Circle
                        G.DrawEllipse(P, New Rectangle(Thing.PointA, New Size(Thing.PointB.X - Thing.PointA.X, Thing.PointB.Y - Thing.PointA.Y)))

                End Select
            End Using
        Next
    End Sub

    Private Class ThingaMaBob

        Public Enum StyleEnum
            Line
            Rectangle
            Circle
        End Enum

        Public Style As StyleEnum
        Public Color As Color
        Public PointA As Point
        Public PointB As Point

    End Class

End Class

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ioustinos_sarrisAuthor Commented:
Aha. i see.
TO see that i got it right.
Everything that is "Drawn" is actually put in a buffer which will be implemented when the Refresh() function is called.

In order to make the refresh do different things every time i must have an instance of an object (or some variables in that matter) which has to be of global scope. Right?.

Would it be better if i extended the pictureBox class?
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics TeacherCommented:
That's exactly right.  The info about what has to be drawn must be stored somewhere.  In the simple example the Form was handling the painting based on the data within the data class, but you can also make the class receive a Graphics in its own "paint" method and the class instance would draw itself onto that graphics based on the data within itself.  So in the Paint() event you'd iterate over all the instances and pass the "e.Graphics" into each one so that it could draw itself.

You can either extend the PictureBox or create a new USERCONTROL and handle its Paint() event.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.