Hallo Martin,
also meine Komponenten funktionieren in DBCtrlGrid gar nicht (müssen sie aber auch nicht). DBEditSql (abgeleitet von DBEdit) lässt sich nicht einmal in das Grid einbinden.
Das Grid übernimmt offenbar die Kontrolle über die eingebunden Kompos, ordnet denen seine eigene interne Datenmenge zu und gibt möglicherweise sogar vor, wann diese Kompos neue Dateninhalte anzeigen sollen (sonst würden sie möglicherweise alle den Inhalt des aktuellen Datensatzes anzeigen).
Wenn das so ist, muss das Grid aber die eingebunden Komponenten kennen, um diese für seine Zwecke umzubiegen...
Mit dem FieldDataLink musst Du Dich m.E. nur näher beschäftigen, wenn Du mehrere Datensätze in Deiner Komponente verwalten willst (wie ein DBGrid).
Ansonsten reicht es, einfach nur FieldDataLink einzubinden. So habe ich es für meine Ein-Datensatz-Komponente gemacht:
Delphi-Quellcode:
//
constructor TDBSqlCustom.Create(AOwner: TComponent);
begin
inherited;
FFieldDataLink:=TFieldDataLink.Create;
FieldDataLink.Control:=Self;
FieldDataLink.OnDataChange:=DataChange;
...
//
procedure TDBSqlCustom.SetDataSet(Value:TDataSet);
begin
if ((FieldDataLink<>nil) and (FieldDataLink.DataSource<>nil)) then begin
if (Value<>FieldDataLink.DataSource.DataSet) then begin
FieldDataLink.DataSource.DataSet:=Value;
ShowData(True); // Datensatzinhalt anzeigen
end;
end;
...
procedure TDBSqlCustom.SetFieldName(Value:String);
begin
if (FFieldName<>Value) then begin
FField:=nil;
FFieldName:=Value;
FFieldDataLink.FieldName:=FFieldName;
ShowData(True);
...
procedure TDBSqlCustom.SetDataSource(Value:TDataSource);
begin
if ((FFieldDataLink<>nil) and (FFieldDataLink.DataSource<>Value)) then begin
ResetFields(True);
FFieldDataLink.DataSource:=nil;
FFieldDataLink.FieldName:='';
if (not (FFieldDataLink.DataSourceFixed and (csLoading in ComponentState))) then FFieldDataLink.DataSource:=Value;
if (Value<>nil) then Value.FreeNotification(Self);
ShowData(True);
...
Für mehrere Datensätze habe ich einen ausreichend großen Puffer für die anzuzeigenden Datensätze angelegt:
FieldDataLinkShow.BufferCount:=100; (wobei ich mehrere Datenmenge syncronisiere und deshalb die Puffergrößen aufeinander abstimmen muss)
Mit FieldDataLinkShow.ActiveRecord:=FieldDataLinkShow. ActiveRecord+-1 kannst Du durch die Datensätze iterieren, ohne dass dies Auswirkungen auf angebundene datensensitive Komponenten hat.
Wenn Du außerhalb des definierten Pufferbereiches kommst, erhältst Du nur noch leere Dateninhalte.
TDBSqlWhere kapselt die ganze Datenbankverbindung und wird von meinen TDBTabControlSql und TDBPanelsSql jeweils benutzt, um "die jeweils nächsten" Datensätze bereitzustellen. Die beiden Komponenten wiederum geben Ihrerseits vor, wann die Dateninhalte der einzelnen Items gezeichnet werden müssen:
Delphi-Quellcode:
//------------------------------------------------------------------------------
//
procedure TDBSqlWhere.SetDBSqlBufferCount(MaxCount:Integer);
var NeedBufferCount:Integer;
begin
if (MaxCount=0) then MaxCount:=MinBufferCount;
if ((MaxCount>0) and (RecordCount>0)) then NeedBufferCount:=Min(RecordCount,MaxCount)
else NeedBufferCount:=RecordCount;
DBSqlBufferSize:=Max(DBSqlBufferSize,NeedBufferCount);
if (FieldDataLinkShow.BufferCount<DBSqlBufferSize) then FieldDataLinkShow.BufferCount:=DBSqlBufferSize;
end;
//------------------------------------------------------------------------------
//
procedure TDBSqlWhere.BeginReadRecord(RR:Integer=-1);
begin
if (RR>0) then FieldDataLinkShow.ActiveRecord:=RR;
if (FieldDataLinkShow<>nil) then begin
ActiveDBSqlRecNo:=DataSetShow.RecNo;
ActiveDBSqlRecord:=FieldDataLinkShow.ActiveRecord;
end
else begin
ActiveDBSqlRecNo:=0;
ActiveDBSqlRecord:=0;
end;
FirstDBSqlRecNo:=ActiveDBSqlRecNo;
LastDBSqlRecNo:=ActiveDBSqlRecNo;
ReadDBSqlRecNo:=ActiveDBSqlRecNo;
FirstDBSqlRecord:=ActiveDBSqlRecord;
LastDBSqlRecord:=ActiveDBSqlRecord;
ReadDBSqlRecord:=ActiveDBSqlRecord;
end;
//------------------------------------------------------------------------------
//
function TDBSqlWhere.GetReadRecord(RR:Integer):Boolean;
begin
Result:=False;
if ((RR>=0) and (RR<RecordCount)) then begin
if ((RR<FirstDBSqlRecord) or (FirstDBSqlRecord<0)) then FirstDBSqlRecord:=RR;
if (RR>LastDBSqlRecord) then LastDBSqlRecord:=RR;
FieldDataLinkShow.ActiveRecord:=RR;
Result:=True;
end;
end;
//------------------------------------------------------------------------------
//
function TDBSqlWhere.ReadRecordIsActive:Boolean;
begin
Result:=(FieldDataLinkShow.ActiveRecord=ActiveDBSqlRecord);
end;
//------------------------------------------------------------------------------
//
procedure TDBSqlWhere.GoToRecNo(RN:Integer);
begin
inherited;
if (DataSetShow<>nil) then begin
if (RN>RecordCount) then RN:=RecordCount;
if (RN>0) then DataSetShow.RecNo:=RN;
end;
end;
//------------------------------------------------------------------------------
//
procedure TDBSqlWhere.EndReadRecord;
begin
if (FieldDataLinkShow<>nil) then FieldDataLinkShow.ActiveRecord:=ActiveDBSqlRecord;
end;
Das sind zwar etwas ältere Quelltexte, das Prinzip sollte aber erkennbar sein...
Gruß Stahli