Drawing Rectangles - Simple Animation


There are three rectangle drawing functions provided by the operating system:

Rectangles, as defined in the class irectangle, are upright rectangles. A rectangle consists of the two points - denoted by a and b within the class. When unit::pixel is in effect, a is the upper-left corner of the rectangle and b is the lower-right corner of the rectangle. Different unit modes and values for the corners may alter this.

Random Rectangle - Peeking and Reading Messages from the Queue

The program of this section demonstrates a simple form of animating graphics. A "still shot" of the output of the program is shown below.

The program is "animated". Displaying an animated diagram is not as simple as using a for loop whilst processing the message message::paint. Proceeding in that manner would cause the program to 'hang' in the drawing process, rendering it incapable of responding to other messages (such as message::size or message::close). Typically, when animating graphics, timers are used. However, rather than use a timer, this program alters the message loop - as shown in the code fragment below. This yields animation based on the performance of the computer rather than restrict the animation to periodic intervals.

for(;;)
 {
  if (peek_message(&queue_message,null,0,0,peek::remove))
   {
    if (queue_message.message == message::quit) break;
    translate_message(&queue_message);
    dispatch_message(&queue_message);
   }
  else
   draw_random_rectangle(window_handle);
 }

Message Loops

The above logic consists of an infinite for loop used to peek at messages. In a normal message loop, messages are read rather than being peeked. A 'normal' C message loop is shown below.

queue queue_message;
while (get_message(&queue_message))
 {
  translate_message(&queue_message);
  dispatch_message(&queue_message);
 }

When a message is read, the operating system does not return until a message is available. That is, the calling thread is blocked until a message is received. The default values for the parameters of get_message ensure that no message identity filtering and no window handle filtering takes place. The normal message loop is exited upon receiving the message message::quit. Neither peeking nor reading removes paint messages from the queue. The only way to do that is to call one of the functions:

Peeking is capable of removing messages or leaving them in the queue - depending upon the options in effect. For the program at hand, when no message is available, a random rectangle is drawn. This yields drawing at the maximum rate - that is, whenever the queue is empty and clock cycles are available. When a message is available, if it is message::quit, a break statement is used to break the infinite for loop and end the program; otherwise, the message is translated and dispatched as normal.

The code used to draw a random rectangle is shown below.

void draw_random_rectangle(handle window_handle)
{
 if (width_of_client==0 || height_of_client==0) return;

 rectangle draw_rectangle(rand() % width_of_client,
                          rand() % height_of_client,
                          rand() % width_of_client,
                          rand() % height_of_client);

 handle brush_handle = create_solid_brush(red_green_blue(rand() % 256,
                                                         rand() % 256,
                                                         rand() % 256));

 handle device_context = get_device_context(window_handle);

 fill_rectangle(device_context,&draw_rectangle,brush_handle);

 release_device_context(window_handle,device_context);

 delete_object(brush_handle);
}

The C runtime function rand (short for random) is used to randomize the width and height of the rectangle to be drawn. Similarly, rand is used to randomize the red, green and blue values of the brush used to draw the rectangle. Note that the client window procedure does not even intercept the paint message.