Sunteți pe pagina 1din 4

Advanced Delphi Programming » Mastering Delphi

Adding a Calculated Field


Last Updated on Sat, 02 Feb 2019 | Mastering Delphi

Now that you've been introduced to TField objects and seen an example of their run-time use, it is time to build a simple example based on the
declaration of field objects at design time using the Fields editor. We can start again from the first example we built, GridDemo, and add a calculated
field. The COUNTRY.DB database table we are accessing has both the population and the area of each country, so we can use this data to compute
the population density.

To build the new example, named Calc, select the Table component in the form, and open the Fields editor. In this editor, choose the Add command,
and select some of the fields. (I've decided to include them all.) Now select the Define command, and enter a proper name and data type
(TFloatField) for the new calculated field, as you can see in Figure 13.8.

FIGURE 13.8:

The definition of a calculated field in the Calc example

Warning It is obvious that as you create some field components at design time using the Fields editor, the fields you skip won't get a corresponding
object. What might not be obvious is that the fields you skip will not be available even at run time, with Fields or FieldByName. When a program
opens a table at run time, if there are no design-time field components, Delphi creates field objects corresponding to the table definition. If there are
some design-time fields, however, Delphi uses those fields without adding any extra ones.

Of course, we also need to provide a way to calculate the new field. This is accomplished in the OnCalcFields event of the Table component, which
has the following code (at least in a first version):

procedure TForm2.Table1CalcFields(DataSet: TDataSet); begin

Table1PopulationDensity.Value := Table1Population.Value / Table1Area.Value; end;

Calculated fields are computed for each record and recalculated each time the record is loaded in an internal buffer, invoking the OnCalcFields event
over and over again. For this reason, a handler of this event should be extremely fast to execute, and cannot alter the status of the dataset, by
accessing different records. A more time-efficient (but less memory-efficient) version of a calculated field is provided by the ClientDataSet
component with "internally calculated" fields, which are evaluated only once, when they are loaded, with the result stored in memory for future
requests.

Everything fine? Not at all! If you enter a new record and do not set the value of the population and area, or if you accidentally set the area to zero, the
division will raise an exception, making it quite problematic to continue using the program. As an alternative, we could have handled every exception
of the division expression and simply set the resulting value to zero: try

a. Value := Table1Population.Value / Table1Area.Value; except on Exception do


b. Value := 0;

end; 

However, we can do even better. We can check if the value of the area is defined—if it is not null—and if it is not zero. It is better to avoid using
exceptions when you can anticipate the possible error conditions:

if not Table1Area.IsNull and

(Table1Area.Value <> 0) then Table1PopulationDensity.Value := Table1Population.Value / Table1Area.Value else

Table1PopulationDensity.Value := 0;

The code of the Table1CalcFields method above (in each of the three versions) accesses some fields directly. This is possible because I used the
Fields editor, and it automatically created the corresponding field declarations, as you can see in this excerpt of the interface declaration of the form:
type

TCalcForm = class(TForm) Table1: TTable;

Table1PopulationDensity: TFloatField;

Table1Area: TFloatField;

Table1Population: TFloatField;

Table1Name: TStringField;

Table1Capital: TStringField;

Table1Continent: TStringField;

procedure Table1CalcFields(DataSet: TDataset);

Each time you add or remove fields in the Fields editor, you can see the effect of your action immediately in the grid present in the form. Of course,
you won't see the values of a calculated field at design time; they are available only at run time, because they result from the execution of compiled
Pascal code.

Since we have defined some components for the fields, we can use them to customize some of the visual elements of the grid. For example, to set a
display format that adds a comma to separate thousands, we can use the Object Inspector to change the DisplayFormat property of some field
components to "###,###,###". This change has an immediate effect on the grid at design time.

The display format I've just mentioned (and used in the previous example) uses the Windows International Settings to format the output. When
Delphi translates the numeric value of this field to text, the comma in the format string is replaced by the proper ThousandSeparator character. For
this reason, the output of the program will automatically adapt itself to different International Settings. On computers that have the Italian
configuration, for example, the comma is replaced by a period.

After working on the table components and the fields, I've customized the DBGrid using its Columns property editor. I've set the Population Density
column to read-only and set its ButtonStyle property to cbsEllipsis, to provide a custom editor. When you set this value, a small button with an ellipsis
is displayed when the user tries to edit the grid cell. Pressing the button invokes the OnEditButtonClick event of the DBGrid:

procedure TCalcForm.DBGrid1EditButtonClick(Sender: TObject); begin

MessageDlg (Format (

'The population density (%.2n)'#13 + 'is the Population (%.0n)'#13 + 'divided by the Area (%.0n).'#13#13 + 'Edit these two fields to change it.',
[Table1PopulationDensity.AsFloat, Table1Population.AsFloat, Table1Area.AsFloat]), mtInformation, [mbOK], 0);

end;

Actually, I haven't provided a real editor, but rather a message describing the situation, as you can see in Figure 13.9, which shows the values of the
calculated fields. To create an editor, you might build a secondary form to handle special data entries.

FIGURE 13.9:

The output of the Calc example. Notice the Population Density calculated column, the ellipsis button, and the message displayed when you select it.



Was this article helpful?

0 0
Self Publishing a Book The Easy Way
This comprehensive guide will present you with a variety of self-publishing options and explore their viability. Well take a look at
all types of books and book-delivery systems.

Get My Free Ebook

« Previous Page Next Page »

Related Posts
Advanced Registry Cleaner PC Diagnosis and Repair
Get Paid to Write at Home
Organize With Office 365
Project Management Templates
Self Publishing Success
Programming a calculated field
Simple HTTP Server - Mastering Delphi
Scaling Forms - Mastering Delphi
Scrolling a Form - Mastering Delphi
Connection Pooling - Mastering Delphi

Responses
MICHELINO MARCELO
How build calc field in delphi ?

9 years ago
Reply

NATHANIEL
How to use internal calculated fields in delphi?

9 years ago
Reply

ezio
How to insert value to an intenal calc field in delphi?

7 years ago
Reply

Post a comment

Name... 

Email...

Website... Optional

Comment it up...

Comment

About | Contact | Write For Us | Shop | Privacy Policy | Resources


S-ar putea să vă placă și