Reputation: 189
I'm trying to create a new field in TFDMemTable
at run time, the field must be a Combobox
and i would like to look up the items for the Combobox
from a second TFDMemTable
.
How can i achieve this ?
Here is a sample of what i need, i have a main table and a secondary table, i am trying to have a field in the main table with items from the secondary table.
I tried doing something like this :
//First i try creating the second table with the values for the combobox
FDMemTableQualityLiterals.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTableQualityLiterals.FieldDefs.Add('IdValue', ftString, 20, false);
FDMemTableQualityLiterals.CreateDataSet;
FDMemTableQualityLiterals.Open;
FDMemTableQualityLiterals.AppendRecord([1, '480p']);
FDMemTableQualityLiterals.AppendRecord([2, '720p']);
FDMemTableQualityLiterals.AppendRecord([3, '1080p']);
// then i try to create the main table with a few field including the qualityID field
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('Name', ftString, 30, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet;
FDMemTable1.Close;
//i try to link/create a new field like qualityID that has literal values instead of an id
CreateLookupField(TDataset(FDMemTable1), 'QualityLookup', TDataset(FDMemTableQualityLiterals), 'QualityID', 'QualityID', 'IdValue');
FDMemTable1.CreateDataSet;
FDMemTable1.open;
FDMemTable1.AppendRecord([0, 'item1', 1]);
FDMemTable1.AppendRecord([1, 'item2', 2]);
FDMemTable1.AppendRecord([2, 'item3', 3]);
// i use this code to show the result in devExpress
cxGrid1DBTableView1.DataController.DataSource := DataSource1;
cxGrid1DBTableView1.DataController.CreateAllItems();
Procedure TForm1.CreateLookupField( ATable: TDataSet; AFieldName: String; ALookupDataset: TDataset; AKeyfields: String; ALookupKeyfields: String; ALookupResultField : String);
Var
I : Integer;
NewField : TField;
Begin
with ATable do begin
if FieldDefs.Updated = False then
FieldDefs.Update;
If FindField(AFieldName) = Nil then
begin
NewField := TStringField.Create(ATable);
NewField.FieldName := AFieldName;
NewField.KeyFields := AKeyFields;
NewFIeld.LookupDataSet := ALookupDataset;
NewField.LookupKeyFields := ALookupKeyFields;
NewField.LookupResultField := ALookupResultField;
NewField.FieldKind := fkLookup;
NewField.Dataset := ATable;
end;
end;
End;
But it doesn't work and i get an error saying the qualityID
doesn't exist, even if we exclude the error, is this approach correct ? is this the way to do this?
Upvotes: 2
Views: 3288
Reputation: 1749
TFieldDefs is a list of Field Definitions not a list of Fields, CreateDataSet
method creates the fields list from TFieldDefs but when you close the DataSet, Fields list will be cleared.
For creating the LoockUp Fields the dataset must be closed and a closed dataset has an empty field list but you need to the fields when you are creating the lookup fields !. So you should create your field list manually for a closed dataset, do it like this :
var
I : Integer;
begin
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('name', ftString, 30, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet; //This is unnecessary
FDMemTable1.Close;
for I := 0 to FDMemTable1.FieldDefs.Count - 1 do
begin
if FDMemTable1.FindField(FDMemTable1.FieldDefs[i].Name) = Nil then
FDMemTable1.FieldDefs.Items[i].CreateField(FDMemTable1);
end;
CreateLookupField(TDataset(FDMemTable1), 'QualityLookup', TDataset(FDMemTableQualityLiterals), 'QualityID', 'QualityID', 'IdValue');
FDMemTable1.CreateDataSet;
//FDMemTable1.open; //not need to `FDMemTable1.open` after `FDMemTable1.CreateDataSet`, `CreateDataSet` method sets Active = True
FDMemTable1.AppendRecord([0, 'Ali', 1]);
FDMemTable1.AppendRecord([1, 'Ali2', 2]);
FDMemTable1.AppendRecord([2, 'Ali3', 3]);
//FDMemTable1.AppendRecord([1, 'Ali', 1, 1]);
//FDMemTable1.AppendRecord([1, 'Ali']);
//FDMemTable1.Close;
// FDMemTable1.CreateDataSet;
// cxGrid1DBTableView1.DataController.DataSource := DataSource1;
//FDMemTable1.Active := true;
// cxGrid1DBTableView1.DataController.CreateAllItems();
end;
Upvotes: 4