Drawing lines, width.

newguy

Well-known member
Joined
Jun 30, 2008
Messages
611
Location
Denver Co, USA
Programming Experience
1-3
Hi all,
This draws fine, just too small...
I am trying to get the line width bigger.
I am drawing inside of a panel, this isn't working.

Paint event:
VB.NET:
Dim g As Graphics = e.Graphics
        Dim l As Line
        For Each l In lines
            g.DrawLine(New Pen(Color.Black, 10), X, Y, X, Y)
        Next
        g.Dispose()
 
Well, that would be because you're specifying the same point as the start and end of the line. If the line has a zero length then you're not going to see it, are you?

Also, you should NOT be disposing the Graphics object. You didn't create it so you don't destroy it. It will get destroyed inside the control, just as it was created inside the control.

Finally, given that you're using the same colour and width each time, you should not be creating a new Pen each time. You should be creating only one Pen object and this time you SHOULD be disposing it, because you created it. I'd go with this code:
VB.NET:
With e.Graphics
    Using p As New Pen(Color.Black, 10.0F)
        For Each l As Line In lines
            g.DrawLine(p, l.X1, l.Y1, l.X2, l.Y2)
        Next
    End Using
End With
 
I tried something similar, and tried yours neither are working. Ths is the real code, ptA and ptB are points in the Line class.

VB.NET:
Dim p As New Pen(Color.Black, 10.0F)
Dim i As Line
For Each i In lines
     g.DrawLine(p, Panel1.Width * i.ptA.X, Panel1.Height * i.ptA.Y, _
     Panel1.Width * i.ptB.X, Panel1.Height * i.ptB.Y)
Next
:confused:
 
Here's everything:
VB.NET:
Private Class Line
        Public ptA As PointF
        Public ptB As PointF
    End Class
    Dim startPoint As Point
    Dim endPoint As Point
    Dim lines As New ArrayList
    Dim prevClip As Rectangle
    Private Sub Panel1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left Then
            startPoint = New Point(e.X, e.Y)
            endPoint = startPoint
            ControlPaint.DrawReversibleLine(Panel1.PointToScreen(startPoint), Panel1.PointToScreen(endPoint), Color.Black)
            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 e.Button = Windows.Forms.MouseButtons.Left Then
            ControlPaint.DrawReversibleLine(Panel1.PointToScreen(startPoint), Panel1.PointToScreen(endPoint), Color.Black)
            endPoint = New Point(e.X, e.Y)
            ControlPaint.DrawReversibleLine(Panel1.PointToScreen(startPoint), Panel1.PointToScreen(endPoint), Color.Black)
        End If
    End Sub
    Private Sub Panel1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseUp
        If e.Button = Windows.Forms.MouseButtons.Left Then
            Dim i As New Line
            i.ptA = New Point(startPoint.X / Panel1.Width, startPoint.Y / Panel1.Height)
            i.ptB = New Point(endPoint.X / Panel1.Width, endPoint.Y / Panel1.Height)
            lines.Add(i)
            Cursor.Clip = prevClip
        End If
    End Sub
    Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
        Dim g As Graphics = e.Graphics
        Dim p As New Pen(Color.Black, 5.0F)
        Dim i As Line
        For Each i In lines
            g.DrawLine(p, Panel1.Width * i.ptA.X, Panel1.Height * i.ptA.Y, _
                       Panel1.Width * i.ptB.X, Panel1.Height * i.ptB.Y)
        Next
    End Sub

I thought after using the graphics you were supposed to dispose them as they are memory hogs?
 
The theory is sound so if it's not working for you then you must be using bad data, so you need to look at your data. I can't see what actual values you're using so I can't say what the problem might be but I'm guessing that your calculations are simply incorrect and the line is being drawn where you can't see it. You can prove for yourself that the principle works by cutting out all the variables and just using literal values. Run this code in a new project and you'll see that it works:
VB.NET:
Public Class Form1

    Private Sub Form1_Paint(ByVal sender As Object, _
                            ByVal e As PaintEventArgs) Handles Me.Paint
        Using p As New Pen(Color.Black, 10)
            e.Graphics.DrawLine(p, 10, 10, 100, 150)
        End Using
    End Sub

End Class
 
I thought after using the graphics you were supposed to dispose them as they are memory hogs?
It's not because they're memory hogs but you are supposed to dispose Graphics objects, and anything else with a Dispose method, after you're finished with them IF you created them in the first place. In this case you didn't create the Graphics object so you don't dispose it. It was created for you by the control and it's the control's responsibility to dispose, which it WILL do. You just worry about disposing your Pen, which you DO create.
 
Well the lines are being drawn where I can see them they are just 1 pixel width in size - this is the problem. And thanks for the correctness on disposing, I must have read that wrong.
 
I just pasted your code into a project of my own and it's a bit of a mess I'm afraid. You're doing a few things wrong. Try running your app and drawing a few lines on your form. Now minimise the form and restore it. Notice how the drawing changes somewhat, AND the lines are thicker?

The problem is that the thin lines you see are getting drawn in your event handlers other than that for Paint. You draw those lines without repainting the form, so the Paint event is never raised and your think lines are never drawn. Minimising and restoring the form forces a repaint, which simply discards those thin lines and draws the thick ones, although in completely different places.

I suggest that you take a look at this.
 
