Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Klasseninstanz zur Laufzeit bestimmen (https://www.delphipraxis.net/186082-klasseninstanz-zur-laufzeit-bestimmen.html)

Delbor 1. Aug 2015 17:07

Delphi-Version: XE4

Klasseninstanz zur Laufzeit bestimmen
 
Hi zusammen
Ich habe eine Klasse, der ich (Schrift-)Attribute zuweisen kann, die ich per eigenem Frame einstelle. Den Frame habe ich hier vorgestellt. Die Klasse sieht ziemlich genau aus, wie der auf der verlinkten Seite vorgestellte Record - eine Klasse ist das Ding nur, weil es einer Objektliste und einer Combobox hinzugefügt wird:
Delphi-Quellcode:
  TAttributsClass = Class(TPersistent)
     public
      BackGround : TColor;
      ForeGround : TColor;
      StyleBold: Boolean;
      StyleItalic : Boolean;
      StyleUnderLine : Boolean;
      StyleStrikeOff : Boolean;
      AttributName: String;
  end;
Instanzen dieser Klasse erstelle ich so:
Delphi-Quellcode:
constructor TCssAttriTLBXFrame.Create(AOwner: TComponent);
begin
  inherited;
  FCssAttributsList := TDataObjectList<TAttributsClass>.Create();
  FCssAttributsList.OwnsObjects := True;
  CreateAttribute(FCommentAttri, 'Kommentare');          
  CreateAttribute(FPropertyAttri, 'Eigenschaften');      
  CreateAttribute(FKeyAttri, 'Schlüsselworte');          
  CreateAttribute(FSpaceAttri, 'Leerzeichen');          

  CreateAttribute(FStringAttri, 'Strings');              
  CreateAttribute(FColorAttri, 'Farben');              
  CreateAttribute(FNumberAttri, 'Zahlen');            
  CreateAttribute(FSymbolAttri, 'Symbole');            

  CreateAttribute(FTextAttri, 'Text');                
  CreateAttribute(FValueAttri, 'Werte');              
  CreateAttribute(FUndefPropertyAttri, 'Undefinierte Eigenschaften');
  CreateAttribute(FImportantPropertyAttri, 'Wichtige Eigenschaften');

end;
Der erste Parameter bezeichnet dabei die Instanz, die erzeugt werden soll, der zweite den String, der in der Combobox angezeigt wird.

Nun geht es darum, die Werte, die ich zB. aus einer Colorbox auslese, im Closeup per Event weiterzureichen.
Gefeuert werden die Events, wenn ein Wert gewählt wurde, zB. wenn eine Checkbox geklickt wird oder beim CloseUp einer Colorbox:
Delphi-Quellcode:
procedure TCssAttriTLBXFrame.CmbxValueForegroundColorCloseUp(Sender: TObject);
begin
   FActiveAttribut := TAttributsClass(CmbxAttributes.Items.Objects[CmbxAttributes.ItemIndex]);
  Label1.Caption := FActiveAttribut.Name;
//   if Assigned(FActiveAttribut) then
//     FActiveAttribut(FActiveAttribut);
end;
Die Eventpropertys sind wie folgt deklariert:
Delphi-Quellcode:
    property CSSCommentEvent: TCSSCommentEvent read FCSSCommentEvent write FCSSCommentEvent;
    property CssPropertyEvent: TCssPropertyEvent read FCssPropertyEvent write FCssPropertyEvent;
    property CssKeyEvent: TCssKeyEvent read FCssKeyEvent write FCssKeyEvent;
    property CssSpaceEvent: TCssSpaceEvent read FCssSpaceEvent write FCssSpaceEvent;

    property CssStringEvent: TCssStringEvent read FCssStringEvent write FCssStringEvent;
    property CssColorEvent: TCssColorEvent read FCssColorEvent write FCssColorEvent;
    property CssNumberEvent: TCssNumberEvent read FCssNumberEvent write FCssNumberEvent;
    property CssSymbolEvent: TCssSymbolEvent read FCssSymbolEvent write FCssSymbolEvent;

    property CssTextEvent: TCssTextEvent read FCssTextEvent write FCssTextEvent;
    property CssValueEvent: TCssValueEvent read FCssValueEvent write FCssValueEvent;
    property CssUndefPropertyEvent: TCssUndefPropertyEvent read FCssUndefPropertyEvent write FCssUndefPropertyEvent;
    property CssImportantPropertyEvent: TCssImportantPropertyEvent read FCssImportantPropertyEvent write FCssImportantPropertyEvent;
Nun brauche ich ja beim Feuern des Events den Eventtip, der gefeuert werden soll. Bloss: Wie bestimme ich den? Dazu brauche ich ja die Instanz meiner Attributklasse.

Gruss
Delbor

Dejan Vu 2. Aug 2015 06:42

AW: Klasseninstanz zur Laufzeit bestimmen
 
Wieso sind deine Eventhandler eigentlich alle unterschiedlich deklariert? Reicht nicht ein Typ?, z.B.
Delphi-Quellcode:
TAttributEvent = Procedure (Sender : TObject; Attribut : TAttributsClass) of Object;
Na ja, wie Du meinst. Wenn das so wäre, dann reicht folgender Code.
Delphi-Quellcode:
Function TMyForm.CreateEvent(Attribut : TAttributsClass) : TAttributEvent;
begin
  if Attribut=FCommentAttri then result := FCSSCommentEvent
  else if Attribut=FPropertyAttri then Result := FCSSPropertyEvent
  else if ...
  ...
  else Raise Exception.Create('Unknown Attribut: '+Attribut.Name);
end;

Procedure TMyForm.FireEvent(Attribut : TAttributsClass);
Var
  Event : TAttributEvent;

begin
  Event := CreateEvent(Attribut);
  CallEventHandler(Event, Attribut);
end;

Procedure TMyForm.CallEventHandler (Event : TAttributEvent; Attribut : TAttributsClass);
Begin
  if Assigned (Event) Then
    Event(Self, Attribut);
end;
Ja, das ist eine ziemlich lange if-else-Folge. Sieht blöd aus, ist aber normal. Da Deine Eventhandler alle individuell deklariert sind, kannst Du das nette 'CallEventHandler' nicht verwenden, sondern musst die 'If Assigned(Event)' Abfrage für jeden Event neu implementieren.

Noch einfacher geht es übrigens mit einem einfachen
Delphi-Quellcode:
TNotifyEvent
, denn wenn das 'CommentEvent' gefeuert wird, ist ja klar, das mit den CommitAttributen etwas los ist, ergo muss man das Attribut nicht übergeben.
Delphi-Quellcode:
Function TMyForm.CreateEvent(Attribut : TAttributsClass) : TNotifyEvent;
begin
  if Attribut=FCommentAttri then result := FCSSCommentEvent
  else if Attribut=FPropertyAttri then Result := FCSSPropertyEvent
  else if ...
  ...
  else Raise Exception.Create('Unknown Attribut: '+Attribut.Name);
end;

Procedure TMyForm.FireEvent(Attribut : TAttributsClass);
Var
  Event : TNotifyEvent;

begin
  Event := CreateEvent(Attribut);
  CallEventHandler(Event);
end;

Procedure TMyForm.CallEventHandler (Event : TNotifyEvent);
Begin
  if Assigned (Event) Then
    Event(Self);
end;

Sir Rufo 2. Aug 2015 07:11

AW: Klasseninstanz zur Laufzeit bestimmen
 
Nun ja, bei XE4 gibt es natürlich auch schon nettere Arten, damit umzugehen
Delphi-Quellcode:
unit Unit1;

interface

uses
  {System.}Generics.Collections,
  {System.}SysUtils;

type
  TObjectHandler = class abstract
  private type
    TAction = TProc<TObject>;
  private
    FRoutes: TDictionary<TClass, TAction>;
  protected type
    TRoute<T> = procedure( Argument: T ) of object;
  protected
    procedure RegisterRoute<T: class>( ARoute: TRoute<T> );
    procedure DoRaise( Argument: TObject );
  end;

  TFoo = class

  end;

  TBar = class

  end;

  TFooBar = class( TObjectHandler )
  private
    procedure Apply( Argument: TFoo ); overload;
    procedure Apply( Argument: TBar ); overload;
  public
    constructor Create( );

    procedure Handle( Argument: TObject );
  end;

implementation

{ TObjectHandler }

procedure TObjectHandler.DoRaise( Argument: TObject );
var
  LAction: TAction;
begin
  if FRoutes.TryGetValue( Argument.ClassType, LAction ) then
    LAction( Argument )
  else
    raise ENotImplemented.CreateFmt( 'Handler für %s fehlt', [ Argument.ClassName ] );
end;

procedure TObjectHandler.RegisterRoute<T>( ARoute: TRoute<T> );
begin
  FRoutes.Add( T,
    procedure( Argument: TObject )
    begin
      ARoute( Argument as T );
    end );
end;

{ TFooBar }

procedure TFooBar.Apply( Argument: TFoo );
begin

end;

procedure TFooBar.Apply( Argument: TBar );
begin

end;

constructor TFooBar.Create;
begin
  inherited Create;
  RegisterRoute<TFoo>( Apply );
  RegisterRoute<TBar>( Apply );
end;

procedure TFooBar.Handle( Argument: TObject );
begin
  DoRaise( Argument );
end;

end.

Dejan Vu 2. Aug 2015 14:08

AW: Klasseninstanz zur Laufzeit bestimmen
 
Zu sehr verwirren wollte ich den TE nun auch nicht.

'Case' (oder hier: if/else-Schlangen) sind zwar 'böse', aber in Fabrikmethoden durchaus erlaubt. Denn es ist ja nun kein Mehrwert ggü dem if/else bzw. 'case' (geht hier leider nicht), eine 1:1 Abbildung in eine Liste (oder Dictionary) zu stopfen.

Obwohl.. bei endlose if/else-Wicklungen würde ich nicht drauf beharren.

Sir Rufo 2. Aug 2015 14:20

AW: Klasseninstanz zur Laufzeit bestimmen
 
Wenn ich CleanCode haben möchte, dann nehmen ich so ein Routing-Dictionary.

(Gerade fällt mir auf, dass die Basis-Klasse keinen Destruktor hat ... ts ts ts)

Delbor 2. Aug 2015 14:39

AW: Klasseninstanz zur Laufzeit bestimmen
 
Hi zusammen

Vielen Dank für eure Antworten!
@Dejan Vu:
Delphi-Quellcode:
procedure TCssAttriTLBXFrame.CmbxAttributesCloseUp(Sender: TObject);
begin
   FActiveAttribut := TAttributsClass(CmbxAttributes.Items.Objects[CmbxAttributes.ItemIndex]);
  Label1.Caption := FActiveAttribut.ClassName; //FActiveAttribut.AttributName;      CmbxAttributes.Items[CmbxAttributes.ItemIndex];

end;
Hier entspricht FActiveAttribut deiner Variablen 'Attribut' in der Prozedur CreateEvent. Als ClassName wird mir hier allerdings TAttributClass zurückgegeben. Gebe ich im Label FActiveAttribut.AttributName aus, erhalte ich allerdings den von mir an die Instanz übergebenen String. Das bedeutet aber auch: die Info über die Klasseninstanz ist in meiner Feldvariablen enthalten - das zeigt ja auch dein Code mit der Abfrage:
Delphi-Quellcode:
  if Attribut=FCommentAttri then result := FCSSCommentEvent
Deshalb denke ich, die Info ist im Property 'Tipinfo' von Tpersistent-Nachfolgern enthalten. Die Frage ist (oder war) nur: wie komme ich da ran?
Zitat:

...denn wenn das 'CommentEvent' gefeuert wird, ist ja klar, das mit den CommitAttributen etwas los ist, ergo muss man das Attribut nicht übergeben.
Doch, muss ich, da die Klasse die neuen, und wenn die nicht geändert wurden, die alten Werte enthält. Die Synhighlither enthalten propertys gleichen Namens wie die von mir erstellten Instanzen, sind aber vom Tip der Klasse TSynHighlighterAttributes. So zum Beispiel für TSynCssSyn:
Delphi-Quellcode:
    fCommentAttri: TSynHighlighterAttributes;
    fPropertyAttri: TSynHighlighterAttributes;
    fKeyAttri: TSynHighlighterAttributes;
    fSpaceAttri: TSynHighlighterAttributes;

    fStringAttri: TSynHighlighterAttributes;
    fColorAttri: TSynHighlighterAttributes;
    fNumberAttri: TSynHighlighterAttributes;
    fSymbolAttri: TSynHighlighterAttributes;

    fTextAttri: TSynHighlighterAttributes;
    fValueAttri: TSynHighlighterAttributes;
    fUndefPropertyAttri: TSynHighlighterAttributes;
    fImportantPropertyAttri: TSynHighlighterAttributes;
Ein Auszug aus der dfm:
Delphi-Quellcode:
    AndAttri.Background = clRed
    CommentAttri.Foreground = clOlive
    CommentAttri.Style = [fsBold, fsItalic]
    IdentifierAttri.Foreground = clBlue
    IdentifierAttri.Style = [fsBold, fsUnderline]
    KeyAttri.Foreground = clBlue
    SpaceAttri.Foreground = clMoneyGreen
    SpaceAttri.Style = [fsUnderline]
    SymbolAttri.Foreground = clGray
    TextAttri.Foreground = clRed
    TextAttri.Style = [fsItalic]
    UndefKeyAttri.Background = clYellow
    ValueAttri.Background = clSilver
Das sind die Werte, die meine Klasse übergeben muss.

Delphi-Quellcode:
Procedure TMyForm.CallEventHandler (Event : TAttributEvent; Attribut : TAttributsClass);
Begin
  if Assigned (Event) Then
    Event(Self, Attribut);
end;
Das heisst: im Eventhandler, der diesen Event entgegennimmt, muss ich erstmal die übergebene Instanz identifizieren. Also eigentlich das Gegenstück zu deiner Prozedur CreateEvent schreiben und dann an passender Stelle die Zuweisung machen - pro identifizierter Instanz je einmal. Oder ich kann die 'passende Stelle' in jeweils eine eigene Prozedur auslagern. Das wären dann 9 - 12 Zuweisungsproceduren, gleichviel, wie einzelne Eventhandler nötig wären.
Einzig bei den 'Kanonieren' (die das Event abfeuern) wäre was einzusparen.

Inzwischen habe ich deinen neuen Beitrag mitbekommen, Dejan Vu.
Zitat:

'Case' (oder hier: if/else-Schlangen) sind zwar 'böse', aber in Fabrikmethoden durchaus erlaubt. Denn es ist ja nun kein Mehrwert ggü dem if/else bzw. 'case' (geht hier leider nicht), eine 1:1 Abbildung in eine Liste (oder Dictionary) zu stopfen.
Und damit sprichst du eigentlich genau das an, was mir kürzlich in den Sinn gekommen ist: meine Attributklassen befinden sich alle in einer Objectliste. Es reicht also, diese zu durchlaufen und in einer Prozedur auf die Klasseninstanz zu prüfen.

Zitat:

(Gerade fällt mir auf, dass die Basis-Klasse keinen Destruktor hat ... ts ts ts)
UUps!! - Du meinst sicher meine...

Gruss
Delbor

Sir Rufo 2. Aug 2015 14:48

AW: Klasseninstanz zur Laufzeit bestimmen
 
Nein, mein
Delphi-Quellcode:
TObjectHandler
hat keinen, obwohl dort das Dictionary aufgeräumt werden muss.

Dejan Vu 2. Aug 2015 15:59

AW: Klasseninstanz zur Laufzeit bestimmen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1310682)
Wenn ich CleanCode haben möchte, dann nehmen ich so ein Routing-Dictionary

