Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Komponenten merken und später zuweisen (https://www.delphipraxis.net/121516-komponenten-merken-und-spaeter-zuweisen.html)

stahli 29. Sep 2008 15:21


Komponenten merken und später zuweisen
 
Hallo alle,

ich habe eine Funktion, die zu einer bestimmten Textbezeichnung eine Komponente ermittelt und zurückgibt:

xyz := GetMyComponent(DescriptionName, ClassName: String; CreateFlag: Boolean): TComponent;

Existiert eine passende Komponente noch nicht, wird sie ggf. direkt in der Funktion erzeugt.
Zu jeder Bezeichnung wird die gelieferte Komponente in einer StringList gespeichert und bei nochmaliger Anfrage mit der gleichen Bezeichnung aus dieser Liste gelesen.
Jede Anfrage mit einer bestimmten Bezeichnung liefert also immer die gleiche Komponente zurück.

Nun kann es vorkommen, dass es Aufrufe gibt, in der die Komponente noch nicht existiert aber auch noch nicht erzeugt werden darf.
Hier würde ich gern eine spätere Zuweisung "vormerken"

C1 := GetMyComponent('Test1', 'TTest', False);
C2 := GetMyComponent('Test1', 'TTest', False);
C3 := GetMyComponent('Test1', 'TTest', False);

Ist eine Rückgabe derzeit nicht möglich, sollen die Parameter in einer Liste gespeichert:
'Test1' -> C1
'Test1' -> C2
'Test1' -> C3

Wird später dann durch
C4 := GetMyComponent('Test1', 'TTest', True);
die passende Komponente erzeugt und zurückgeliefert, soll diese Komponente auch C1, C2 und C3 zugewiesen werden.


Lässt sich das realisieren und wie? Müsste ich die potentielle Rückgabeadresse mit übergeben?

GetMyComponent(MY_RESULT_ADRESS: POINTER; DescriptionName, ClassName: String; CreateFlag: Boolean): TComponent;

xyz := GetMyComponent(Pointer(xyz), 'Test1', 'TTest', False): TComponent;


Mir fehlt der Ansatz, wie man da heran geht (Zeiger sind was fürchterliches)...

Das besondere Problem (für mich) ist, dass C1, C2, und C3
- normale Variablen
- Variable einer Komponente
- Propertys einer Komponente (write FMyComponent bzw. write SetMyComponent)

sein können.


Lässt sich das (so) lösen?
Danke für jede Hilfe.


Hintergrund:
Ich habe von TMemIniFile eine Komponente abgeleitet, die Binärdaten (Bilder) und auch Komponenten speichern und lesen kann. Das funktioniert alles super, nur die Verküpfungen der Komponenten untereinander sind noch nicht komplett geklärt.
Beim Speichern und Laden von Komponenten weist TExtIniFile automatisch Sections zu, die diese Komponenten dann zum schreiben und lesen ihrer Daten verwenden. Bei Bedarf werden die benötigten Komponenten automatisch erzeugt und dann veranlasst, ihre eigenen Daten einzulesen.
Die Ini-Komponente stelle ich dann hier gern bereit, falls Bedarf besteht.

PS:
Über den Sinn und Unsinn der Verwendung von Textdateien zur Datenspeicherung will ich keine unendliche Diskussion entfachen ;-) Für meine Zwecke ist das im Moment genau das richtige.


Stahli

stahli 30. Sep 2008 08:49

Re: Komponenten merken und später zuweisen
 
Ich will nochmal genauer fragen:

Das Beispiel zeigt, was ich ungefähr machen will. Hier blinkt Panel2. Durch den Schalterklick wird der Zeiger von Panel3 nun auch Panel2 zugewiesen.
Ab sofort blinkt Panel3, da die Instanzen von Panel2 und 3 jetzt identisch sind.

Delphi-Quellcode:
unit fPointertest;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;
 
type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Panel3: TPanel;
    Timer1: TTimer;
    Button1: TButton;
    procedure Timer1Timer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
type
  PObject = ^TObject;
var
  F, T: PObject;
begin
  F := @Panel2;
  T := @Panel3;
  FreeAndNil(Panel2);
  F^ := T^;
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Panel2.Visible := not Panel2.Visible;
end;
 
end.

Zu meinem Problem könnte ich mir das so vorstellen:

