Tabcontrol Object im Tab speichern

Rund um die LCL und andere Komponenten
Antworten
gtmind.de
Beiträge: 9
Registriert: So 27. Feb 2011, 16:23
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.4.z)
CPU-Target: AMD 32/64 bit
Wohnort: Dessau-Roßlau
Kontaktdaten:

Tabcontrol Object im Tab speichern

Beitrag von gtmind.de »

Hallo allerseits,
ich versuche gerade den Tabs im Tabcontol IDs mitzugeben. Quellcode funktioniert in Delphi.

Code: Alles auswählen

 
//Object:
type
  TFid = class
  public
    id: Integer;
    constructor Create(fid: Integer);
  end;
 
......
 
constructor TFid.Create(fid: Integer);
begin
  id := fid;
end;
 
//TabControl in einer Schleife füllen
  .....
  Qu.Open;
  i := 0;
  while not Qu.Eof do
  begin
    i := tc.Tabs.AddObject(
      Qu.FieldByName('VAL').Value,
      TFid.Create(TStringField(Qu.FieldByName('COL')).AsInteger)
      );
 
    //ShowMessage(IntToStr(i)+' === '+IntToStr(TFid(tc.Tabs.Objects[i]).id));
    inc(i);
    Qu.Next;
  end;
  tc.EndUpdate;
 
// Tabcontrol auslesen
procedure TfrmSolutions.tcChange(Sender: TObject);
begin
  ShowMessage(tc.Tabs.ValueFromIndex[tc.TabIndex]);
end;
 
.

ergibt immer 0. Egal welcher Wert im Object ist (war?)

Gruß Gerald
Auch aus Steinen, die einem in den Weg gelegt werden, kann man etwas schönes bauen.

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Tabcontrol Object im Tab speichern

Beitrag von theo »

Geht nicht, afaik.
S.a.
http://forum.lazarus.freepascal.org/ind ... ic=13131.0

Eine separate Liste halten.

gtmind.de
Beiträge: 9
Registriert: So 27. Feb 2011, 16:23
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.4.z)
CPU-Target: AMD 32/64 bit
Wohnort: Dessau-Roßlau
Kontaktdaten:

Re: Tabcontrol Object im Tab speichern

Beitrag von gtmind.de »

In Delphi keine Problem ... habe schon auf ComboBox umgestellt :roll: :cry:
Auch aus Steinen, die einem in den Weg gelegt werden, kann man etwas schönes bauen.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Tabcontrol Object im Tab speichern

Beitrag von wp_xyz »

Du bringst hier etwas durcheinander:
(1) Wenn du Zusatzinformation per TStrings.ValueFromIndex auslesen willst, muss die Information vorher via TStrings.Add('Name=Wert') in die Liste geschrieben worden sein. Das Argument des Add-Aufrufs ist aber gerade der Text, der auf dem Tab-Reiter steht, also "Name=Wert" - das willst du sicher nicht.

(2) Du schreibst die Zusatzinformation per TStrings.AddObject('name', Zusatzinfo_als_TObject) in die StringListe. Das wäre normalerweise OK, wenn die Zusatzinformation über TStrings.Objects[index] ausgelesen werden würde. Aber hier funktioniert auch das nicht, weil das eingehängte Objekt bereits intern verwendet wird. Um das zu sehen, klicke ein TabControl aufs Formular, füge im Designmodus ein paar Tabs hinzu und schreibe folgenden OnChange-Event-Handler:

Code: Alles auswählen

procedure TForm1.TabControl1Change(Sender: TObject);
var
  tabObj: TObject;
begin
  tabObj := TabControl1.Tabs.Objects[TabControl1.TabIndex];
  if tabObj = nil then
    ShowMessage('NIL')
  else
    ShowMessage(tabObj.Classname + / ' + TWinControl(tabObj).Caption);
end; 

Bei jedem Klick wird "TabSheet/<Name des Tabs>" ausgegeben, obwohl eigentlich bewusst gar kein TTabSheet als Objekt an die Tabs gehängt worden ist. Meiner Meinung nach ist TTabControl hier sehr schlecht programmiert, weil Einhängen von Zusatzinformationen unterbunden wird.

Wenn du einen zusätzlichen Integer zu jedem Tab speichern möchtest, fallen mir folgende Möglichkeiten ein:

(1) ein separates Array (oder TList oder TIntegerList, o.ä) außerhalb des TTabControl anlegen und dort den Integer speichern. Du musst natürlich dafür sorgen, dass die Tab-Liste und die Integer-Liste synchron bleiben.

(2) Eine andere, sehr hackermäßige Variante geht davon aus, dass alle GUI-Elemente bei einem String, der ein #0 enthält, die folgenden Zeichen nicht mehr anzeigen. Daher könntest du die Zusatzinformation einfach nach einer #0 mit in die Tab-Beschriftung packen:

Code: Alles auswählen

  while not Qu.Eof do
  begin
    tc.Tabs.Add(
      Qu.FieldByName('VAL').Value + #0 + IntToStr(Qu.FieldByName('COL')).AsInteger));
...

Später beim Auslesen:

Code: Alles auswählen

procedure TfrmSolutions.tcChange(Sender: TObject);
var
  s, info: String;
  p: Integer;
begin
  s := tc.Tabs[tc.TabIndex];
  p := pos(#0, s);
  if p > 0 then begin
    info := copy(s, p+1, MaxInt);
    s := copy(s, 1, p-1);
  end else
    info := '';
 ShowMessage(s + LineEnding + 'ZusatzInfo: ' + info);
end;

Ich bin nicht sicher, ob sich alle Widgetsets so verhalten wie das von mir verwendete Windows. Und wie alle Hackerlösungen kann das irgendwann nicht mehr funktionieren.

(3) Die richtige Stelle, einen Integer einem Objekt mitzugeben, wäre die Allzweck-Eigenschaft "Tag". Nur: vordergründig erzeugt TTabControl keine separaten Objekte für die Tabs. Aber wie wir oben gesehen haben, ist das nicht richtig. Es wird für jeden Tab ein TTabsheet erzeugt und in den Objects[] der Tab-Strings abgelegt. Damit kommt man auf diese
Weise an das "Tag" zum Schreiben

Code: Alles auswählen

var
  tabsheet: TTabSheet;
  i: Integer;
...
  while not Qu.Eof do
  begin
    i := tc.Tabs.Add(Qu.FieldByName('VAL').Value);
    tabsheet := TTabSheet(tc.Tabs.Objects[i]);
    tabsheet.Tag := Qu.FieldByName('COL')).AsInteger);
  ...

und so zum Auslesen

Code: Alles auswählen

var
  tabsheet: TTabsheet;
begin
  tabsheet := TTabSheet(tc.Tabs.Objects[tc.TabIndex])
  ShowMessage(IntToStr(tabsheet.Tag));

Auch das gefällt mir nicht, weil das TTabControl offenbar sehr schlampig programmiert ist und sich irgendwann sicher jemand der Komponente annehmen wird - als Folge ist nicht garantiert, dass es weiterhin ein verstecktes TabSheet geben wird.

Also? Ich würde Variante 1 nehmen.

Antworten