Kann man. Muss man nicht.
Zitat:

Zitat von Robert C. Martin in 'Clean Code'
...is to bury the switch statement in the basement of an ABSTRACT FACTORY and never let anyone see it. The factory will use the switch statement to create appropriate instances ... My general rule for switch statements is that they can be tolerated if they appear only once..


idefix2 2. Aug 2015 16:53

AW: Klasseninstanz zur Laufzeit bestimmen
 
Zitat:

Zitat von Dejan Vu (Beitrag 1310678)
'Case' (oder hier: if/else-Schlangen) sind zwar 'böse'

Was, jetzt ist case also auch schon böse geworden?

Man kanns übertreiben...

Sir Rufo 2. Aug 2015 17:08

AW: Klasseninstanz zur Laufzeit bestimmen
 
Zitat:

Zitat von idefix2 (Beitrag 1310697)
Zitat:

Zitat von Dejan Vu (Beitrag 1310678)
'Case' (oder hier: if/else-Schlangen) sind zwar 'böse'

Was, jetzt ist case also auch schon böse geworden?

Man kanns übertreiben...

Bitte auch den Kontext lesen und im selbigen verstehen.

Delbor 2. Aug 2015 19:14

AW: Klasseninstanz zur Laufzeit bestimmen
 
Hi zusammen

