Graphics
Simple Bar Chart  Lab Report
Create a Simple Bar Chart from "Scratch" 
Delphi 7 VCL Version for Windows
  

Delphi 7/Windows or Kylix 3/Linux CLX Version

Purpose
The Simple Bar Chart shows how to create a simple bar chart graphic and display it, or write it to a BMP disk file, using either the Delphi Visual Component Library (VCL) (Windows only) or Kylix Cross Platform (CLX) Objects for Windows or Linux.

Materials and Equipment

Software Requirements
Windows 95/98/2000, Delphi 3/4/5/6/7 or 
Linux and Kylix (tested with Red Hat 7.2 and Kylix 3)
SimpleBarChart exectuable

Hardware Requirements
VGA display.

Procedure

  1. Double click on the SimpleBarChart.EXE icon to start the program.
  2. Press the Show Bars button to see several bars.
  3. Press the Write BMP button to create an 800-by-400 BarChart.BMP file with the bar chart. An in-memory bitmap containing the graphic can be made to be any size.

Discussion
This project was one of my first attempts to convert a Delphi VCL program to a Delphi/Kylix CLX program.  [VCL programs can only run in Windows while a Cross Platform (CLX) program can run in Windows or Linux.]  The original conversion was from Delphi 5 VCL  to Kylix 1 CLX.  My original intent was to use IFDEFs to keep one source program that could be compiled in Delphi or Kylix.  This seemed to work with Delphi 5 VCL and Kylix 1 CLX, but I have not found a convenient way to use either VCL or CLX under Windows, and CLX under Kylix.  Now I keep separate source files for VCL and CLX versions.  Differences between the VCL and CLX versions will be described below.

The uses statement in the project file (.dpr) uses the "Q" library for the CLX version:

SimpleBarChart.dpr Project File:  uses Statement

CLX
uses
  QForms,
  ScreenSimpleBarChart in 'ScreenSimpleBarChart.pas' {FormBarChart};
VCL
uses
  Forms,
  ScreenSimpleBarChart in 'ScreenSimpleBarChart.pas' {FormBarChart};

