Canvas.Paint

From Xojo Documentation

Event


Canvas.Paint(g as Graphics, areas() As Realbasic.Rect)

Supported for all project types and targets.

The area needs to be redrawn, such as when it has been covered by another window and then uncovered. Use the g parameter for all drawing.The areas parameter contains the areas of the Canvas that need redrawing. If areas is empty then the entire Canvas needs to be redrawn.

Notes

fa-exclamation-circle-32.png
Directly accessing the Graphics property of the Canvas has been deprecated. Use this event instead.

The g parameter gives you access to the Graphics class methods for drawing. Use the Paint event handler for all drawing. You can also use a method called from the Paint event handler, but be sure to pass the Graphics object from the Paint event to your method.

You can continue to have code outside the Paint event handler draw directly to your own Picture properties. To display the Picture, simply draw it to the Canvas in the Paint event handler (using g.DrawPicture).

On Windows only, the EraseBackground property determines whether the entire Canvas background is erased before repainting.

Redrawing Areas

By redrawing just the specific areas that have changed, you can significantly improve your drawing performance. When you call Invalidate (specifying the rect to invalidate), the areas parameter contains the coordinates for the rectangles that need redrawing. You can then choose to redraw just those parts of the Graphics or you can continue to redraw everything as you have done in the past. This parameter may also contain coordinates that do not come directly from Invalidate calls as the operating system is ultimately in control of drawing.

When this event is called as a result of an Invalidate call, the drawing is clipped to only the invalidated regions regardless of whether you use the areas parameter.

Examples

This example draws a 3D rectangle with a raised look:

Sub Paint(g As Graphics)
Const White = &cffffff
Const DarkGray = &c8c8c8c
Const LightGray = &cefefef

g.ForeColor = White
g.DrawLine(1, 1, Me.Width, 1)
g.DrawLine(1, Me.Height - 1, 1, 1)
g.ForeColor = DarkGray
g.DrawLine(Me.Width - 1, 2, Me.Width - 1, Me.Height)
g.DrawLine(1, Me.Height - 1, Me.Width, Me.Height - 1)

//fill in the light gray rectangle
g.ForeColor = LightGray
g.FillRect(2, 2, Me.Width - 3, Me.Height - 3)

This example uses the Paint event handler of a Canvas control to draw the text "The quick brown fox" in Helvetica bold, italic, 18 point, 50 pixels from the top of and 10 pixels from the left side of the control:

Sub Paint(g As Graphics)
g.Bold = True
g.Italic = True
g.TextFont = "Helvetica"
g.TextSize = 18
g.DrawString("The quick brown fox", 10, 50)

This example assigns the color of a particular pixel in a Canvas control to a variable:

Sub Paint(g As Graphics)
Dim c As Color
c = g.Pixel(10, 10)

This example sets a particular pixel of a Canvas control to a specific RGB value:

Sub Paint(g As Graphics)
g.Pixel(10, 10) = RGB(100, 105, 225)

This is example draws a triangle in a Canvas. It is placed in the Paint event. The parameter g as Graphics is passed into this event:

Sub Paint(g As Graphics)
Dim points(6) As Integer
points(1) = 10 // X of Point 1
points(2) = 10 // Y of Point 1
points(3) = 75 // X of Point 2
points(4) = 30 // Y of Point 2
points(5) = 10 // X of Point 3
points(6) = 125 // Y of Point 3
g.ForeColor = RGB(100, 200, 255)

This example uses the Clip method to define child Graphics items within the parent Canvas. The code is in the Paint event of a Canvas. The two clippings define regions at the top of the canvas and the DrawOval method draws object in each one. Notice that the first call tries to draw an oval that is wider than the region. It is truncated in the drawing.

Sub Paint(g As Graphics)
Dim myClip As Graphics = g.Clip(0, 0, 150, 15)
Dim myClip2 As Graphics = g.Clip(150, 0, 150, 15)

// draw the border of the Canvas..
g.ForeColor = &c000000
g.DrawRect(0, 0, g.Width, g.Height)

//draw into the first area...
myClip.ForeColor = &cff0000
myClip.DrawRect(0, 0, myClip.Width, myClip.Height) // draw the border of the area..
myClip.DrawOval(0, 0, 200, 15) // the oval does not appear outside the region despite the call

//draw into the second area...
myClip2.ForeColor = &c0000ff
myClip2.DrawRect(0, 0, myClip2.Width, myClip2.Height) // draw the border of the area
myClip2.DrawOval(0, 0, 150, 15)

Creating a Custom Control

This simple Canvas control changes from black to white when you click on it.

Drag a Canvas control into a window. Add a Boolean property (mBlack) to the Window. This is used toggle the color of the Canvas when it is clicked.

The code for the Canvas MouseDown event handler looks like this:

Function MouseDown(X As Integer, Y As Integer) As Boolean
mBlack = Not mBlack // Toggle the color

Me.Invalidate(False) // Tell the Canvas to draw itself
End Function

This code simple toggles the mBlack value when the Canvas is clicked and then tells the Canvas to redraw itself.

In the Paint event handler, you draw the rectangle setting the color based on the value of mBlack:

Sub Paint(g As Graphics)
If mBlack Then
g.ForeColor = &c000000
Else
g.ForeColor = &cffffff
End If

g.FillRect(0, 0, g.Width, g.Height)

Optimization to draw only in the given areas

Add the following functions to a class or module:

Function IsWithinRect(left As Integer, top As Integer, width As Integer, height As Integer, rect As REALbasic.Rect) As Boolean
left = Max (left, rect.Left)
top = Max (top, rect.Top)
Dim right As Integer = Min(left + width, rect.Left + rect.Width)
Dim bottom As Integer = Min(top + height, rect.Top + rect.Height)

Return (left < right) And (top < bottom)
End Function

Function IsWithinRects(left As Integer, top As Integer, width As Integer, height As Integer, rects() As REALbasic.Rect) As Boolean
For Each r As REALbasic.Rect In rects
If IsWithinRect(left, top, width, height, r) Then
Return True
End If
Next
End Function

With that, you can test if an object you want to draw within a particular position needs drawing at all, possibly speeding up the drawing process:

Sub Paint(g As Graphics, areas() As REALbasic.Rect)
' Draw an image at position 100 / 100, but only if needed
If areas.Ubound < 0 Or IsWithinRects(100, 100, theImage.Width, theImage.Height, areas) Then
g.DrawPicture(theImage, 100, 100)
End If

See Also

Window.Paint event.