Sorry, wenn ich auf Sir Rufos Vorschlag bisher nicht eingegangen bin; der Grund liegt vor allem darin, dass ich bisher sehr wenig mit Generics arbeite, da ich die Dinger zu wenig durchschaue.
Eigentlich ist die einzige generische Klasse, die ich bisher benutze, eine Objectliste, die mir einst DeddyH vorgeschlagen hat. Ein weiterer seiner Vorschläge betraf die Verwendung einer Class Factory.Und so sieht das Ding heute bei mir aus :

Delphi-Quellcode:
uses Generics.Collections, Vcl.Forms, System.Classes, System.SysUtils;

type
  EFrameNotRegistered = class(Exception);
  TFrameClass = class of TFrame;

  TFrameFactory = class abstract
  strict private
    class var FAssociations: TDictionary<string, TFrameClass>;
    class constructor Create;
    class destructor Destroy;
  public
    class procedure RegisterFrameClass(const Extension: string; FrameClass: TFrameClass);
    class function GetRegisteredFrameClass(const Extension: string; AOwner: TComponent): TFrame;
  end;

implementation

{ TFrameFactory }

class constructor TFrameFactory.Create;
begin
  FAssociations := TDictionary<string, TFrameClass>.Create;
end;

class destructor TFrameFactory.Destroy;
begin
  FAssociations.Free;