I have this now - it works but flicker a lot:
VB.NET:
 Public Class Line
        Public ptA As PointF
        Public ptB As PointF
    End Class
    Dim startPoint As Point
    Dim endPoint As Point
    Dim lines As New ArrayList
    Dim prevClip As Rectangle
    Private Sub Panel1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left Then
            startPoint = New Point(e.X, e.Y)
            EndPoint = startPoint
            ControlPaint.DrawReversibleLine(Panel1.PointToScreen(startPoint), Panel1.PointToScreen(EndPoint), Color.Black)
            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 e.Button = Windows.Forms.MouseButtons.Left Then
            ControlPaint.DrawReversibleLine(Panel1.PointToScreen(startPoint), Panel1.PointToScreen(endPoint), Color.Black)
            endPoint = New Point(e.X, e.Y)
            ControlPaint.DrawReversibleLine(Panel1.PointToScreen(startPoint), Panel1.PointToScreen(endPoint), Color.Black)
        End If
    End Sub
    Private Sub Panel1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseUp
        If e.Button = Windows.Forms.MouseButtons.Left Then
            Dim i As New Line
            i.ptA = New Point(startPoint.X, startPoint.Y)
            i.ptB = New Point(endPoint.X, endPoint.Y)
            lines.Add(i)
            Cursor.Clip = prevClip
        End If
    End Sub
    Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
        DrawLine(e.Graphics)
        Panel1.Refresh()
    End Sub
    Private Sub DrawLine(ByVal g As Graphics)
        Dim p As Pen = New Pen(Color.DarkBlue, 3.0F)
        Dim i As Line
        For Each i In lines
            g.DrawLine(p, i.ptA, i.ptB)
        Next
        p.Dispose()
    End Sub
 
Did you look at the post that jmcilhinney suggested? If you had, you should have ended up with something like this :-

VB.NET:
Option Explicit On
Option Strict On

Public Class Form1

    Public Class Line
        'The line's start point.
        Private _start As Point
        'The line's end point.
        Private _end As Point
        'The line's start point.
        Public Property Start() As Point
            Get
                Return Me._start
            End Get
            Set(ByVal value As Point)
                Me._start = value
            End Set
        End Property
        'The line's end point.
        Public Property [End]() As Point
            Get
                Return Me._end
            End Get
            Set(ByVal value As Point)
                Me._end = value
            End Set
        End Property
        Public Sub New()
            Me.New(Point.Empty, Point.Empty)
        End Sub
        Public Sub New(ByVal start As Point, ByVal [end] As Point)
            Me._start = start
            Me._end = [end]
        End Sub
    End Class
    Public CompletedLines As New List(Of Line)

    Private startPoint As New Point(0, 0)
    Private endPoint As New Point(0, 0)
    Private LineRunning As Boolean = False

    Public Sub New()

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

        ' Add any initialization after the InitializeComponent() call.
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.SetStyle(ControlStyles.UserPaint, True)

    End Sub


    Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        endPoint.X = e.X
        endPoint.Y = e.Y
        Me.Invalidate()
    End Sub
    Private Sub Form1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
        If e.Button = Windows.Forms.MouseButtons.Left Then
            If LineRunning = False Then
                'start new line
                startPoint.X = e.X
                startPoint.Y = e.Y
                LineRunning = True
            Else
                'finish current line and add to list
                endPoint.X = e.X
                endPoint.Y = e.Y
                CompletedLines.Add(New Line(startPoint, endPoint))
                LineRunning = False
            End If
        End If
    End Sub

    Private pBlack As New Pen(Color.Black, 10)
    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        With e.Graphics

            'draw all the existing lines
            For Each _Line As Line In CompletedLines
                .DrawLine(pBlack, _Line.Start, _Line.End)
            Next

            If LineRunning = True Then
                .DrawLine(pBlack, startPoint, endPoint)
            End If
        End With
    End Sub

End Class
 
I did, but I didn't see what you have. I fact I pasted the entire code and it was not working, so I went back to modify what I had. Though I appreciate the help, I can't find the code you have anywhere in the link he sent. Why do people seem upset at me, I am trying to learn something very new, I find some freakish stuff on the internet and when it does not work I simply try to ask for help. I help people with code from time to time, but never have I given someone such a hard time. So what gives.

Signed,
Confused seeker of knowledge
 
What does the Refresh method do? It forces a repaint of the control, which means it raises the Paint event. In your code you're calling Refresh in the Paint event handler, so every time the control repaints you're forcing it to repaint. That's what the flickering is: non-stop repainting.

You ONLY force a repaint when you have changed what's going to get drawn. Even then, you should ONLY be invalidating the area that's changed and then calling Update. There's no need to repaint the entire control if only a small area has changed.

I'd really suggest that you get rid of all that ControlPaint stuff. Just draw in the Paint event handler.
 
What does the Refresh method do? It forces a repaint of the control, which means it raises the Paint event. In your code you're calling Refresh in the Paint event handler, so every time the control repaints you're forcing it to repaint. That's what the flickering is: non-stop repainting.
If you do keep the ControlPaint stuff, when do you actually want to force the Panel to repaint? Not when it's just repaint. You want it to repaint when you've just finished creating a line, which would be in the MouseUp event handler.

You're still not going to get thick lines displayed as you're drawing them using that DrawReversibleLine method because it doesn't let you specify a thickness. If you try out the code that InertiaM provided you'll see that using the Paint event only WILL allow you to display thick lines as they're being drawn.
 
It does work, while I am drawing it is a thin black line but changes to thick blue after I am done, I will most likely change my code as you have suggested, thanks.
 
Last edited:
Back
Top