procedure GetCompenentPointer(var ReadComponent: TComponent; ....);
begin
...
end;

Wenn eine aktuelle Zuweisung einer gültigen Komponente momentan noch nicht möglich ist, merke ich mir dessen Adresse.
Wenn später ein Ergebnis vorliegt (wenn nämlich die Komponente eingelesen wird, auf die vorhin schon verwiesen wurde) weise ich der GemerktenAdresse^ := DenPointerDerJetztGefundenenKomponente^ zu.

Kann das so gehen - oder bin ich auf dem Holzweg?
Funktioniert das auch mit einer property, die Methoden als Getter und Setter verwendet?



Stahli

jfheins 30. Sep 2008 09:10

Re: Komponenten merken und später zuweisen
 
Ich habe zwar immernoch nicht verstanden, was du eigentlich genau willst, aber folgendes kann ich dir schonmal sagen:

1. Du kannst keinen Pointer auf eine Property zeigen lassen. Einfach weil es sein kann, dass sie read/write only ist, oder dass überhaupt keine Variable dahinter steckt ;)

Pointer auf Komponenten sind sowieso ... flüssiger als Wasser ... weil die Objektvariable (bspw. Panel2) bereits ein Pointer ist. d.h. Du kannst einfach die Objektvariable übergeben, statt noch wild herumpointern zu müssen.

Kann es sein, dass du so eine Art "Viele miteinander verknüpfte Objekte in einer Textdatei speichern und wieder lesen können"-Code schreiben möchtest?

stahli 30. Sep 2008 09:41

Re: Komponenten merken und später zuweisen
 
Zitat:

Du kannst keinen Pointer auf eine Property zeigen lassen. Einfach weil es sein kann, dass sie read/write only ist, oder dass überhaupt keine Variable dahinter steckt
Bis auf den Smily ist das eigentlich nachvollziehbar. Der Smily gehört aber so: :(

Zitat:

weil die Objektvariable (bspw. Panel2) bereits ein Pointer ist. d.h. Du kannst einfach die Objektvariable übergeben, statt noch wild herumpointern zu müssen.
Nein, das eben - nach meinem Verständnis - nicht. Zu dem Zeitpunkt bei dem ich Panel2 "verschieben" möchte, ist Panel3 noch unbekannt (nicht existent). Irgendwann kenne ich dann mal Panel3 und dann möchte ich die entsprechende Zuweisung NACHHOLEN.
Dazu brauche ich doch die ADRESSE des Pointers auf Panel2 und muss diese 4 Bytes jetzt auf Panel3 zeigen lassen. Panel2 selbst (und vielleicht die anderen 5 Komponentenzeiger, die noch auf eine Zuweisung auf Panel3 warten) sind jetzt nicht vmehr bekannt. Ich kann lediglich die entsprechenden Adressen der Pointer auf der Liste heraussuchen und diese dann auf Panel3 zeigen lassen.

Delphi-Quellcode:
Kann es sein, dass du so eine Art "Viele miteinander verknüpfte Objekte in einer Textdatei speichern und wieder lesen können"-Code schreiben möchtest?
Das trifft den Pudel auf den Kopf. Das Erzeugen der Komponenten funktioniert auch. Nur der Verweis auf eine Komponente, die erst später erzeugt wird, funktioniert noch nicht.
Ich hatte das alles schon mal mit einer Stream-Speicherung gelöst, indem ich den Komponenten temp. ID´s vergeben hatte und nach dem Datei-Einlesen alle Zuordnungen über eine Suche im Speicher realisiert habe.
Aus verschiedenen Gründen habe ich jetzt auf eine Ini-Speicherung umgestellt und wollte die Zuordnungen möglichst eleganter lösen. Mit "normalen" Komponenten würde das sicher auch funktionieren - aber vermutlich wohl nicht mit Propertys... :evil:

Stahli

jfheins 30. Sep 2008 09:57

Re: Komponenten merken und später zuweisen
 
Darf man - aus reiner Neugier natürlich - fragen, wartum du nicht das bereits vorhandene, ,und von Delphi für die dfm-Dateien benutzte Streaming verwendest ?

So was in der Art macht aud die Hier im Forum suchendpcollection ;)

Wenn du es gerne selber mamchen möchtest; würde ich so vorgehen, dass ich erstmal alle Objekte auslese (ohne Verknüpfungen herzustellen) und dann die Obekte die Verknüpfungen erneut herstellen lasse.