end;

class function TFrameFactory.GetRegisteredFrameClass(const Extension: string;
  AOwner: TComponent): TFrame;
  var AFrameClass: TFrameClass;  //TCustomFrameClass
begin
  if FAssociations.TryGetValue(AnsiLowerCase(Extension), AFrameClass) then
    Result := AFrameClass.Create(AOwner)
  else
    raise EFrameNotRegistered.CreateFmt('Für die Endung %s ist keine Frameklasse registriert.', [Extension]);
end;

class procedure TFrameFactory.RegisterFrameClass(const Extension: string;
  FrameClass: TFrameClass);
begin
  FAssociations.AddOrSetValue('.' + AnsiLowerCase(Extension), FrameClass);
end;

end.
Meinen Frames muss ich dann noch folgendes verpassen:
Delphi-Quellcode:
initialization
  TFrameFactory.RegisterFrameClass('css', TCSSFrame);
Dein Vorschlag ist offenbar das generische Gegenstück zu dieser Fabrikklasse, und wenn mich meine bisherigen Kenntnisse der Generics nicht täuschen, könnte ich da jede Klasse registrieren, die, in deinem Beispiel, von TFoo, bzw. TBar erbt oder selbst von einem dieser Typen ist.
Somit könnte ich da jeden meiner Eventhandler registrieren. Hab ich das richtig verstanden?

