Chapter 7
Working with graphics and multimedia

Graphics and multimedia elements can add polish to your applications. Delphi offers a variety of ways to introduce these features into your application. To add graphical elements, you can insert pre-drawn pictures at design time, create them using graphical controls at design time, or draw them dynamically at runtime. To add multimedia capabilities, Delphi includes special components that can play audio and video clips.

Overview of graphics programming

The VCL graphics components encapsulate the Windows Graphics Device Interface (GDI), making it very easy to add graphics to your Windows programming.

To draw graphics in a Delphi application, you draw on an object's canvas, rather than directly on the object. The canvas is a property of the object, and is itself an object. A main advantage of the canvas object is that it handles resources effectively and it takes care of device context, so your programs can use the same methods regardless of whether you are drawing on the screen, to a printer, or on bitmaps or metafiles. Canvases are available only at runtime, so you do all your work with canvases by writing code.

Note: Since TCanvas is a wrapper resource manager around the Windows device context, you can also use all Windows GDI functions on the canvas. The Handle property of the canvas is the device context Handle.

How graphic images appear in your application depends on the type of object whose canvas you draw on. If you are drawing directly onto the canvas of a control, the picture is displayed immediately. However, if you draw on an offscreen image such as a TBitmap canvas, the image is not displayed until a control copies from the bitmap onto the control's canvas. That is, when drawing bitmaps and assigning them to an image control, the image appears only when the control has an opportunity to process its OnPaint message.

When working with graphics, you often encounter the terms drawing and painting:

The examples in the beginning of this chapter demonstrate how to draw various graphics, but they do so in response to OnPaint events. Later sections show how to do the same kind of drawing in response to other events.

Refreshing the screen

At certain times, Windows determines that objects onscreen need to refresh their appearance, so it generates WM_PAINT messages, which the VCL routes to OnPaint events. The VCL calls any OnPaint event handler that you have written for that object when you use the Refresh method. The default name generated for the OnPaint event handler in a form is FormPaint. You may want to use the Refresh method at times to refresh a component or form. For example, you might call Refresh in the form's OnResize event handler to redisplay any graphics or if you want to paint a background on a form.

While some operating systems automatically handle the redrawing of the client area of a window that has been invalidated, Windows does not. In the Windows operating system anything drawn on the screen is permanent. When a form or control is temporarily obscured, for example during window dragging, the form or control must repaint the obscured area when it is re-exposed. For more information about the WM_PAINT message, see the Windows online Help.

If you use the TImage control, the painting and refreshing of the graphic contained in the TImage is handled automatically by the VCL. Drawing on a TImage creates a persistent image. Consequently, you do not need to do anything to redraw the contained image. In contrast, TPaintBox's canvas maps directly onto the screen device, so that anything drawn to the PaintBox's canvas is transitory. This is true of nearly all controls, including the form itself. Therefore, if you draw or paint on a TPaintBox in its constructor, you will need to add that code to your OnPaint event handler in order for image to be repainted each time the client area is invalidated.

Types of graphic objects

The VCL provides the graphic objects shown in Table 7.1. These objects have methods to draw on the canvas, which are described in "Using Canvas methods to draw graphic objects" and to load and save to graphics files, as described in "Loading and saving graphics files".

Table 7.1   Graphic object types

Object

Description

Picture

Used to hold any graphic image. To add additional graphic file formats, use the Picture Register method. Use this to handle arbitrary files such as displaying images in an image control.

Bitmap

A powerful graphics object used to create, manipulate (scale, scroll, rotate, and paint), and store images as files on a disk. Creating copies of a bitmap is fast since the handle is copied, not the image.

Clipboard

Represents the container for any text or graphics that are cut, copied, or pasted from or to an application. With the clipboard, you can get and retrieve data according to the appropriate format; handle reference counting, and opening and closing the Clipboard; manage and manipulate formats for objects in the Clipboard.

Icon

Represents the value loaded from a Windows icon file (::ICO file).

Metafile

Contains a metafile, which records the operations required to construct an image, rather than contain the actual bitmap pixels of the image. Metafiles are extremely scalable without the loss of image detail and often require much less memory than bitmaps, particularly for high-resolution devices, such as printers. However, metafiles do not draw as fast as bitmaps. Use a metafile when versatility or precision is more important than performance.

Common properties and methods of Canvas

Table 7.2 lists the commonly used properties of the Canvas object. For a complete list of properties and methods, see the TCanvas component in online Help.

Table 7.2   Common properties of the Canvas object

Properties

Descriptions

Font

Specifies the font to use when writing text on the image. Set the properties of the TFont object to specify the font face, color, size, and style of the font.

Brush

Determines the color and pattern the canvas uses for filling graphical shapes and backgrounds. Set the properties of the TBrush object to specify the color and pattern or bitmap to use when filling in spaces on the canvas.

Pen

Specifies the kind of pen the canvas uses for drawing lines and outlining shapes. Set the properties of the TPen object to specify the color, style, width, and mode of the pen.

PenPos

Specifies the current drawing position of the pen.

Pixels

Specifies the color of the area of pixels within the current ClipRect.

These properties are described in more detail in "Using the properties of the Canvas object".

Table 7.3 is a list of several methods you can use:

Table 7.3   Common methods of the Canvas object

Method

Descriptions

Arc

Draws an arc on the image along the perimeter of the ellipse bounded by the specified rectangle.

Chord

Draws a closed figure represented by the intersection of a line and an ellipse.

CopyRect

Copies part of an image from another canvas into the canvas.

Draw

Renders the graphic object specified by the Graphic parameter on the canvas at the location given by the coordinates (X, Y).

Ellipse

Draws the ellipse defined by a bounding rectangle on the canvas.

FillRect

Fills the specified rectangle on the canvas using the current brush.

FloodFill

Fills an area of the canvas using the current brush.

FrameRect

Draws a rectangle using the Brush of the canvas to draw the border.

LineTo

Draws a line on the canvas from PenPos to the point specified by X and Y, and sets the pen position to (X, Y).

MoveTo

Changes the current drawing position to the point (X,Y).

Pie

Draws a pie-shaped the section of the ellipse bounded by the rectangle (X1, Y1) and (X2, Y2) on the canvas.

Polygon

Draws a series of lines on the canvas connecting the points passed in and closing the shape by drawing a line from the last point to the first point.

PolyLine

Draws a series of lines on the canvas with the current pen, connecting each of the points passed to it in Points.

Rectangle

Draws a rectangle on the canvas with its upper left corner at the point (X1, Y1) and its lower right corner at the point (X2, Y2). Use Rectangle to draw a box using Pen and fill it using Brush.

RoundRect

Draws a rectangle with rounded corners on the canvas.

StretchDraw

