locked
Graphics erased during exit from PAINT routine. RRS feed

  • Question

  • I have just converted a VB6 program to VB.NET using the recommended ArtinSoft-upgrade-companion converter
    which seems quite impressive.

    However, when I draw to a picturebox, and use a PAINT event subroutine,
    exiting the PAINT routine always clears the drawing on the picturebox control.

    To draw, I use code as created by the ArtinSoft converter:

           Using g as graphics = PicBox.CreateGraphics()
                     g.DrawRectangle( etc etc)

    and I can draw zillions of boxes quite happily, both inside and outside of the PicBox_PAINT subroutine, and from a Timer routine.

    But whenever the PicBox_PAINT routine executes (to draw or to do nothing, I've tried everything),
    the PicBox is erased on exit from PicBox_PAINT (regardless of where its content was drawn from).

    Putting a MsgBox("Exiting PAINT") at the end of the PAINT routine confirms that
    the painting has worked. As soon as I click OK on the MsgBox then the PicBox is erased.
    Without the MsgBox gives the same erase result - i've tried lots of permutations.

    The program works wonderfully if I remove the PAINT routine and just use my own routine to repaint
    the control on the rare occasions that it is needed (after minimize and maximize). It is surprising that
    the graphics are persistent for pretty well every other situation. I though the PAINT routine was going to
    be needed after other windows were moved in front of my graphics program, but this is not the case.

    Can anyone help me with the "erase after paint" problem, and also explain why the graphics are

    persistent in most situations (with no PAINT routine). I am using Windows-7 Home Premium 64-bit.

    Thanks

    John

    on a cold wintry day in Perth Western Australia

    Wednesday, June 27, 2012 3:37 AM

Answers

  • Inside the Paint event, use e.graphics, not picbox.Creategraphics.

    Armin

    Wednesday, June 27, 2012 4:07 AM
  • The reason your graphics disappear is because you aren't drawing 'on' the control: your are drawing to a 'DeviceContext'. Effectively:

    • The paint event gives you the drawing context to perform your drawing.
    • You create a new context, and draw on that. Your 'graphics' are applied to the picturebox.
    • When the paint event completes, all your graphics you painted to the passed (paint event) context will be applied. Since you haven't drawn anything, the result is an 'empty' control.

    As noted, you should always perform drawing in the paint event using the passed graphics object.

    It isn't so much 'documenting' the behavior but understanding the objects that you are dealing with. To take a trivial example, it would be like documenting (somewhere!) that your house key doesn't work in your car: if one understands what 'keys' are, it would be fairly clear what the result would be when trying your house key in your car.

    To be fair, graphics are not 'trivial' and can be quite complex. This is why you will see the 'always draw in the paint event' comments, with very little explanation. 99.9% of the time, this will work, even for very complex scenarios. An in-depth understanding is not normally necessary, but a general understanding of how drawing works in .NET is required and will answer most questions.

    I create extremely complex (and trivial!) graphical applications and haven't found any reasons to not use the paint event. Actually, within a control, one would use the OnPaint method, rather than handle the paint event directly.


    Stephen J Whiteley

    Friday, June 29, 2012 6:50 PM
  • Hi John,

    here is a short summary how to paint in NET. Especially in a Picturebox:

    Usage of the Paint event. You can download my sample

    for more informations see:

    Overwritting OnPaint Method
    http://msdn.microsoft.com/de-de/library/cksxshce.aspx

    Control.OnPaint Method
    http://msdn.microsoft.com/de-de/library/system.windows.forms.control.onpaint.aspx

    Graphics Class
    http://msdn.microsoft.com/en-us/library/ac148eb3(v=vs.80)

    PaintEventArgs Class (System.Windows.Forms.PaintEventArgs)
    http://msdn.microsoft.com/en-us/library/system.windows.forms.painteventargs.aspx

    ------------

    I hope this helps

    regards Ellen


    Ich benutze/ I'm using VB2008 & VB2010





    Friday, June 29, 2012 7:16 PM

All replies

  • Inside the Paint event, use e.graphics, not picbox.Creategraphics.

    Armin

    Wednesday, June 27, 2012 4:07 AM
  • Thanks Armin,

    That works perfectly.

    Presumably during the PAINT event the PicBox has 2 drawing surfaces.

    (1) The new one that will be used on exit which is linked to via 'e'.
    and (2) the old one accessed via
    picBox.creategraphics which is active until replaced by the 'e' surface when PAINT exits.

    Seems like an obvious possibility when I think about it.
    Do you know where this is documented/described.

    Also, any explanation of why the graphics are  '90% persistent'?

    thanks again

    John

    Wednesday, June 27, 2012 5:19 AM
  • I don't think it's documented/described. Maybe somewhere I don't know of. Experience is the documentation in this case. ;)

    Persistence is due to Win7's DWM (desktop window manager). Windows are internally rendered into persistent targets so that the DWM can play with it (aero flip etc.). If you switch Aero (or one of these options, that I don't know how it's named) off, you should get the known behavior.


    Armin

    Wednesday, June 27, 2012 12:25 PM
  • Thanks again Armin,

    Thank you for taking the trouble to answer that.

    I like to have some idea of why things happen, and whether
    things are explained anywhere.

    Thanks

    John

    Wednesday, June 27, 2012 11:13 PM
  • The reason your graphics disappear is because you aren't drawing 'on' the control: your are drawing to a 'DeviceContext'. Effectively:

    • The paint event gives you the drawing context to perform your drawing.
    • You create a new context, and draw on that. Your 'graphics' are applied to the picturebox.
    • When the paint event completes, all your graphics you painted to the passed (paint event) context will be applied. Since you haven't drawn anything, the result is an 'empty' control.

    As noted, you should always perform drawing in the paint event using the passed graphics object.

    It isn't so much 'documenting' the behavior but understanding the objects that you are dealing with. To take a trivial example, it would be like documenting (somewhere!) that your house key doesn't work in your car: if one understands what 'keys' are, it would be fairly clear what the result would be when trying your house key in your car.

    To be fair, graphics are not 'trivial' and can be quite complex. This is why you will see the 'always draw in the paint event' comments, with very little explanation. 99.9% of the time, this will work, even for very complex scenarios. An in-depth understanding is not normally necessary, but a general understanding of how drawing works in .NET is required and will answer most questions.

    I create extremely complex (and trivial!) graphical applications and haven't found any reasons to not use the paint event. Actually, within a control, one would use the OnPaint method, rather than handle the paint event directly.


    Stephen J Whiteley

    Friday, June 29, 2012 6:50 PM
  • Hi John,

    here is a short summary how to paint in NET. Especially in a Picturebox:

    Usage of the Paint event. You can download my sample

    for more informations see:

    Overwritting OnPaint Method
    http://msdn.microsoft.com/de-de/library/cksxshce.aspx

    Control.OnPaint Method
    http://msdn.microsoft.com/de-de/library/system.windows.forms.control.onpaint.aspx

    Graphics Class
    http://msdn.microsoft.com/en-us/library/ac148eb3(v=vs.80)

    PaintEventArgs Class (System.Windows.Forms.PaintEventArgs)
    http://msdn.microsoft.com/en-us/library/system.windows.forms.painteventargs.aspx

    ------------

    I hope this helps

    regards Ellen


    Ich benutze/ I'm using VB2008 & VB2010





    Friday, June 29, 2012 7:16 PM
  • Thank you SJW,

    It is humbling to receive good and patient replies. All were helpful and yours particularly.

    I like your keys analogy.

    If you are busy, please read no further.

    Thanks
    John

    At the risk of boring you with details of my silly program....

    It is for my grandchildren, and includes a number of railway engines racing around tracks made up of square cells (a 30x40 grid).
    Using Timer controls, every 50 milliseconds or so (depending on speed settings) each engine's old cell is redrawn as empty track,
    and its new cell is redrawn with the engine (plus trailing cells when I add trucks behind the engines),.

    Also mouse clicks toggle cells between track, non-track and STOP point, to allow the kids to lay/change track layout,
    while the engines are zipping around. 

    All the cell and engine statuses are held in arrays, so to redraw the whole lot via paint-event is easy.

    But I only want to redraw a couple of cells each time, so being a VB6 programmer I was calling ReDrawCell(x,y) for the specific cells I wanted to redraw, and using the control's current drawing surface. When activated by Windows, the paint-event-routine called ReDrawCell for every cell, now using the new drawing surface.

    Trying to follow your advice, maybe ReDrawCell(x,y) needs to set a NeedsRedraw flag for cell x,y and then invalidate the cell's rectangle, and the paint-event-routine would then just redraw the flagged cell using ReallyDrawCell(x,y). Or the flag could be dropped and the paint-event-routine could simply work out which cells were in the invalidated rectangle - which it probably should be doing anyway.
    (So this has forced me to code the paint-event-routine properly.)

    I haven't had time to try coding that, but you might confirm I'm on the right track. 

    But, maybe either way is as good as the other. Both easy to understand. Both allow repaint when needed by Windows.
    Or is it really important to get rid of drawing outside the paint event, just as a matter of principal.

    best regards
    John

    Wednesday, July 11, 2012 4:49 PM