You want to activate the Paint event for a form or control to cause its graphics to refresh.
Sample code folder: Chapter 09\Invalidating
It's best to let the operating system handle exactly when any object should repaint itself. In Visual Basic 2005, this means it's best to draw in an object's Paint event and not to worry about when to activate the painting. However, there are times when you want to control when graphics are redrawn, such as for simple animations, when data values in the program change, or when other events happen that affect the image. In these cases, you can call the Refresh() method of the object to be refreshed, or you can call the Invalidate() method to do much the same thing. The operating system handles the rest of the details.
The demonstration code shown here draws a five-pointed star centered on the mouse cursor. As the mouse moves around on the form, the star moves with it, which means each mouse-move event should trigger a form Paint event. You accomplish this by invalidating the form with each move of the mouse. You can also use the Refresh() method.
Create a new Windows Forms application, and add the following code to the form's class template:
' ----- Keep track of the mouse position. Private MouseX As Integer Private MouseY As Integer Private Sub Form1_MouseMove(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles Me.MouseMove ' ----- Record the mouse position. MouseX = e.X MouseY = e.Y ' ----- Mark the form for redrawing. Me.Invalidate() ' ----- If you want to update the form quicker, ' call Refresh() instead of Invalidate(). 'Me.Refresh() End Sub
The form's Paint event grabs the form's Graphics object to provide the surface to draw on, then creates an array of points defining the five points of the star, centered around the current position of the mouse:
Private Sub Form1_Paint(ByVal sender As Object, _ ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles Me.Paint ' ----- Refresh the form display. Dim canvas As Graphics = e.Graphics Dim starPoints(4) As Point Dim angle As Double Dim radians As Double Dim pointX As Double Dim pointY As Double Dim counter As Integer Const pointDistance As Double = 50 Const angleStart As Integer = 198 Const angleRotation As Integer = 144 ' ----- Calculate each of the star's points. angle = angleStart For counter = 0 To 4 angle += angleRotation radians = angle * Math.PI / 180 pointX = Math.Cos(radians) * pointDistance + MouseX pointY = Math.Sin(radians) * pointDistance + MouseY starPoints(counter) = New Point(CInt(pointX), _ CInt(pointY)) Next counter ' ----- Draw the star. I've provided a few alternatives. canvas.FillPolygon(Brushes.DarkRed, starPoints, _ Drawing2D.FillMode.Alternate) 'canvas.FillPolygon(Brushes.DarkRed, starPoints, _ ' Drawing2D.FillMode.Winding) 'canvas.DrawPolygon(Pens.DarkRed, starPoints) End Sub
There are several ways to draw or solid-fill a polygon such as this five-pointed star. The last three statements in the code let you experiment with three different techniques. The algorithm used to fill the center of a polygon can either end up with alternating areas filled, or not. Figure 9-13 shows the results of filling using Drawing2D.FillMode.Alternate. The Drawing2D.FillMode.Winding mode causes the star to be completely filled in, including the center area.
Figure 9-13. As the mouse moves the form is invalidated, causing the star to move with the cursor
The Invalidate() method does not force an immediate refresh of the form. Instead, it puts in a request for a redraw the next time the system is not too busy. Windows considers screen updates low-priority tasks, so if your system is busy doing other things, the screen changes will be postponed. If you want the changes to occur immediately, follow the Invalidate() method call with a call to the form's (or, if you are drawing on a control, the control's) Update() method:
The Refresh() method combines both lines into one method call. So why would you call Invalidate() when the more powerful Refresh() method is available? Invalidate() accepts arguments that let you narrow down the size of the area to redraw. Redrawing the entire form can be a slow process, especially if you have to do it often. By passing a Rectangle or Region object to Invalidate(), you can tell Windows, "Redraw only in this limited area."