Draws a graphic on the canvas so that the image fits in the specified rectangle. The graphic image may need to change its magnitude or aspect ratio to fit.

TextHeight, TextWidth

Returns the height and width, respectively, of a string in the current font. Height includes leading between lines.

TextOut

Writes a string on the canvas, starting at the point (X,Y), and then updates the PenPos to the end of the string.

TextRect

Writes a string inside a region; any portions of the string that fall outside the region do not appear.

These methods are described in more detail in "Using Canvas methods to draw graphic objects".

Using the properties of the Canvas object

With the Canvas object, you can set the properties of a pen for drawing lines, a brush for filling shapes, a font for writing text, and an array of pixels to represent the image.

This section describes

Using pens

The Pen property of a canvas controls the way lines appear, including lines drawn as the outlines of shapes. Drawing a straight line is really just changing a group of pixels that lie between two points.

The pen itself has four properties you can change: Color, Width, Style, and Mode.

The values of these properties determine how the pen changes the pixels in the line. By default, every pen starts out black, with a width of 1 pixel, a solid style, and a mode called copy that overwrites anything already on the canvas.

Changing the pen color

You can set the color of a pen as you would any other Color property at runtime. A pen's color determines the color of the lines the pen draws, including lines drawn as the boundaries of shapes, as well as other lines and polylines. To change the pen color, assign a value to the Color property of the pen.

To let the user choose a new color for the pen, put a color grid on the pen's toolbar. A color grid can set both foreground and background colors. For a non-grid pen style, you must consider the background color, which is drawn in the gaps between line segments. Background color comes from the Brush color property.

Since the user chooses a new color by clicking the grid, this code changes the pen's color in response to the OnClick event:

procedure TForm1.PenColorClick(Sender: TObject);
begin
  Canvas.Pen.Color := PenColor.ForegroundColor;
end;

Changing the pen width

A pen's width determines the thickness, in pixels, of the lines it draws.

Note: When the thickness is greater than 1, Windows 95 always draw solid lines, no matter what the value of the pen's Style property.

To change the pen width, assign a numeric value to the pen's Width property.

Suppose you have a scroll bar on the pen's toolbar to set width values for the pen. And suppose you want to update the label next to the scroll bar to provide feedback to the user. Using the scroll bar's position to determine the pen width, you update the pen width every time the position changes.

This is how to handle the scroll bar's OnChange event:

procedure TForm1.PenWidthChange(Sender: TObject);
begin
  Canvas.Pen.Width := PenWidth.Position;  { set the pen width directly }
 PenSize.Caption := IntToStr(PenWidth.Position);  { convert to string for caption }
end;

Changing the pen style

A pen's Style property allows you to set solid lines, dashed lines, dotted lines, and so on.

Note: Windows 95 does not support dashed or dotted line styles for pens wider than one pixel and makes all larger pens solid, no matter what style you specify.

The task of setting the properties of pen is an ideal case for having different controls share same event handler to handle events. To determine which control actually got the event, you check the Sender parameter.

To create one click-event handler for six pen-style buttons on a pen's toolbar, do the following:

  1. Select all six pen-style buttons and select the Object Inspector|Events|OnClick event and in the Handler column, type SetPenStyle.

    Delphi generates an empty click-event handler called SetPenStyle and attaches it to the OnClick events of all six buttons.

  2. Fill in the click-event handler by setting the pen's style depending on the value of Sender, which is the control that sent the click event:
    procedure TForm1.SetPenStyle(Sender: TObject);
    begin
      with Canvas.Pen do
      begin
        if Sender = SolidPen then Style := psSolid
       else if Sender = DashPen then Style := psDash
       else if Sender = DotPen then Style := psDot
       else if Sender = DashDotPen then Style := psDashDot
       else if Sender = DashDotDotPen then Style := psDashDotDot
       else if Sender = ClearPen then Style := psClear;
      end;
    end;
    

Changing the pen mode

A pen's Mode property lets you specify various ways to combine the pen's color with the color on the canvas. For example, the pen could always be black, be an inverse of the canvas background color, inverse of the pen color, and so on. See TPen in online Help for details.

Getting the pen position

The current drawing position--the position from which the pen begins drawing its next line--is called the pen position. The canvas stores its pen position in its PenPos property. Pen position affects the drawing of lines only; for shapes and text, you specify all the coordinates you need.

To set the pen position, call the MoveTo method of the canvas. For example, the following code moves the pen position to the upper left corner of the canvas:

Canvas.MoveTo(0, 0);

Note: Drawing a line with the LineTo method also moves the current position to the endpoint of the line.

Using brushes

The Brush property of a canvas controls the way you fill areas, including the interior of shapes. Filling an area with a brush is a way of changing a large number of adjacent pixels in a specified way.

The brush has three properties you can manipulate:

The values of these properties determine the way the canvas fills shapes or other areas. By default, every brush starts out white, with a solid style and no pattern bitmap.

Changing the brush color

A brush's color determines what color the canvas uses to fill shapes. To change the fill color, assign a value to the brush's Color property. Brush is used for background color in text and line drawing so you typically set the background color property.

You can set the brush color just as you do the pen color, in response to a click on a color grid on the brush's toolbar (see "Changing the pen color"):

procedure TForm1.BrushColorClick(Sender: TObject);
begin
  Canvas.Brush.Color := BrushColor.ForegroundColor;
end;

Changing the brush style

A brush style determines what pattern the canvas uses to fill shapes. It lets you specify various ways to combine the brush's color with any colors already on the canvas. The predefined styles include solid color, no color, and various line and hatch patterns.

To change the style of a brush, set its Style property to one of the predefined values: bsSolid, bsClear, bsHorizontal, bsVertical, bsFDiagonal, bsBDiagonal, bsCross, or bsDiagCross.

This example sets brush styles by sharing a click-event handler for a set of eight brush-style buttons. All eight buttons are selected, the Object Inspector|Events|OnClick is set, and the OnClick handler is named SetBrushStyle. Here is the handler code:

procedure TForm1.SetBrushStyle(Sender: TObject);
begin
  with Canvas.Brush do
  begin
    if Sender = SolidBrush then Style := bsSolid
   else if Sender = ClearBrush then Style := bsClear
   else if Sender = HorizontalBrush then Style := bsHorizontal
   else if Sender = VerticalBrush then Style := bsVertical
   else if Sender = FDiagonalBrush then Style := bsFDiagonal
   else if Sender = BDiagonalBrush then Style := bsBDiagonal
   else if Sender = CrossBrush then Style := bsCross
   else if Sender = DiagCrossBrush then Style := bsDiagCross;
  end;
end;

Setting the Brush Bitmap property

A brush's Bitmap property lets you specify a bitmap image for the brush to use as a pattern for filling shapes and other areas.

