Esta solución es buena, pero tiene una carencia: no tiene en cuenta que ya pueden existir campos en el dataset.
En mi caso, suelo añadir campos calculados a datasets "reales" que ya contiene campos persistentes. Un ejemplo es construir un mensaje de estado a partir de los valores de ciertos campos, y así mostrar en un grid directamente ese mensaje.
En ese caso, hay que respetar los campos existentes y luego añadirle los nuevos calculados:
Código Delphi
[-]procedure CrearCampoCalculado(DataSet :TDataSet; nombrecampo :string; tipo :TFieldType; longi :integer);
var
f: TField;
i: Integer;
begin
try
DataSet.FieldDefs.Update;
for i:=0 to DataSet.FieldDefs.Count - 1 do
if DataSet.FindField(DataSet.FieldDefs[i].Name) = nil then
DataSet.FieldDefs.Items[i].CreateField(DataSet);
if DataSet.FindField(nombrecampo) = nil then begin
case tipo of
ftString: f:=TStringField.Create(DataSet);
ftInteger: f:=TIntegerField.Create(DataSet);
ftBoolean: f:=TBooleanField.Create(DataSet);
else ShowMessage('Tipo de campo no contemplado: '+GetEnumName(TypeInfo(TFieldType),integer(tipo)));
end;
if f <> nil then begin
f.DataSet:=DataSet;
f.Name:=DataSet.Name+nombrecampo;
f.FieldName:=nombrecampo;
f.DisplayLabel:=nombrecampo;
if tipo = ftString then
f.Size:=longi;
f.Calculated:=true;
end;
end
else ShowMessage('Ya existe un campo de nombre "'+nombrecampo+'"');
except on e:exception do
ShowMessage(e.Message);
end;
end;
Nota: la función GetEnumName requiere
uses TypInfo;
Y llamo a esa función en el evento BeforeOpen:
Código Delphi
[-]procedure tDatasetBeforeOpen(DataSet: TDataSet);
begin
CrearCampoCalculado(DataSet, 'temporal_entero', ftInteger,0);
CrearCampoCalculado(DataSet, 'temporal_texto', ftString,20);
end;
Espero que ayude.