Link to home
Start Free TrialLog in
Avatar of ioustinos_sarris
ioustinos_sarrisFlag for Greece

asked on

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

Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

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.

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

you got me there idle mind, didn't see your post
No problem...glad we came to the same conclusion.  =)
Avatar of ioustinos_sarris

ASKER

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!
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
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
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?
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.