Gruss
Delbor

Sir Rufo 2. Aug 2015 19:25

AW: Klasseninstanz zur Laufzeit bestimmen
 
Genau so isses :)

Delbor 3. Aug 2015 19:24

AW: Klasseninstanz zur Laufzeit bestimmen
 
Hi zusammen

Wie man nur so blind sein kann!! Nochmal zur Erinnerung die CreateAufrufe und die Createprozedur selbst:
Delphi-Quellcode:
constructor TJavaScriptAttriTLBXFrame.Create(AOwner: TComponent);
begin
  inherited;
  FJavaScriptAttributsList := TDataObjectList<TAttributsClass>.Create();
  FJavaScriptAttributsList.OwnsObjects := True;

  CreateAttribute(FCommentAttri, 'Kommentare', 'FCommentAttri');           //    fCommentAttri: TSynHighlighterAttributes;
  CreateAttribute(FIdentifierAttri, 'Bezeichner', 'FIdentifierAttri');       //    fPropertyAttri: TSynHighlighterAttributes;
  CreateAttribute(FKeyAttri, 'Schlüsselworte', 'FKeyAttri');          //    fKeyAttri: TSynHighlighterAttributes;

  CreateAttribute(FNonReservedKeyAttri, 'Nicht reservierte Schlüssel', 'FNonReservedKeyAttri');           //    fSpaceAttri: TSynHighlighterAttributes;
  CreateAttribute(FEventAttri, 'Ereignisse', 'FEventAttri');              //    fStringAttri: TSynHighlighterAttributes;
  CreateAttribute(FNumberAttri, 'Zahlen', 'FNumberAttri');              //    fNumberAttri: TSynHighlighterAttributes;


  CreateAttribute(FSpaceAttri, 'Leerzeichen', 'FSpaceAttri');                //    fColorAttri: TSynHighlighterAttributes;
  CreateAttribute(FStringAttri, 'Strings', 'FStringAttri');                 //    fTextAttri: TSynHighlighterAttributes;
  CreateAttribute(FSymbolAttri, 'Symbole', 'FSymbolAttri');             //    fSymbolAttri: TSynHighlighterAttributes;
end;

destructor TJavaScriptAttriTLBXFrame.Destroy;
begin
   FJavaScriptAttributsList.Free;
  inherited;
end;

procedure TJavaScriptAttriTLBXFrame.CreateAttribute(var AAttrib: TAttributsClass; const AName: string; AInstanz : String);
begin
  AAttrib:= TAttributsClass.Create(Self);
  AAttrib.AttributName := AName;
  AAttrib.InstanzName := AInstanz;
  FJavaScriptAttributsList.Add(AAttrib);
  CmbxAttributes.Items.AddObject(AName,TObject(AAttrib));
  Application.ProcessMessages;
end;
Damit wird bei jedem Aufruf eine Instanz der Klasse TAttributsClass erzeugt und nicht eine Klasseninstanz FCommentAttri - somit kann ich auch nicht auf eine Instanz FCommentAttri zugreifen. Einfach, nicht?

Um die richtigen Instanzen zu erzeugen, müsste ich wohl eher so etwas macen:
Delphi-Quellcode:
procedure TJavaScriptAttriTLBXFrame.CreateAttribute(var AAttrib: TAttributsClass; const AName: string; AInstanz : String);
begin
  AAttrib:= AAttrib.Create(Self);
  AAttrib.AttributName := AName;
  AAttrib.InstanzName := AInstanz;
  FJavaScriptAttributsList.Add(AAttrib);
  CmbxAttributes.Items.AddObject(AName,TObject(AAttrib));
  Application.ProcessMessages;
end;
Wobei dies auch nicht ganz stimmt: Der rechte Teil muss ein Klassenbezeichner sein - der muss aber zum Instanzbezeichner passen. Das property Instanzname ist auch nicht das gelbe vom Ei...
Das heisst nichts anderes, als dass es einige von TAttributsClass abgeleitete Klassen geben wird, wie zum Beispiel TCommentAttri. Die Erzeugung ist dann:
Delphi-Quellcode:
FCommentAttri:= TCommentAttri.Create
Damit habe ich ohne Verrenkungen zugriff auf die richtige Instanz.