The following example loads a bitmap from a file and assigns it to the Brush of the Canvas of Form1:

var
  Bitmap: TBitmap;
begin
  Bitmap := TBitmap.Create;
  try
    Bitmap.LoadFromFile('MyBitmap.bmp');
    Form1.Canvas.Brush.Bitmap := Bitmap;
    Form1.Canvas.FillRect(Rect(0,0,100,100));
  finally
    Form1.Canvas.Brush.Bitmap := nil;
    Bitmap.Free;
  end;
end;

Note: The brush does not assume ownership of a bitmap object assigned to its Bitmap property. You must ensure that the Bitmap object remain valid for the lifetime of the Brush, and you must free the Bitmap object yourself afterwards.

Reading and setting pixels

You will notice that every canvas has an indexed Pixels property that represents the individual colored points that make up the image on the canvas. You rarely need to access Pixels directly, it is available only for convenience to perform small actions such as finding or setting a pixel's color.

Note: Setting and getting individual pixels is thousands of times slower than performing graphics operations on regions. Do not use the Pixel array property to access the image pixels of a general array. For high-performance access to image pixels, see the TBitmap.ScanLine property.

Using Canvas methods to draw graphic objects

This section shows how to use some common methods to draw graphic objects. It covers:

Drawing lines and polylines

A canvas can draw straight lines and polylines. A straight line is just a line of pixels connecting two points. A polyline is a series of straight lines, connected end-to-end. The canvas draws all lines using its pen.

Drawing lines

To draw a straight line on a canvas, use the LineTo method of the canvas.

LineTo draws a line from the current pen position to the point you specify and makes the endpoint of the line the current position. The canvas draws the line using its pen.

For example, the following method draws crossed diagonal lines across a form whenever the form is painted:

procedure TForm1.FormPaint(Sender: TObject);
begin
 with Canvas do
 begin
   MoveTo(0, 0);
   LineTo(ClientWidth, ClientHeight);
   MoveTo(0, ClientHeight);
   LineTo(ClientWidth, 0);
 end;
end;

Drawing polylines

In addition to individual lines, the canvas can also draw polylines, which are groups of any number of connected line segments.

To draw a polyline on a canvas, call the Polyline method of the canvas.

The parameter passed to the PolyLine method is an array of points. You can think of a polyline as performing a MoveTo on the first point and LineTo on each successive point. For drawing multiple lines, Polyline is faster than using the MoveTo method and the LineTo method because it eliminates a lot of call overhead.

The following method, for example, draws a rhombus in a form:

procedure TForm1.FormPaint(Sender: TObject);
begin
 with Canvas do
   PolyLine([Point(0, 0), Point(50, 0), Point(75, 50), Point(25, 50), Point(0, 0)]);
end;

This example takes advantage of Delphi's ability to create an open-array parameter on-the-fly. You can pass any array of points, but an easy way to construct an array quickly is to put its elements in brackets and pass the whole thing as a parameter. For more information, see online Help.

Drawing shapes

Canvases have methods for drawing different kinds of shapes. The canvas draws the outline of a shape with its pen, then fills the interior with its brush. The line that forms the border for the shape is controlled by the current Pen object.

This section covers:

Drawing rectangles and ellipses

To draw a rectangle or ellipse on a canvas, call the canvas's Rectangle method or Ellipse method, passing the coordinates of a bounding rectangle.

The Rectangle method draws the bounding rectangle; Ellipse draws an ellipse that touches all sides of the rectangle.

The following method draws a rectangle filling a form's upper left quadrant, then draws an ellipse in the same area:

procedure TForm1.FormPaint(Sender: TObject);
begin
 Canvas.Rectangle(0, 0, ClientWidth div 2, ClientHeight div 2);
 Canvas.Ellipse(0, 0, ClientWidth div 2, ClientHeight div 2);
end;

Drawing rounded rectangles

To draw a rounded rectangle on a canvas, call the canvas's RoundRect method.

The first four parameters passed to RoundRect are a bounding rectangle, just as for the Rectangle method or the Ellipse method. RoundRect takes two more parameters that indicate how to draw the rounded corners.

The following method, for example, draws a rounded rectangle in a form's upper left quadrant, rounding the corners as sections of a circle with a diameter of 10 pixels:

procedure TForm1.FormPaint(Sender: TObject);
begin
 Canvas.RoundRect(0, 0, ClientWidth div 2, ClientHeight div 2, 10, 10);
end;

Drawing polygons

To draw a polygon with any number of sides on a canvas, call the Polygon method of the canvas.

Polygon takes an array of points as its only parameter and connects the points with the pen, then connects the last point to the first to close the polygon. After drawing the lines, Polygon uses the brush to fill the area inside the polygon.

For example, the following code draws a right triangle in the lower left half of a form:

procedure TForm1.FormPaint(Sender: TObject);
begin
 Canvas.Polygon([Point(0, 0), Point(0, ClientHeight),
   Point(ClientWidth, ClientHeight)]);
end;

Handling multiple drawing objects in your application

Various drawing methods (rectangle, shape, line, and so on) are typically available on the toolbar and button panel. Applications can respond to clicks on speed buttons to set the desired drawing objects. This section describes how to:

Keeping track of which drawing tool to use

A graphics program needs to keep track of what kind of drawing tool (such as a line, rectangle, ellipse, or rounded rectangle) a user might want to use at any given time. You could assign numbers to each kind of tool, but then you would have to remember what each number stands for. You can do that more easily by assigning mnemonic constant names to each number, but your code won't be able to distinguish which numbers are in the proper range and of the right type. Fortunately, Object Pascal provides a means to handle both of these shortcomings. You can declare an enumerated type.

An enumerated type is really just a shorthand way of assigning sequential values to constants. Since it's also a type declaration, you can use Object Pascal's type-checking to ensure that you assign only those specific values.

To declare an enumerated type, use the reserved work type, followed by an identifier for the type, then an equal sign, and the identifiers for the values in the type in parentheses, separated by commas.

For example, the following code declares an enumerated type for each drawing tool available in a graphics application:

type
  TDrawingTool = (dtLine, dtRectangle, dtEllipse, dtRoundRect);

By convention, type identifiers begin with the letter T, and groups of similar constants (such as those making up an enumerated type) begin with a 2-letter prefix (such as dt for "drawing tool").

The declaration of the TDrawingTool type is equivalent to declaring a group of constants:

const
  dtLine = 0;
 dtRectangle = 1;
 dtEllipse = 2;
  dtRoundRect = 3;

The main difference is that by declaring the enumerated type, you give the constants not just a value, but also a type, which enables you to use Object Pascal's type-checking to prevent many errors. A variable of type TDrawingTool can be assigned only one of the constants dtLine..dtRoundRect. Attempting to assign some other number (even one in the range 0..3) generates a compile-time error.