The form file was named ScreenSimpleBarChart.dfm in Delphi/VCL and ScreenSimpleBarChart.xfm in Kylix/CLX.  Several changes were needed for Kylix to make sure the unit names and the files had the same case since (Kylix is case sensitive but Delphi is not.

The code for the ScreenSimpleBarChart form is in the SimpleBarChart.pas file.  In this file, the DrawBarChart procedure is used to draw on any canvas, namely, the Image.Canvas or the Bitmap.Canvas. So a single routine can be used for a screen display or a file (or could also be used for printing).  The HeightPercent and WidthPercent functions create device-independent drawings by determining the number of pixels a certain certain percentage of canvas height or width something is. 

The first CLX/VCL difference is in the uses statement:

SimpleBarChart.pas Project File:  uses Statement

CLX
uses
  SysUtils, Types, Classes, Variants,
  QGraphics, QControls, QForms, QDialogs, QStdCtrls, QExtCtrls;
VCL
uses
  SysUtils, WinProcs, Messages, Classes,
  Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, ExtCtrls;

Besides the difference in the name of form files with CLX (*.xfm) and with VCL (*.dfm), an "RGB" function must be provided for the CLX environment:

SimpleBarChart.pas Project File:  Implementation Difference

CLX
{$R *.xfm}
  // Delphi Windows unit function missing in Kylix
  FUNCTION RGB(CONST r,g,b:  BYTE):  TColor;
  BEGIN
    RESULT := (r OR (g SHL 8) OR (b SHL 16))
  END {RGB};
VCL
{$R *.dfm}

I normally design forms to be a fixed size such that there is no need to resize the form at run time.  This can be easily implemented in Delphi VCL by setting the form's BorderStyle to bsSingle.  A different approach is needed with CLX.  The following code in a form's create method prevents any resizing:

SimpleBarChart.pas Project File:  FormCreate Difference

CLX
procedure TFormBarChart.FormCreate(Sender: TObject);
...
begin
// Need this in CLX to prevent resizing form
  WITH FormBarChart.Constraints DO
  BEGIN
    MaxHeight := Height;
    MaxWidth := Width;
    MinHeight := Height;
    MinWidth := Width;
  END; 
VCL
// Set form's BorderStyle to bsSingle in IDE

A minor CLX/VCL difference was needed in 

SimpleBarChart.pas Project File:  TBitmap.PixelFormat

CLX
Bitmap.PixelFormat := pf32bit;  // No pf24bit PixelFormat in Kylix
VCL
Bitmap.PixelFormat := pf24bit;  // avoid working with palettes

I try to always use pf24bit bitmaps in Windows, since they're smaller than pf32bit bitmaps.  Unfortunately, CLX only supports pf32bit TBitmaps.

Certain graphics operations needed to be "tweaked" to get the same results in Delphi and Kylix.  During the first conversion attempt, Delphi showed a white background and Kylix showed a black background.  The FillRect code shown below was added to both versions to always establish the background color.

The DrawBarChart procedure shown above was called to draw the graphics on any canvas in a device-independent way.  Here the complete VCL source code for this procedure (the CLX version is quite similar):

SimpleBarChart.pas Project File:  FormCreate Difference

VCL
PROCEDURE DrawBarChart (Canvas:  TCanvas; Width, Height:  INTEGER);
  CONST
    BarWidth   = 5;  // bar width is 5%
    Reserved   = 5;  // reserve 5% margin
    TextHeight = 8;  // text height is 8%

  VAR
    iBase  :  INTEGER;
    iWidth :  INTEGER;
    jBase  :  INTEGER;
    jHeight:  INTEGER;
    j      :  INTEGER;

  FUNCTION WidthPercent(CONST percent:  INTEGER):  INTEGER;
  BEGIN
    RESULT := iBase + MulDiv(iWidth, percent, 100)
  END;


  FUNCTION HeightPercent(CONST percent:  INTEGER):  INTEGER;
  BEGIN
    // '-' sign here to flip "Y" since "Y" goes from top to bottom
    RESULT := jBase - MulDiv(jHeight, percent, 100)
  END;


  PROCEDURE DrawBar(CONST BarColor, OutlineColor:  TColor; CONST X, height:  INTEGER);
  BEGIN
    Canvas.Brush.Color := BarColor;
    Canvas.Pen.Color   := OutlineColor;
    // Use 100-height since "Y" values are top to bottom
    Canvas.Rectangle( WidthPercent(X),           HeightPercent(height),
                      WidthPercent(X+BarWidth),  HeightPercent(0) );
  END;


BEGIN
  iBase := MulDiv(Width,  Reserved, 100);    // 5% margin
  jBase := Height - MulDiv(Height, Reserved, 100);

  iWidth  := Width  - 2*MulDiv(Width,  Reserved, 100);  // 90% working area
  jHeight := Height - 2*MulDiv(Height, Reserved, 100);

  // In Delphi, the background of a new canvas is normally white.
  // For Kylix compatibility, the following was added to avoid a black
  // background.
  Canvas.Brush.Color := clWhite;
  Canvas.FillRect(Canvas.ClipRect);

  Canvas.Brush.Style := bsClear;
  Canvas.Font.Name := 'Arial';
  Canvas.Font.Height := MulDiv(jHeight, TextHeight, 100);
  Canvas.TextOut(iBase, MulDiv(jHeight, Reserved, 100), 'Simple Bar Chart');

  // Draw Horizontal Reference Lines at 20% intervals
  Canvas.Pen.Color := clBlack;
  FOR j := 0 TO 5 DO
  BEGIN
    Canvas.MoveTo ( iBase,        HeightPercent(20*j) );
    Canvas.LineTo ( iBase+iWidth, HeightPercent(20*j) )
  END;

  // Unclear why this is needed in Kylix but not D3
  Canvas.Brush.Style := bsSolid;

  DrawBar(clYellow,  clRed,   0, 12);
  DrawBar(clRed,     clRed,  10, 80);
  DrawBar(clBlue,   clBlue,  20, 40);

  // Use RGB function to define a dark shade of Gray
  DrawBar(RGB({Red} 100, {Green} 100, {Blue} 100), clBlack, 30, 50);

  DrawBar(clRed, clBlue,   40, 90);
  DrawBar(clWhite, clRed,  50, 65);

  Canvas.Brush.Style := bsDiagCross;
  DrawBar(clLime, clRed,   60, 75);

  Canvas.Brush.Style := bsSolid;
  DrawBar(clLime, clLime,  70, 22);

END {DrawBarChart};                                                

Here's a summary of the changes D3 VCL to convert to K1 CLX:

  1. In D3, fix all case sensitivity differences in unit names.

  2.  Rename *.dfm to *.xfm

  3.  Load project in Kylix. Ignore the error:
    "Error reading FormBarChart.BorderStyle: Invalid property value."

  4. For FormBarChart, change Scaled property to False, and AutoScroll to False

  5. Reset form's icon by setting the Icon property to SimpleBarChart.ico 

The following chart summarizes the "bloat" by version of Delphi/Kylix: for the SimpleBarChart executable.  I really wish Borland would stop this code bloat.

Summary of Executable Size

Version Size[KB]
D3 VCL 221
D4 VCL 312
D5 VCL 324
D6 VCL 389
D7 VCL 393
D7 CLX 654
Kylix 1 CLX 415
Kylix 3 CLX  798

Conclusions
This example shows how to create a bar chart graphic "from scratch". 

In Delphi 3 or later for more complicated examples, the TChart component is probably a better alternative.  (TChart is not available in Kylix).


Keywords
Canvas, Brush.Color, Pen.Color, Rectangle, FillRect, Delphi/VCL, Kylix/CLX

Download
VCL: 
Delphi 3..7 Source and EXE (212 KB) for Windows:  SimpleBarChartVCL.zip 

CLX:  Delphi 7/Kylix 3 Source and Red Hat Linux executable (352 KB):  SimpleBarChart.tar.gz
In Linux to extract files:   gunzip < SimpleBarChart.tar.gz | tar xvf -


Updated 14 Jun 2009
Since 1 Nov 1998