Alternativ (das hört sich nach dem an, was du schon probiert hattest) Wenn du auf etwas stößt, dass du noch nicht gelesen hast, ne ID vergeben und am Ende kann sich dann jedes Objekt (unter Angabe der ID) sein richtiges Objekt "abholen" ...

Alles nicht so einfach wenns derart universell sein soll :stupid:

stahli 30. Sep 2008 10:29

Re: Komponenten merken und später zuweisen
 
Zitat:

Darf man - aus reiner Neugier natürlich - fragen, wartum du nicht das bereits vorhandene, ,und von Delphi für die dfm-Dateien benutzte Streaming verwendest ?
Warum Du fragst ist eigentlich egal ;-)
Ich hatte zum Einen keinen wirklichen Zugang zu den Streaming-Funktionen gefunden. Zwar habe ich verstanden, wie das grundsätzlich funktioniert, aber das für meine Zwecke zu verwenden erschien mir zu kompliziert und nicht genau passend.
- Mit meiner Version bin ich nicht an bestimmte Reihenfolgen gebunden.
- Jede Komponente kann ihre Daten lesen und schreiben, wenn sie es für richtig hält.
- Es können beliebige Daten geschrieben und gelesen werden (nicht nur propertys).
(nach meinem Verständnis geht das mit dem dfm-Streaming nicht)

Jedenfalls war der Aufwand, eine eigene Ini-Komponente abzuleiten nicht wirklich groß und ich bin mit dem Ergebnis (bis auf die Verknüpfungen bisher) sehr zufrieden...

Zitat:

Wenn du es gerne selber mamchen möchtest; würde ich so vorgehen, dass ich erstmal alle Objekte auslese (ohne Verknüpfungen herzustellen) und dann die Obekte die Verknüpfungen erneut herstellen lasse.
Alternativ (das hört sich nach dem an, was du schon probiert hattest) Wenn du auf etwas stößt, dass du noch nicht gelesen hast, ne ID vergeben und am Ende kann sich dann jedes Objekt (unter Angabe der ID) sein richtiges Objekt "abholen" ...
Alles nicht so einfach wenns derart universell sein soll
So habe ich es bei meiner Stream-Variante getan und werde es jetzt dann auch so machen. Mit so einer "Pointerumbiegung" hätte ich das nur etwas universeller und einfacher lösen können - schade, dass es mit propertys so nicht geht :-(


Die Datei sieht übrigens dann ungefähr so aus (Bild gekürzt):

Zitat:

[Club]
ID1=39597,7929584838
ID2=39597,7966440509
HeadingLong=BV Halle 06 e.V.
HeadingShort=BV Halle 06
HeadingAbbr=HAL
EMail=
Players.Item1=Component(DPlayer1) // diese Einträge
Players.Item2=Component(DPlayer2) // werden automatisch
Players.Item3=Component(DPlayer3) // erzeugt, ebenso
Players.Item4=Component(DPlayer4) // die entsprechenden
Players.Item5=Component(DPlayer5) // Sections

[Component(DPlayer1)]
{ClassName}=TDPlayer
{Owner}=
Person.ID1=39597,7929584838
Person.ID2=39597,7969948148
Person.FirstName=André
Person.LastName=Günther
Person.NickName=Die Lippe
Person.ShortName=
Person.BirthDay=29.05.1988
Person.Kind=m
Person.Picture=Base64(Qk3GXwEAAA.................. ...................AAADYAAAA)
PersonClub.ClubLeader=0
PersonClub.HomeTeamNo=0
PersonClub.HomeTeamPos=0
PersonClub.HomeTeamLeader=0
PersonTournament.Participation=0

[Component(DPlayer2)]
{ClassName}=TDPlayer
{Owner}=
Person.ID1=39597,7929584838
Person.ID2=39597,7982654861
Person.FirstName=André
Person.LastName=Stahl
Person.NickName=Printer
Person.ShortName=
Person.BirthDay=29.05.1988
Person.Kind=m
Person.Picture=Base64(Qk3GXwEAAA.................. ...................AAADYAAAA)
PersonClub.ClubLeader=0
PersonClub.HomeTeamNo=0
PersonClub.HomeTeamPos=0
PersonClub.HomeTeamLeader=0
PersonTournament.Participation=0
Die zu benutzenden Methoden sind:
TExtIniFile.WriteComponent(...);
TExtIniFile.WriteComponentList(...);
TExtIniFile.ReadComponent(...);
TExtIniFile.ReadComponentList(...);
Es werden also auch Listen von Komponenten gespeichert und wieder hergestellt.

TExtIniFile erzeugt dann automatisch die entsprechenden Einträge und Sections und veranlasst die Komponenten dann, diese beim Speichern/Lesen zu verwenden.

Für Binädaten kann man
TExtIniFile.WriteBase64(...);
TExtIniFile.ReadBase64(...);
nutzen.

Was noch nicht umgesetzt ist, ist eben
TExtIniFile.WriteComponentPOINTER(...);
TExtIniFile.ReadComponentPOINTER(...);
um Verküpfungen wieder herzustellen.


Stahli

stahli 30. Sep 2008 12:12

Re: Komponenten merken und später zuweisen
 
Ich werde eine Methode
TExtIniFile.WriteComponentPointerProperty(Componen t, 'PropertyName', ...);
TExtIniFile.ReadComponentPointerProperty(Component , 'PropertyName', ...);
implementieren.

Alle vorerst gescheiterten Zuweisungsversuche könnten dann in einer Liste gesammel werden (Component, PropertyName, Zielkomponenten-Bezeichnung).
Später kann ich über IsPublishedProp und SetPropValue jederzeit direkt auf diese Eigenschaften zugreifen und die Werte später zuweisen.
Das sollte machbar sein und ich kann auf temporäre ID´s bzw. einen zweiten Einlesedurchlauf verzichten...

Eine Funktion für das Setzen "einfacher Pointer" (Variablen) benötige ich derzeit nicht, aber das könnte über die oben beschriebene Verfahrensweise (Adresse des Pointers merken) auch realisierbar sein.


Mit optimistischen Grüßen
Stahli

stahli 30. Sep 2008 20:46

Re: Komponenten merken und später zuweisen
 
Mannooo!

Jetzt bin ich fast fertig, damit und dann lässt sich eine TComponent so nicht zuweisen :-(

Delphi-Quellcode:
procedure TExtIniFile.ReadComponentProperty(PropertyComponent: TComponent;
  PropertyName, Section, Ident: String);
var
  S: String;
  CN: String;
  CCN: String;
  P: Integer;
  RC: TComponent;
  ExistFlag: Boolean;
begin
  PropertyFlag := True;
  RC := nil;
  S := ReadString(Section, Ident, '');
  if (S <> '') and (S <> 'Component(nil)') then
  begin
    P := Pos('(', S);
    Delete(S, 1, P);
    P := Pos(')', S);
    CN := Copy(S, 1, Pred(P));
    CCN := ReadString('Component(' + CN + ')', '{ClassName}', '');
    ExistFlag := ExistComponentName(CN);
    if ExistFlag then
    begin
      RC := FoundComponent(CN);
    end
    else
    begin
      PropertyList.AddObject(CN + '=' + PropertyName, PropertyComponent);
    end;
  end;
  if (IsPublishedProp(PropertyComponent, PropertyName)) and (Assigned(RC)) then
  begin
    SetPropValue(PropertyComponent, PropertyName, RC); // ==> Es gibt keine überladene Version von 'SetPropValue', die man mit diesen Argumenten aufrufen kann
{
  TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat,
    tkString, tkSet, tkClass, tkMethod, tkWChar, tkLString, tkWString,
    tkVariant, tkArray, tkRecord, tkInterface, tkInt64, tkDynArray);
}
  end;
  PropertyFlag := False;
end;
Lässt sich einer Property eine Komponente zuweisen, wenn ich nur den Propertynamen habe???

Sonst kann ich wohl nochmal von neuem anfangen :-(

Stahli

Apollonius 30. Sep 2008 20:58

Re: Komponenten merken und später zuweisen
 
Einfach mal in TypInfo.pas stöbern: Da findet sich eine Prozedur namens SetObjectProp mit Parametern vom Typ TObject, String und nochmal TObject. Das ist doch exakt was du willst.

stahli 30. Sep 2008 21:11

Re: Komponenten merken und später zuweisen
 
GANZ exakt :-)
Danke!


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:16 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz