locked
How to draw in a picturebox RRS feed

  • Question

  • I am trying to display results in a picturebox.

    I use the the paint event to draw text on the picturebox. The first time the code runs, the text gets displayed. But the next time the paint event fires, all I get in the picturebox is the errorimage (a big red X through it). How do you get it to refresh the displayed text in the picturebox?

    The routine crashes when it calles the first gr.drawstring in the ShowResults.

     Private Sub Results_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles picResults.Paint
            ShowResults(e.Graphics, New Point(0, 0), picResults.Size)
        End Sub

        Sub ShowResults(gr As Graphics, DiagramUpperLeft As Point, DiagramSize As Size)

            gr.ResetClip()
            gr.ResetTransform()
            gr.Clear(Color.White)
            gr.Clip = New Region(New Rectangle(DiagramUpperLeft, DiagramSize))

            Dim pFont As Font = New Font(FontName, FontSize)
            Dim pbrush As Brush = Brushes.Black

            'set margins
            Dim lmargin, rmargin, tmargin, bmargin As Integer
            Dim Txt As String, strbox As SizeF
            Dim xl, yt, yb As Integer
            Dim ypadding As Integer = 4

            Txt = Me.Text  'Program description and version from the form title
            strbox= gr.MeasureString(Txt, pFont)

            Dim linspacing As Integer = strbox.Height + ypadding 'Use this as a generic text linefeed spacing for vertical positioning
            Dim spcwidth As Integer = (gr.MeasureString("_ _", pFont)).Width - (gr.MeasureString("__", pFont)).Width

            Dim cols() As Integer = {25, 75, 150, 275, 400, 550}
            yt = tmargin + 25 : yb = yt

            Txt = lblCase.Text
            strbox= (gr.MeasureString(Txt, pFont))
            xl= lmargin + cols(0)
            gr.DrawString(Txt, pFont, pbrush, xl, yb) ' <-- crashes here the second time through

            Txt = lblP.Text
            strbox= (gr.MeasureString(Txt, pFont))
            xl= lmargin + cols(1)
            gr.DrawString(Txt, pFont, pbrush, xl, yb)

            Txt = lblM.Text
            strbox= (gr.MeasureString(Txt, pFont))
            xl= lmargin + cols(2)
            gr.DrawString(Txt, pFont, pbrush, xl, yb)

            Txt = "Qmax (" & IIf(metric, "kPa", "psf") & ")"
            strbox= (gr.MeasureString(Txt, pFont))
            xl= lmargin + cols(3)
            gr.DrawString(Txt, pFont, pbrush, xl, yb)

            Txt = "GovComb"
            strbox= (gr.MeasureString(Txt, pFont))
            xl= lmargin + cols(4)
            gr.DrawString(Txt, pFont, pbrush, xl, yb)

            Txt = "FOOTING SIZE"
            strbox= (gr.MeasureString(Txt, pFont))
            xl= lmargin + cols(5)
            gr.DrawString(Txt, pFont, pbrush, xl, yb)

            'Clean up
            ' Don't do a gr.Dispose() if you are planning on continuing to draw to the graphics object!

            pbrush.Dispose()
            pFont.Dispose()
            'gr.Dispose()

        End Sub


    Allen Johnson


    • Edited by AJohnson212 Friday, December 13, 2013 9:03 PM
    Friday, December 13, 2013 9:01 PM

Answers

  • As BlueLed stated, you should not dispose pBrush in your case since it is simply representing the System.Drawing.Brushes.Black brush which is a shared read-only system brush.

    If you dig into this in Visual Studio, you can see that there is an IntPtr, NativeBrush, on the Brush class. When the brush represents System.Drawing.Brushes.Black and .Dispose() is issued it appears to be killing the system brush, as the next time through, even when you dim the brush again, the IntPtr NativeBrush=0.

    When using a user-defined brush, such as:

    Dim userBrush As New SolidBrush(Color.Black)

    you should dispose it when done using it. If you come through a loop and the above Dim line gets executed again, it will recreate the user-defined brush and all should work as expected.


    - HomeGrownCoder My posts are kept as simple as possible for easier understanding. In many cases you can probably optimize or spruce up what I present. Have fun coding!

    • Proposed as answer by IronRazerz Saturday, December 14, 2013 2:07 PM
    • Marked as answer by AJohnson212 Monday, December 16, 2013 2:11 PM
    Saturday, December 14, 2013 5:20 AM

All replies

  • The routine crashes when it calles the first gr.drawstring in the ShowResults. 

    When it 'crashes' what is the exact error message and what are the values of the relevant variables (gr, Txt, pFont, pbrush, xl, yb)?    The message usually tells you what the cause of the error is and the variables often indicate why the error occurred.

    • Edited by Acamar Friday, December 13, 2013 9:40 PM sp
    Friday, December 13, 2013 9:39 PM
  • There is no error message, I just get the red X through the box.

    The variables are the same as they were the first time it ran and displayed correctly.

    I copied the code from the PrDoc_PrintPage code that worked fine with the Print Preview Control. But now that added this, the code in the PrDoc breaks at the same location, with an error:
    "An unhandled exception of type 'System.ArguementException' occurred in System.Windows.Forms.dll

    Additional Information: Parameter is not valid."

    But before I added the ShowResults Sub, it worked fine.

    If I comment out the ShowResults in the Results_Paint Sub, the Print Preview works fine, but only the first time though. The next time I print preview it, it hangs up again.


    Allen Johnson




    • Edited by AJohnson212 Friday, December 13, 2013 10:03 PM
    Friday, December 13, 2013 9:46 PM
  • try this:

    Public Class Form1
    
        Dim pFont As New Font(FontName, FontSize)
        Dim pbrush As Brush = Brushes.Black
    
        Private Sub Results_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles picResults.Paint
            ShowResults(e.Graphics, New Point(0, 0), picResults.Size)
        End Sub
        Sub ShowResults(ByVal gr As Graphics, ByVal DiagramUpperLeft As Point, ByVal DiagramSize As Size)
    
            gr.ResetClip()
            'gr.ResetTransform()
            gr.Clear(Color.White)
            gr.Clip = New Region(New Rectangle(DiagramUpperLeft, DiagramSize))
    
            'set margins
            Dim lmargin, rmargin, tmargin, bmargin As Integer
            Dim Txt As String, strbox As SizeF
            Dim xl, yt, yb As Integer
            Dim ypadding As Integer = 4
            Dim metric As Boolean = True
    
            Txt = Me.Text  'Program description and version from the form title
            strbox = gr.MeasureString(Txt, pFont)
    
            Dim linespacing As Integer = CInt(strbox.Height + ypadding) 'Use this as a generic text linefeed spacing for vertical positioning
            Dim spcwidth As Integer = CInt(gr.MeasureString("_ _", pFont).Width - gr.MeasureString("__", pFont).Width)
    
            Dim cols() As Integer = {25, 75, 150, 275, 400, 550}
            yt = tmargin + 25 : yb = yt
    
            Txt = lblCase.Text
            strbox = gr.MeasureString(Txt, pFont)
            xl = lmargin + cols(0)
            'Stop
            gr.DrawString(Txt, pFont, pbrush, xl, yb) ' <-- crashes here the second time through
    
            Txt = lblP.Text
            strbox = (gr.MeasureString(Txt, pFont))
            xl = lmargin + cols(1)
            gr.DrawString(Txt, pFont, pbrush, xl, yb)
    
            Txt = lblM.Text
            strbox = (gr.MeasureString(Txt, pFont))
            xl = lmargin + cols(2)
            gr.DrawString(Txt, pFont, pbrush, xl, yb)
    
            Txt = "Qmax (" & If(metric, "kPa", "psf") & ")"
            strbox = (gr.MeasureString(Txt, pFont))
            xl = lmargin + cols(3)
            gr.DrawString(Txt, pFont, pbrush, xl, yb)
    
            Txt = "GovComb"
            strbox = (gr.MeasureString(Txt, pFont))
            xl = lmargin + cols(4)
            gr.DrawString(Txt, pFont, pbrush, xl, yb)
    
            Txt = "FOOTING SIZE"
            strbox = (gr.MeasureString(Txt, pFont))
            xl = lmargin + cols(5)
            gr.DrawString(Txt, pFont, pbrush, xl, yb)
    
            'Clean up
            ' Don't do a gr.Dispose() if you are planning on continuing to draw to the graphics object!
            ' Don't Dispose() the Brush + Font if you are planning on continuing to use them!
    
            'i moved the Brush + Font declarations to form scope
    
            'pbrush.Dispose()
            'pFont.Dispose()
            'gr.Dispose()
    
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            picResults.Invalidate()
        End Sub
    End Class


    thanks for any help

    Friday, December 13, 2013 10:02 PM
  • I left the pBrush and pFont as local variables, but commented out the .Dispose() lines and that seems to work.  I guess I'm not understanding these objects too well.  Wouldn't they be recreated when the routine runs the second time through, if they are "disposed"?

    Allen Johnson

    Friday, December 13, 2013 10:14 PM
  • I left the pBrush and pFont as local variables, but commented out the .Dispose() lines and that seems to work.  I guess I'm not understanding these objects too well.  Wouldn't they be recreated when the routine runs the second time through, if they are "disposed"?

    Allen Johnson

    I'd've thought so, but it doesn't work + it took me a few minutes to find the problem.

    I tried to find an explanation of this behaviour on MSDN, but I was unable to find a fitting description.

    Maybe someone else can explain...


    thanks for any help

    Friday, December 13, 2013 10:36 PM
  • There is no error message, I just get the red X through the box.

    The variables are the same as they were the first time it ran and displayed correctly.

    I don't follow.   You have stated "The routine crashes when it calles the first gr.drawstring in the ShowResults."  If there isn't an error and an error message, why do you think the problem is at this line of code? What exactly is a 'crash'?

    The code you have posted has nothing to do with printing, but you are now talking about PR_Doc and a print preview.  I don't see how it can possibly have 'worked fine' before you added the ShowResults sub because there would have been no code to do any drawing at all! The picture box paint event handler would have done exactly nothing. Or are you saying that there is some other code somewhere that worked fine before you added this sub? If so, you need to look at the connection between that other code and this sub. I suspect that the problem is actually in some other code that attempts to update the picture box, overwriting whatever the paint event handler is doing, and the red X simply indicates that the picture box has no valid current image.

    Friday, December 13, 2013 10:52 PM
  • I know the error occurs at that line because that's when the red X appears and the program stops working. Removing the .dispose at the end of the routine fixed that problem.

    But now I get another problem.

    I have a series of indexed textboxes.

    (I used a VB6 conversion program to import the original VB6 program to a vb.net program and it created an array of textboxes:

      Sub InitializetxtP()
            ReDim txtP(4)
            Me.txtP(4) = _txtP_4
            Me.txtP(3) = _txtP_3
            Me.txtP(2) = _txtP_2
            Me.txtP(1) = _txtP_1
        End Sub

    )

    But now the ShowResults crashes with the code below:

          Txt = CType(txtP(i).Text, String)
                strbox = (gr.MeasureString(Txt, pFont)) ' <-- crashes here.
                xl = lmargin + cols(1) - strbox.Width
                gr.DrawString(Txt, pFont, pBrush, xl, yb)



    Allen Johnson

    Friday, December 13, 2013 11:07 PM
  • I left the pBrush and pFont as local variables, but commented out the .Dispose() lines and that seems to work.  I guess I'm not understanding these objects too well.  Wouldn't they be recreated when the routine runs the second time through, if they are "disposed"?

    Allen Johnson

    This

    Dim pbrush As Brush = Brushes.Black

    doesn't create a new brush, it uses the black brush created by gdi+

    If you dispose it, there will be some kind of error the next time it is used internally.


    • Edited by BlueLed Friday, December 13, 2013 11:11 PM
    • Proposed as answer by IronRazerz Saturday, December 14, 2013 12:29 PM
    Friday, December 13, 2013 11:10 PM
  • I know the error occurs at that line because that's when the red X appears and the program stops working. Removing the .dispose at the end of the routine fixed that problem.

    That's an invalid conclusion.  The red X appears when the picturebox gets redrawn.  There is no particular connection between what created the red X and the re-drawing of the picture box.

    If your question has been answered you should mark one or more of the responses as answers and post your new question in a new thread.

    Saturday, December 14, 2013 3:13 AM
  • As BlueLed stated, you should not dispose pBrush in your case since it is simply representing the System.Drawing.Brushes.Black brush which is a shared read-only system brush.

    If you dig into this in Visual Studio, you can see that there is an IntPtr, NativeBrush, on the Brush class. When the brush represents System.Drawing.Brushes.Black and .Dispose() is issued it appears to be killing the system brush, as the next time through, even when you dim the brush again, the IntPtr NativeBrush=0.

    When using a user-defined brush, such as:

    Dim userBrush As New SolidBrush(Color.Black)

    you should dispose it when done using it. If you come through a loop and the above Dim line gets executed again, it will recreate the user-defined brush and all should work as expected.


    - HomeGrownCoder My posts are kept as simple as possible for easier understanding. In many cases you can probably optimize or spruce up what I present. Have fun coding!

    • Proposed as answer by IronRazerz Saturday, December 14, 2013 2:07 PM
    • Marked as answer by AJohnson212 Monday, December 16, 2013 2:11 PM
    Saturday, December 14, 2013 5:20 AM