Gruss
Delbor

Delbor 4. Aug 2015 09:45

AW: Klasseninstanz zur Laufzeit bestimmen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi zusammen

Die Idee aus meinem vorigen Beitrag war wirklich nicht schlecht - sie liefert eine Antwort auf die Frage, die der Threadtitel vorgibt - aber sie ist noch weniger das Gelbe vom Ei, wie das Property 'InstanzName' der Klasse TAttributsClass, da sie zu einem, wie ich meine, ziemlich seltsamen Konstrukt führt:
Delphi-Quellcode:
  TAttributsClass = Class(TPersistent)
     public
      BackGround : TColor;
      ForeGround : TColor;
      StyleBold: Boolean;
      StyleItalic : Boolean;
      StyleUnderLine : Boolean;
      StyleStrikeOff : Boolean;
      AttributName: String;
      InstanzName: String;
      Constructor Create(AOwner: TComponent);
      Destructor Destroy; override;
  end;

  TJavaScriptCommentClass = Class(TAttributsClass);
  TJavaScriptIdentifierClass = Class(TAttributsClass);
  TJavaScriptKeyClass = Class(TAttributsClass);

  TJavaScriptNonReservedKeyClass = Class(TAttributsClass);
  TJavaScriptEventClass = Class(TAttributsClass);
  TJavaScriptNumberClass = Class(TAttributsClass);
//
  TJavaScriptSpaceClass = Class(TAttributsClass);
  TJavaScriptStringClass = Class(TAttributsClass);
  TJavaScriptSymbolClass = Class(TAttributsClass);
Dabei führen die von TAttributsClass abgeleiteten Klassen keinerlei neue Member ein, weder Eigenschaften Methoden oder Ereignisse - wobei ich mir schon überlegt habe, ob die Dinger nicht selbst ein Event abfeuern könnten...
Aber ich habe etwas viel besseres gefunden..

Ein Test in einem meiner Synedit-Frames brachte das gewünschte Resultat, ersichtlich im angehängten Jpeg:

Delphi-Quellcode:
procedure TCSSFrame.SynEdit1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  LContext: TRttiContext; LType: TRttiType; LProperty: TRttiProperty;
  LMethod: TRttiMethod; LField: TRttiField;
begin
  if Self.SynEdit1.SelText <> '' then begin
    Label1.Caption := SynEdit1.SelText;
      Label1.Caption := Label1.Caption + ' SynEdit1.TabWidth := '+ IntToStr(SynEdit1.TabWidth);
    if assigned(FOnSelectText) then    // Dieser Event wird gefeuert,
      FOnSelectText(Self);             // wenn Text markiert wird.
  end;
  LContext := TRttiContext.Create;
    try
      LType := LContext.GetType(TSynCssSyn);
      SynEdit1.lines.Add(LType.ToString);
      for LProperty in LType.GetProperties do
      begin
        SynEdit1.lines.Add (LProperty.ToString);
      end;
    finally
    LContext.Free;
  end;
end;
Wie der Anhang zeigt, liefert mir das alle Propertys als String. Um meine neuen Einstellungen aus meinem Frame richtig zuordnen zu können, brauche ich entweder einen Kalssenbezeichner, der dem Probertynamen entspricht oder einen String, den ich mitt dem als String vorliegenden Propertynamen vergleichen kann.
Natürlich muss ich aus der sich ergebenden Liste noch den (Teil-)String filtern, den ich in TAttributsClass.Instanzname übergebe. Aber das dürfte wohl kaum ein Problem sein.
Ein weiterer Effekt: Ich brauche zur Übergabe noch genau einen Eventtyp.

Oder gibts noch eine bessere Lösung?

Gruss
Delbor


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:30 Uhr.

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