In the following code, a field added to a form keeps track of the form's drawing tool:

type
  TDrawingTool = (dtLine, dtRectangle, dtEllipse, dtRoundRect);
 TForm1 = class(TForm)
    ...  { method declarations }
 public
    Drawing: Boolean;
   Origin, MovePt: TPoint;
   DrawingTool: TDrawingTool;  { field to hold current tool }
  end;

Changing the tool with speed buttons

Each drawing tool needs an associated OnClick event handler. Suppose your application had a toolbar button for each of four drawing tools: line, rectangle, ellipse, and rounded rectangle. You would attach the following event handlers to the OnClick events of the four drawing-tool buttons, setting DrawingTool to the appropriate value for each:

procedure TForm1.LineButtonClick(Sender: TObject);  { LineButton }
begin
  DrawingTool := dtLine;
end;

procedure TForm1.RectangleButtonClick(Sender: TObject);  { RectangleButton }
begin
  DrawingTool := dtRectangle;
end;

procedure TForm1.EllipseButtonClick(Sender: TObject);  { EllipseButton }
begin
  DrawingTool := dtEllipse;
end;

procedure TForm1.RoundedRectButtonClick(Sender: TObject);  { RoundRectButton }
begin
  DrawingTool := dtRoundRect;
end;

Using drawing tools

Now that you can tell what tool to use, you must indicate how to draw the different shapes. The only methods that perform any drawing are the mouse-move and mouse-up handlers, and the only drawing code draws lines, no matter what tool is selected.

To use different drawing tools, your code needs to specify how to draw, based on the selected tool. You add this instruction to each tool's event handler.

This section describes

Drawing shapes

Drawing shapes is just as easy as drawing lines: Each one takes a single statement; you just need the coordinates.

Here's a rewrite of the OnMouseUp event handler that draws shapes for all four tools:

procedure TForm1.FormMouseUp(Sender: TObject);
begin
  case DrawingTool of
    dtLine: 
      begin
        Canvas.MoveTo(Origin.X, Origin.Y);
       Canvas.LineTo(X, Y)
      end;
   dtRectangle: Canvas.Rectangle(Origin.X, Origin.Y, X, Y);
   dtEllipse: Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
   dtRoundRect: Canvas.RoundRect(Origin.X, Origin.Y, X, Y,
                   (Origin.X - X) div 2, (Origin.Y - Y) div 2);
  end;
 Drawing := False;
end;

Of course, you also need to update the OnMouseMove handler to draw shapes:

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  if Drawing then
  begin
    Canvas.Pen.Mode := pmNotXor;
   case DrawingTool of
      dtLine: begin
                Canvas.MoveTo(Origin.X, Origin.Y);
               Canvas.LineTo(MovePt.X, MovePt.Y);
               Canvas.MoveTo(Origin.X, Origin.Y);
               Canvas.LineTo(X, Y);
              end;
     dtRectangle: begin
                      Canvas.Rectangle(Origin.X, Origin.Y, MovePt.X, MovePt.Y);
                     Canvas.Rectangle(Origin.X, Origin.Y, X, Y);
                   end;
     dtEllipse: begin
                    Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
                   Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
                  end;
     dtRoundRect: begin
                     Canvas.RoundRect(Origin.X, Origin.Y, X, Y,
                       (Origin.X - X) div 2, (Origin.Y - Y) div 2);
                    Canvas.RoundRect(Origin.X, Origin.Y, X, Y,
                       (Origin.X - X) div 2, (Origin.Y - Y) div 2);
                   end;
    end;
   MovePt := Point(X, Y);
  end;
 Canvas.Pen.Mode := pmCopy;
end;

Typically, all the repetitious code that is in the above example would be in a separate routine. The next section shows all the shape-drawing code in a single routine that all mouse-event handlers can call.

Sharing code among event handlers

Any time you find that many your event handlers use the same code, you can make your application more efficient by moving the repeated code into a routine that all event handlers can share.

To add a method to a form,

  1. Add the method declaration to the form object.

    You can add the declaration in either the public or private parts at the end of the form object's declaration. If the code is just sharing the details of handling some events, it's probably safest to make the shared method private.

  2. Write the method implementation in the implementation part of the form unit.

The header for the method implementation must match the declaration exactly, with the same parameters in the same order.

The following code adds a method to the form called DrawShape and calls it from each of the handlers. First, the declaration of DrawShape is added to the form object's declaration:

type
  TForm1 = class(TForm)
    ...  { fields and methods declared here}
 public
    { Public declarations }
   procedure DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode);
  end;

Then, the implementation of DrawShape is written in the implementation part of the unit:

