PainEventArgs

ALX

Well-known member
Joined
Nov 16, 2005
Messages
253
Location
Columbia, SC
Programming Experience
10+
In one form in my program, I have a handfull of controls, but I use a sub routine to paint the rest of the form. The sub that handles the paint event begins...
VB.NET:
    Private Sub Form1_Paint(ByVal sender As Object, ByVal pe As PaintEventArgs) Handles MyBase.Paint
I would like to call this routine from other subs within this form class, but I would need to match the arguments signature. I can handle the "sender" part, but I don't know how to come up with the "PaintEventsArgs" portion. Is there a way to get a reference to the graphics object that .NET passes to this sub or do I need to create a new graphics object and pass that as the PaintEventArgs ???
 
That is an event handler. Its purpose is to handle an event. It should not be called explicitly. If you have code you want to reuse then put it in its own method. You can then call that method from the event handler or anywhere else. That's how methods work.
 
As Jmcilhinney has stated you shouldn't be calling this method directly but there's no reason why you cant pass the painteventargs to another rountine that you can call i.e

VB.NET:
Private Sub Form1_Paint(ByVal sender As Object, ByVal pe As PaintEventArgs) Handles MyBase.Paint   
 
Call DoMyPainting(pe)
 
end sub

VB.NET:
Sub DoMyPainting(Byval PaintArgs as painteventargs)
end sub
 
OK... I should have known that I could not call the event handler directly. So now I will set up a sub to handle the business of painting the form...
VB.NET:
[SIZE=2][COLOR=#0000ff]Private[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Sub[/COLOR][/SIZE][SIZE=2] Paint_This_Form1([/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] pe [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] PaintEventArgs)[/SIZE]
[SIZE=2][SIZE=2]pe.Graphics.FillRectangle(BKBrush, [/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] Rectangle(X, Y, 168, 400))
[/SIZE][/SIZE][SIZE=2][COLOR=#008000]'...and so on ...
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Sub
[/COLOR][/SIZE]
... and call it from the event handler...
VB.NET:
[SIZE=2][COLOR=#0000ff]Private[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Sub[/COLOR][/SIZE][SIZE=2] Form1_Paint([/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] sender [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Object[/COLOR][/SIZE][SIZE=2], [/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] pe [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] PaintEventArgs) [/SIZE][SIZE=2][COLOR=#0000ff]Handles[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]MyBase[/COLOR][/SIZE][SIZE=2].Paint
    Paint_This_Form1(pe)
'...
[SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Sub
[/COLOR][/SIZE][/SIZE]
I now face the same question, just one step removed. I will need a PaintEventArgs argument for any other sub in this class that needs to call Paint_This_Form1(ByVal pe As PaintEventArgs).

VB.NET:
Private Sub Aux_Sub1 ()
    Paint_This_Form1([COLOR=green]--how can I get "pe" here ?--[/COLOR])
End Sub
Since .NET passes a graphics object in "pe" when it calls my event handler, my first instinct is to use it (if I could get a reference to it) rather than create a new graphics object to do the painting. It seems wasteful to create another graphics object when NET has already created one for this purpose, but my main concern is to do this properly.
 
Last edited:
Now I understand the issue. What you should be doing is first off telling the form how to paint itself by putting all the required code in the Paint event handler. Now you know that whenever the form gets painted it will be done as you wish. Now, when you want that code executed you don't worry about calling that method. You just tell the form to repaint itself by calling Refresh. That will raise a paint event and thus the Paint event handler will be executed.
 
Here is the method to my madness...
Originally, I did things that way, only I used "Me.Invalidate()" to force a repaint of the form. My program runs a recursive loop through a cycle that recalculates values used in the paint event. Every time the sequence encounters a "Me.Invalidate()" method, it first clears the screen, and then repaints it. When the sequence changes rapidly, it causes the display to flash rapidly each time the screen is cleared and updated, making it difficult (actually irritating) to watch. My plan was to repaint the form directly on top of the pre-existing data and avoid the screen clearing that "Me.Invalidate()" causes.
 
The PaintEventArgs class is, as the name suggests, supposed to be used in a Paint event handler. In that Paint event handler, what do you do to draw on the control? You use the Graphics property of the PaintEventArgs object. It is the Graphics object that is important, not the PaintEventArgs object. You can create a Graphics object for a control wherever and whenever you like, simply by calling its CreateGraphics method. You can then use that object to do whatever drawing you like and then Dispose it. Just remember though, that any drawing done outside of the Paint event handler will disappear next time the control is repainted.

There are also techniques you can use to reduce flicker when repainting objects. I'm no GDI+ guru so I won't claim to know much about it, but perahps you should look into what can be done on that front, like double-buffering.
 
To reduce the flicker when your repainting an object put the following inside the forms constructor...

VB.NET:
SetStyle(ControlStyles.AllPaintingInWMPaint,true)
' Intercepts the WM_EraseBackGorund. Be advised though this command plays havoc with the 
transparency key property, and unless you use the graphics object supplied by 
the painteventargs argument in the event handler it won't work.
SetStyle(ControlStyles.DoubleBuffer,true)
'Microsofts Built in shortcut for off screen Painting
SetStyle(ControlStyles.UserPaint,true)
'Tells Windows that the control will be painting its self rather than the operating system doing it.
 
Back
Top