implementation
{$R *.FRM}
...  { other method implementations omitted for brevity }
procedure TForm1.DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode);
begin
  with Canvas do
  begin
    Pen.Mode := AMode;
   case DrawingTool of 
      dtLine:
        begin
          MoveTo(TopLeft.X, TopLeft.Y);
         LineTo(BottomRight.X, BottomRight.Y);
        end;
     dtRectangle: Rectangle(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
     dtEllipse: Ellipse(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
     dtRoundRect: RoundRect(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y,
        (TopLeft.X - BottomRight.X) div 2, (TopLeft.Y - BottomRight.Y) div 2);
    end;
  end;
end;

The other event handlers are modified to call DrawShape.

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  DrawShape(Origin, Point(X, Y), pmCopy);  { draw the final shape }
 Drawing := False;
end;
procedure TForm1.FormMouseMove(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Drawing then
  begin
    DrawShape(Origin, MovePt, pmNotXor);  { erase the previous shape }
   MovePt := Point(X, Y);  { record the current point }
   DrawShape(Origin, MovePt, pmNotXor);  { draw the current shape }
  end;
end;

Drawing on a graphic

You don't need any components to manipulate your application's graphic objects. You can construct, draw on, save, and destroy graphic objects without ever drawing anything on screen. In fact, your applications rarely draw directly on a form. More often, an application operates on graphics and then uses a VCL image control component to display the graphic on a form.

Once you move the application's drawing to the graphic in the image control, it is easy to add printing, Clipboard, and loading and saving operations for any graphic objects. graphic objects can be bitmap files, metafiles, icons or whatever other graphics classes that have been installed such as JPEG graphics.

Note: Because you are drawing on an offscreen image such as a TBitmap canvas, the image is not displayed until a control copies from a bitmap onto the control's canvas. That is, when drawing bitmaps and assigning them to an image control, the image appears only when the control has an opportunity to process its paint message. Contrastly, if you are drawing directly onto the canvas property of a control, the picture object is displayed immediately.

Making scrollable graphics

The graphic need not be the same size as the form: it can be either smaller or larger. By adding a scroll box control to the form and placing the graphic image inside it, you can display graphics that are much larger than the form or even larger than the screen. To add a scrollable graphic first you add a TScrollbox component and then you add the image control.

Adding an image control

An image control is a container component that allows you to display your bitmap objects. You use an image control to hold a bitmap that is not necessarily displayed all the time, or which an application needs to use to generate other pictures.

Note: "Adding graphics to controls" shows how to use graphics in controls.

Placing the control

You can place an image control anywhere on a form. If you take advantage of the image control's ability to size itself to its picture, you need to set the top left corner only. If the image control is a nonvisible holder for a bitmap, you can place it anywhere, just as you would a nonvisual component.

If you drop the image control on a scroll box already aligned to the form's client area, this assures that the scroll box adds any scroll bars necessary to access offscreen portions of the image's picture. Then set the image control's properties.

Setting the initial bitmap size

When you place an image control, it is simply a container. However, you can set the image control's Picture property at design time to contain a static graphic. The control can also load its picture from a file at runtime, as described in "Loading and saving graphics files".

To create a blank bitmap when the application starts,

  1. Attach a handler to the OnCreate event for the form that contains the image.
  2. Create a bitmap object, and assign it to the image control's Picture.Graphic property.

In this example, the image is in the application's main form, Form1, so the code attaches a handler to Form1's OnCreate event:

procedure TForm1.FormCreate(Sender: TObject);
var
  Bitmap: TBitmap;  { temporary variable to hold the bitmap }
begin
  Bitmap := TBitmap.Create;  { construct the bitmap object }
 Bitmap.Width := 200;  { assign the initial width... }
 Bitmap.Height := 200;  { ...and the initial height }
 Image.Picture.Graphic := Bitmap;  { assign the bitmap to the image control }
end;

Assigning the bitmap to the picture's Graphic property gives ownership of the bitmap to the picture object. The picture object destroys the bitmap when it finishes with it, so you should not destroy the bitmap object. You can assign a different bitmap to the picture (see "Replacing the picture"), at which point the picture disposes of the old bitmap and assumes ownership of the new one.

If you run the application now, you see that client area of the form has a white region, representing the bitmap. If you size the window so that the client area cannot display the entire image, you'll see that the scroll box automatically shows scroll bars to allow display of the rest of the image. But if you try to draw on the image, you don't get any graphics, because the application is still drawing on the form, which is now behind the image and the scroll box.

Drawing on the bitmap

To draw on a bitmap, use the image control's canvas and attach the mouse-event handlers to the appropriate events in the image control. Typically you would use region operations (fills, rectangles, polylines, and so on). These are fast and efficient methods of drawing.

An efficient way to draw images when you need to access individual pixels is to use the bitmap ScanLine property. For general-purpose usage, you can set up the bitmap pixel format to 24 bits and then treat the pointer returned from ScanLine as an array of RGB. Otherwise, you will need to know the native format of the ScanLine property. This example shows how to use ScanLine to get pixels one line at a time.

procedure TForm1.Button1Click(Sender: TObject);
// This example shows drawing directly to the BitMap
var
  x,y : integer;
  BitMap : TBitMap;
  P : PByteArray;
begin
  BitMap := TBitMap.create;
  try
    BitMap.LoadFromFile('C:\Program Files\Borland\Delphi 4\Images\Splash\256color\
factory.bmp');
    for y := 0 to BitMap.height -1 do
    begin
      P := BitMap.ScanLine[y];
      for x := 0 to BitMap.width -1 do
        P[x] := y;
    end;
  canvas.draw(0,0,BitMap);
  finally
    BitMap.free;
  end;
end;

Loading and saving graphics files

Graphic images that exist only for the duration of one running of an application are of very limited value. Often, you either want to use the same picture every time, or you want to save a created picture for later use. The VCL's image control makes it easy to load pictures from a file and save them again.

The VCL components you use to load, save, and replace graphic images support many graphic formats including bitmap files, metafiles, glyphs, and so on. They also support installable graphic classes.

The way to load and save graphics files is the similar to any other files and is described in the following sections:

Loading a picture from a file

Your application should provide the ability to load a picture from a file if your application needs to modify the picture or if you want to store the picture outside the application so a person or another application can modify the picture.

To load a graphics file into an image control, call the LoadFromFile method of the image control's Picture object.

The following code gets a file name from an open-file dialog box, and then loads that file into an image control named Image:

procedure TForm1.Open1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
  begin
    CurrentFile := OpenDialog1.FileName;
   Image.Picture.LoadFromFile(CurrentFile);
  end;
end;

Saving a picture to a file

The VCL picture object can load and save graphics in several formats, and you can create and register your own graphic-file formats so that picture objects can load and store them as well.

To save the contents of an image control in a file, call the SaveToFile method of the image control's Picture object.

The SaveToFile method requires the name of a file in which to save. If the picture is newly created, it might not have a file name, or a user might want to save an existing picture in a different file. In either case, the application needs to get a file name from the user before saving, as shown in the next section.

The following pair of event handlers, attached to the File|Save and File|Save As menu items, respectively, handle the resaving of named files, saving of unnamed files, and saving existing files under new names.

procedure TForm1.Save1Click(Sender: TObject);
begin
  if CurrentFile <> '' then
    Image.Picture.SaveToFile(CurrentFile)  { save if already named }
 else SaveAs1Click(Sender);  { otherwise get a name }
end;
procedure TForm1.Saveas1Click(Sender: TObject);
begin
  if SaveDialog1.Execute then  { get a file name }
  begin
    CurrentFile := SaveDialog1.FileName;  { save the user-specified name }
   Save1Click(Sender);  { then save normally }
  end;
end;

Replacing the picture

You can replace the picture in an image control at any time. If you assign a new graphic to a picture that already has a graphic, the new graphic replaces the existing one.

To replace the picture in an image control, assign a new graphic to the image control's Picture object.

Creating the new graphic is the same process you used to create the initial graphic (see "Setting the initial bitmap size"), but you should also provide a way for the user to choose a size other than the default size used for the initial graphic. An easy way to provide that option is to present a dialog box, such as the one in Figure 7.1.

Figure 7.1   Bitmap-dimension dialog box from the BMPDlg unit.

This particular dialog box is created in the BMPDlg unit included with the GraphEx project (in the EXAMPLES\DOC\GRAPHEX directory).

With such a dialog box in your project, add it to the uses clause in the unit for your main form. You can then attach an event handler to the File|New menu item's OnClick event. Here's an example:

procedure TForm1.New1Click(Sender: TObject);
var
  Bitmap: TBitmap;  { temporary variable for the new bitmap }
begin
  with NewBMPForm do
  begin
    ActiveControl := WidthEdit;  { make sure focus is on width field }
   WidthEdit.Text := IntToStr(Image.Picture.Graphic.Width);  { use current dimensions... }
   HeightEdit.Text := IntToStr(Image.Picture.Graphic.Height);  { ...as default }
   if ShowModal <> idCancel then  { continue if user doesn't cancel dialog box }
    begin
      Bitmap := TBitmap.Create;  { create fresh bitmap object }
     Bitmap.Width := StrToInt(WidthEdit.Text);  { use specified width }
     Bitmap.Height := StrToInt(HeightEdit.Text);  { use specified height }
     Image.Picture.Graphic := Bitmap;  { replace graphic with new bitmap }
     CurrentFile := '';  { indicate unnamed file }
    end;
  end;
end;

Note: Assigning a new bitmap to the picture object's Graphic property causes the picture object to destroy the existing bitmap and take ownership of the new one. The VCL handles the details of freeing the resources associated with the previous bitmap automatically.

Using the Clipboard with graphics

You can use the Windows Clipboard to copy and paste graphics within your applications or to exchange graphics with other applications. The VCL's Clipboard object makes it easy to handle different kinds of information, including graphics.

Before you can use the Clipboard object in your application, you must add the Clipbrd unit to the uses clause of any unit that needs to access Clipboard data.

Copying graphics to the Clipboard

You can copy any picture, including the contents of image controls, to the Clipboard. Once on the Clipboard, the picture is available to all Windows applications.

To copy a picture to the Clipboard, assign the picture to the Clipboard object using the Assign method.

This code shows how to copy the picture from an image control named Image to the Clipboard in response to a click on an Edit|Copy menu item:

procedure TForm1.Copy1Click(Sender: TObject);
begin
  Clipboard.Assign(Image.Picture)
end.

Cutting graphics to the Clipboard

Cutting a graphic to the Clipboard is exactly like copying it, but you also erase the graphic from the source.

To cut a graphic from a picture to the Clipboard, first copy it to the Clipboard, then erase the original.

In most cases, the only issue with cutting is how to show that the original image is erased. Setting the area to white is a common solution, as shown in the following code that attaches an event handler to the OnClick event of the Edit|Cut menu item:

procedure TForm1.Cut1Click(Sender: TObject);
var
  ARect: TRect;
begin
  Copy1Click(Sender);  { copy picture to Clipboard }
 with Image.Canvas do
  begin
    CopyMode := cmWhiteness;  { copy everything as white }
   ARect := Rect(0, 0, Image.Width, Image.Height);  { get bitmap rectangle }
   CopyRect(ARect, Image.Canvas, ARect);  { copy bitmap over itself }
   CopyMode := cmSrcCopy;  { restore normal mode }
  end;
end;

Pasting graphics from the Clipboard

If the Windows Clipboard contains a bitmapped graphic, you can paste it into any image object, including image controls and the surface of a form.

To paste a graphic from the Clipboard,

  1. Call the Clipboard's HasFormat method to see whether the Clipboard contains a graphic.

    HasFormat is a Boolean function. It returns True if the Clipboard contains an item of the type specified in the parameter. To test for graphics, you pass CF_BITMAP.

  2. Assign the Clipboard to the destination.

This code shows how to paste a picture from the Clipboard into an image control in response to a click on an Edit|Paste menu item:

procedure TForm1.PasteButtonClick(Sender: TObject);
var
  Bitmap: TBitmap;
begin
 if Clipboard.HasFormat(CF_BITMAP) then   { is there a bitmap on the Clipboard? )
 begin
   Image.Picture.Bitmap.Assign(Clipboard);
 end;
end;

The graphic on the Clipboard could come from this application, or it could have been copied from another application, such as Windows Paintbrush. You do not need to check the clipboard format in this case because the paste menu should be disabled when the clipboard does not contain a supported format.

Rubber banding example

This section walks you through the details of implementing the "rubber banding" effect in an graphics application that tracks mouse movements as the user draws a graphic at runtime. The example code in this section is taken from a sample application located in the EXAMPLES\DOC\GRAPHEX directory. The application draws lines and shapes on a window's canvas in response to clicks and drags: pressing a mouse button starts drawing, and releasing the button ends the drawing.

To start with, the example code shows how to draw on the surface of the main form. Later examples demonstrate drawing on a bitmap.

This section covers:

Responding to the mouse

Your application can respond to the mouse actions: mouse-button down, mouse moved, and mouse-button up. It can also respond to a click (a complete press-and-release, all in one place) that can be generated by some kinds of keystrokes (such as pressing Enter in a modal dialog box).

This section covers:

What's in a mouse event?

The VCL has three mouse events: OnMouseDown event, OnMouseMove event, and OnMouseUp event.

When a VCL application detects a mouse action, it calls whatever event handler you've defined for the corresponding event, passing five parameters. Use the information in those parameters to customize your responses to the events. The five parameters are as follows:

Table 7.4   Mouse-event parameters

Parameter

Meaning

Sender

The object that detected the mouse action

Button

Indicates which mouse button was involved: mbLeft, mbMiddle, or mbRight

Shift

Indicates the state of the Alt, Ctrl, and Shift keys at the time of the mouse action

X, Y

The coordinates where the event occurred

Most of the time, you need the coordinates returned in a mouse-event handler, but sometimes you also need to check Button to determine which mouse button caused the event.

Note: Delphi uses the same criteria as Microsoft Windows in determining which mouse button has been pressed. Thus, if you have switched the default "primary" and "secondary" mouse buttons (so that the right mouse button is now the primary button), clicking the primary (right) button will record mbLeft as the value of the Button parameter.

Responding to a mouse-down action

Whenever the user presses a button on the mouse, an OnMouseDown event goes to the object the pointer is over. The object can then respond to the event.

To respond to a mouse-down action, attach an event handler to the OnMouseDown event.

The VCL generates an empty handler for a mouse-down event on the form:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
begin
end;

Here's code that displays some text at the point where the mouse button is pressed. It uses the X and Y parameters sent to the method, and calls the TextOut method of the canvas to display text there:

The following code displays the string 'Here!' at the location on a form clicked with the mouse:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
begin
 Canvas.TextOut(X, Y, 'Here!');  { write text at (X, Y) }
end;

When the application runs, you can press the mouse button down with the mouse cursor on the form and have the string, "Here!" appear at the point clicked. This code sets the current drawing position to the coordinates where the user presses the button:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
begin
 Canvas.MoveTo(X, Y);  { set pen position }
end;

Pressing the mouse button now sets the pen position, setting the line's starting point. To draw a line to the point where the user releases the button, you need to respond to a mouse-up event.

Responding to a mouse-up action

An OnMouseUp event occurs whenever the user releases a mouse button. The event usually goes to the object the mouse cursor is over when the user presses the button, which is not necessarily the same object the cursor is over when the button is released. This enables you, for example, to draw a line as if it extended beyond the border of the form.

To respond to mouse-up actions, define a handler for the OnMouseUp event.

Here's a simple OnMouseUp event handler that draws a line to the point of the mouse-button release:

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Canvas.LineTo(X, Y);  { draw line from PenPos to (X, Y) }
end;

This code lets a user draw lines by clicking, dragging, and releasing. In this case, the user cannot see the line until the mouse button is released.

Responding to a mouse move

An OnMouseMove event occurs periodically when the user moves the mouse. The event goes to the object that was under the mouse pointer when the user pressed the button. This allows you to give the user some intermediate feedback by drawing temporary lines while the mouse moves.

To respond to mouse movements, define an event handler for the OnMouseMove event. This example uses mouse-move events to draw intermediate shapes on a form while the user holds down the mouse button, thus providing some feedback to the user. The OnMouseMove event handler draws a line on a form to the location of the OnMouseMove event:

procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Canvas.LineTo(X, Y);  { draw line to current position }
end;

With this code, moving the mouse over the form causes drawing to follow the mouse, even before the mouse button is pressed.

Mouse-move events occur even when you haven't pressed the mouse button.

If you want to track whether there is a mouse button pressed, you need to add an object field to the form object.

Adding a field to a form object to track mouse actions

To track whether a mouse button was pressed, you must add an object field to the form object. When you add a component to a form, Delphi adds a field that represents that component to the form object, so that you can refer to the component by the name of its field. You can also add your own fields to forms by editing the type declaration in the form unit's header file.

In the following example, the form needs to track whether the user has pressed a mouse button. To do that, it adds a Boolean field and sets its value when the user presses the mouse button.

To add a field to an object, edit the object's type definition, specifying the field identifier and type after the public directive at the bottom of the declaration.

Delphi "owns" any declarations before the public directive: that's where it puts the fields that represent controls and the methods that respond to events.

The following code gives a form a field called Drawing of type Boolean, in the form object's declaration. It also adds two fields to store points Origin and MovePt of typeTPoint.

type
  TForm1 = class(TForm)
   procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
   procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
   procedure FormMouseMove(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
 public
    Drawing: Boolean;  { field to track whether button was pressed }
    Origin, MovePt: TPoint;  { fields to store points }
  end;

When you have a Drawing field to track whether to draw, set it to True when the user presses the mouse button, and False when the user releases it:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Drawing := True;  { set the Drawing flag }
 Canvas.MoveTo(X, Y);
end;
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Canvas.LineTo(X, Y);
 Drawing := False;  { clear the Drawing flag }
end;

Then you can modify the OnMouseMove event handler to draw only when Drawing is True:

procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Drawing then  { only draw if Drawing flag is set }
   Canvas.LineTo(X, Y);
end;

This results in drawing only between the mouse-down and mouse-up events, but you still get a scribbled line that tracks the mouse movements instead of a straight line.

The problem is that each time you move the mouse, the mouse-move event handler calls LineTo, which moves the pen position, so by the time you release the button, you've lost the point where the straight line was supposed to start.

Refining line drawing

With fields in place to track various points, you can refine an application's line drawing.

Tracking the origin point

When drawing lines, track the point where the line starts with the Origin field.

Origin must be set to the point where the mouse-down event occurs, so the mouse-up event handler can use Origin to place the beginning of the line, as in this code:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Drawing := True;
 Canvas.MoveTo(X, Y);
 Origin := Point(X, Y);  { record where the line starts }
end;
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Canvas.MoveTo(Origin.X, Origin.Y);  { move pen to starting point }
 Canvas.LineTo(X, Y);
 Drawing := False;
end;

Those changes get the application to draw the final line again, but they do not draw any intermediate actions--the application does not yet support "rubber banding."

Tracking movement

The problem with this example as the OnMouseMove event handler is currently written is that it draws the line to the current mouse position from the last mouse position, not from the original position.You can correct this by moving the drawing position to the origin point, then drawing to the current point:

procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Drawing then
  begin
    Canvas.MoveTo(Origin.X, Origin.Y);  { move pen to starting point }
   Canvas.LineTo(X, Y);
  end;
end;

The above tracks the current mouse position, but the intermediate lines do not go away, so you can hardly see the final line. The example needs to erase each line before drawing the next one, by keeping track of where the previous one was. The MovePt field allows you to do this.

MovePt must be set to the endpoint of each intermediate line, so you can use MovePt and Origin to erase that line the next time a line is drawn:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Drawing := True;
 Canvas.MoveTo(X, Y);
 Origin := Point(X, Y);
 MovePt := Point(X, Y);  { keep track of where this move was }
end;
procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Drawing then
  begin
    Canvas.Pen.Mode := pmNotXor;  { use XOR mode to draw/erase }
   Canvas.MoveTo(Origin.X, Origin.Y);  { move pen back to origin }
   Canvas.LineTo(MovePt.X, MovePt.Y);  { erase the old line }
   Canvas.MoveTo(Origin.X, Origin.Y);  { start at origin again }
   Canvas.LineTo(X, Y);  { draw the new line }
  end;
 MovePt := Point(X, Y);  { record point for next move }
 Canvas.Pen.Mode := pmCopy;
end;

Now you get a "rubber band" effect when you draw the line. By changing the pen's mode to pmNotXor, you have it combine your line with the background pixels. When you go to erase the line, you're actually setting the pixels back to the way they were. By changing the pen mode back to pmCopy (its default value) after drawing the lines, you ensure that the pen is ready to do its final drawing when you release the mouse button.

Working with multimedia

Delphi allows you to add multimedia components to your applications. To do this, you can use either the TAnimate component on the Win32 page or the TMediaplayer component on the System page of the Component palette. Use the animate component when you want to add silent video clips to your application. Use the media player component when you want to add audio and/or video clips to an application.

For more information on TAnimate and TMediaplayer components, see the VCL on-line help.

The following topics are discussed in this section:

Adding silent video clips to an application

The animation control in Delphi allows you to add silent video clips to your application.

To add a silent video clip to an application:

  1. Double-click the animate icon on the Win32 page of the Component palette. This automatically puts an animation control on the form window in which you want to display the video clip.
  2. Using the Object Inspector, select the Name property and enter a new name for your animation control. You will use this name when you call the animation control. (Follow the standard rules for naming Delphi identifiers).

    Always work directly with the Object Inspector when setting design time properties and creating event handlers.

  3. Do one of the following:

    This loads the AVI file into memory. If you want to display the first frame of the AVI clip on-screen until it is played using the Active property or the Play method, then set the Open property to True.

  4. Set the Repetitions property to the number of times you want to the AVI clip to play. If this value is 0, then the sequence is repeated until the Stop method is called.
  5. Make any other changes to the animation control settings. For example, if you want to change the first frame displayed when animation control opens, then set the StartFrame property to the desired frame value.
  6. Set the Active property to True using the drop down list or write an event handler to run the AVI clip when a specific event takes place at runtime. For example, to activate the AVI clip when a button object is clicked, write the button's OnClick event specifying that. You may also call the Play method to specify when to play the AVI.

    Note: If you make any changes to the form or any of the components on the form after setting Active to True, the Active property becomes False and you have to reset it to True. Do this either just before runtime or at runtime.

Example of adding silent video clips

Suppose you want to display an animated logo as the first screen that appears when your application starts. After the logo finishes playing the screen disappears.

To run this example, create a new project and save the Unit1.pas file as Frmlogo.pas and save the Project1.dpr file as Logo.dpr. Then:

  1. Double-click the animate icon from the Win32 page of the Component palette.
  2. Using the Object Inspector, set its Name property to Logo1.
  3. Select its FileName property, click the ellipsis (...) button, choose the cool.avi file from your ..\Demos\Coolstuf directory. Then click Open in the Open AVI dialog.

    This loads the cool.avi file into memory.

  4. Position the animation control box on the form by clicking and dragging it to the top right hand side of the form.
  5. Set its Repetitions property to 5.
  6. Click the form to bring focus to it and set its Name property to LogoForm1 and its Caption property to Logo Window. Now decrease the height of the form to right- center the animation control on it.
  7. Double-click the form's OnActivate event and write the following code to run the AVI clip when the form is in focus at runtime:
    Logo1.Active := True;
    
  8. Double-click the Label icon on the Standard page of the Component palette. Select its Caption property and enter Welcome to Cool Images 4.0. Now select its Font property, click the ellipsis (...) button and choose Font Style: Bold, Size: 18, Color: Navy from the Font dialog and click OK. Click and drag the label control to center it on the form.
  9. Click the animation control to bring focus back to it. Double-click its OnStop event and write the following code to close the form when the AVI file stops:
    LogoForm1.Close;
    
  10. Select Run|Run to execute the animated logo window.

Adding audio and/or video clips to an application

The media player component in Delphi allows you to add audio and/or video clips to your application. It opens a media device and plays, stops, pauses, records, etc., the audio and/or video clips used by the media device. The media device may be hardware or software.

To add an audio and/or video clip to an application:

  1. Double-click the media player icon on the System page of the Component palette. This automatically put a media player control on the form window in which you want the media feature.
  2. Using the Object Inspector, select the Name property and enter a new name for your media player control. You will use this when you call the media player control. (Follow the standard rules for naming Delphi identifiers.)

    Always work directly with the Object Inspector when setting design time properties and creating event handlers.

  3. Select the DeviceType property and choose the appropriate device type to open using the AutoOpen property or the Open method. (If DeviceType is dtAutoSelect the device type is selected based on the file extension of the media file specified by the FileName property.) For more information on device types and their functions, see Table 7.5.
  4. If the device stores its media in a file, specify the name of the media file using the FileName property. Select the FileName property, click the ellipsis (...) button, and choose a media file from any available local or network directories and click Open in the Open dialog. Otherwise, insert the hardware the media is stored in (disk, cassette, and so on) for the selected media device, at runtime.
  5. Set the AutoOpen property to True. This way the media player automatically opens the specified device when the form containing the media player control is created at runtime. If AutoOpen is False, the device must be opened with a call to the Open method.
  6. Set the AutoEnable property to True to automatically enable or disable the media player buttons as required at runtime; or, double-click the EnabledButtons property to set each button to True or False depending on which ones you want to enable or disable.

    The multimedia device is played, paused, stopped, and so on when the user clicks the corresponding button on the mediaplayer component. The device can also be controlled by the methods that correspond to the buttons (Play, Pause, Stop, Next, Previous, and so on).

  7. Position the media player control bar on the form by either clicking and dragging it to the appropriate place on the form or by selecting the Align property and choosing the appropriate align position from the drop down list.

    If you want the media player to be invisible at runtime, set the Visible property to False and control the device by calling the appropriate methods (Play, Pause, Stop, Next, Previous, Step, Back, Start Recording, Eject).

  8. Make any other changes to the media player control settings. For example, if the media requires a display window, set the Display property to the control that displays the media. If the device uses multiple tracks, set the Tracks property to the desired track.

    Table 7.5    Multimedia device types and their functions

    Device Type

    Software/Hardware used

    Plays

    Uses Tracks

    Uses a Display Window

    dtAVIVideo

    AVI Video Player for Windows

    AVI Video files

    No

    Yes

    dtCDAudio

    CD Audio Player for Windows or a CD Audio Player

    CD Audio Disks

    Yes

    No

    dtDAT

    Digital Audio Tape Player

    Digital Audio Tapes

    Yes

    No

    dtDigitalVideo

    Digital Video Player for Windows

    AVI, MPG, MOV files

    No

    Yes

    dtMMMovie

    MM Movie Player

    MM film

    No

    Yes

    dtOverlay

    Overlay device

    Analog Video

    No

    Yes

    dtScanner

    Image Scanner

    N/A for Play (scans images on Record)

    No

    No

    dtSequencer

    MIDI Sequencer for Windows

    MIDI files

    Yes

    No

    dtVCR

    Video Cassette Recorder

    Video Cassettes

    No

    Yes

    dtWaveAudio

    Wave Audio Player for Windows

    WAV files

    No

    No

Example of adding audio and/or video clips

This example runs an AVI video clip of a multimedia advertisement for Delphi. To run this example, create a new project and save the Unit1.pas file to FrmAd.pas and save the Project1.dpr file to DelphiAd.dpr. Then:

  1. Double-click the media player icon on the System page of the Component palette.
  2. Using the Object Inspector, set the Name property of the media player to VideoPlayer1.
  3. Select its DeviceType property and choose dtAVIVideo from the drop down list.
  4. Select its FileName property, click the ellipsis (...) button, choose the speedis.avi file from your ..\Demos\Coolstuf directory. Click Open in the Open dialog.
  5. Set its AutoOpen property to True and its Visible property to False.
  6. Double-click the Animate icon from the Win32 page of the Component palette. Set its AutoSize property to False, its Height property to 175 and Width property to 200. Click and drag the animation control to the top left corner of the form.
  7. Click the media player to bring back focus to it. Select its Display property and choose Animate1 from the drop down list.
  8. Click the form to bring focus to it and select its Name property and enter Delphi_Ad. Now resize the form to the size of the animation control.
  9. Double-click the form's OnActivate event and write the following code to run the AVI video when the form is in focus:
    Videoplayer1.Play;
    
  10. Choose Run|Run to execute the AVI video.