Delphi-PRAXiS
Seite 4 von 5   « Erste     234 5      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Routine mit Namen aufrufen (https://www.delphipraxis.net/184033-routine-mit-namen-aufrufen.html)

Sigi55 22. Feb 2015 20:47

AW: Routine mit Namen aufrufen
 
Hallo,

Mann-O-Mann, da hab ich ja was losgetreten ...

Ich würd ja gern den Ansatz von Ha-Jö testen, aber ich kann das
nicht ausprogrammieren ..., das ist für mich zu weit im Eingemachten.

Mit dem Ansatz von BadenPower komm ich klar.

Vielleicht hat ja jemand Lust, Zeit, Ruhe und Muße die bessere Lösung
als fertiges Beispiel zu bauen ??

Gruß

Sigi

hanvas 23. Feb 2015 15:57

AW: Routine mit Namen aufrufen
 
Zitat:

Zitat von Sigi55 (Beitrag 1291030)

Ich würd ja gern den Ansatz von Ha-Jö testen, aber ich kann das
nicht ausprogrammieren ..., das ist für mich zu weit im Eingemachten.

Ich hatte Dir doch schon fast alles geliefert. Hier nochmal die Komfortvariante.

Delphi-Quellcode:

unit jRegister;
interface
uses classes;

type TJobRegister = class(TComponent)
     private
      FRegister : TStringList;
     public
      Constructor Create(aOwner : TComponent);                                 override;
      Destructor Destroy;                                                     override;

      procedure  RegisterObjectMethods
       (Instance : TObject; const methods : TStrings);                         virtual;

      procedure  RegisterObjectMethodByName
       (const registeredName : String; Instance : TObject; const method : String);
                                                                                virtual;
      procedure  RegisterObjectMethod
        (const registeredName : String; instance : TObject; addr : Pointer);   virtual;
      procedure  RegisterCall  (const registeredName : String; m : pMethod); virtual;
      procedure  UnRegisterCall (const registeredName : String);              virtual;
      procedure  Call(const aFunctionToCall : String);                        virtual;
     end;

     TExecute = procedure of object;

function jobRegister : TJobRegister;

implementation
uses sysUtils;

var reg : TJobRegister = nil;

function jobRegister : TJobRegister;
begin
 if not Assigned(reg) then
    reg := TJobRegister.Create(Application);
 result := reg;
end;

Constructor TJobRegister.Create(aOwner : TComponent);
begin
 inherited Create(aOwner);
 FRegister := TStringList.Create;
 FRegister.Sorted := True;
end;

Destructor TJobRegister.Destroy;
var i : Integer;
    p : pMethod;
begin
 for i := 0 to FRegister.Count-1 do
  begin
    p := pMethod(FRegister.Objects[i]);
    FreeMem(p);
  end;
end;

procedure  TJobRegister.RegisterObjectMethods
       (Instance : TObject; const methods : TStrings);
var i : Integer;
  n,v : String;
begin
 for i := 0 to methods.count-1 do
  begin
    n := methods.Names[i];
    v := methods.Values[n];
    if (n<>'') and
       (v<>'') then
         RegisterObjectMethodByName(n,instance,v);
  end;
end;

procedure  TJobRegister.RegisterObjectMethodByName
       (const registeredName : String; Instance : TObject; const method : String);
var p : Pointer;
begin
 if Assigned(instance) then
  begin
   p := Instance.MethodAddress(method);
   if (Assigned(p)) then
       RegisterObjectMethod(registeredName,Instance,p);
  end;
end;


procedure  TJobRegister.RegisterObjectMethod
        (const registeredName : String; instance : TObject; addr : Pointer);
var p : pMethod;
begin
 GetMem(p,SizeOf(TMethod));
 p.Data := instance;
 p.Code := addr;
 RegisterCall(registeredName,p);
end;

procedure  TJobRegister.RegisterCall (const registeredName : String; m : pMethod);
begin
    if (FRegister.IndexOf(registeredName)<0) then
        FRegister.AddObject(registeredName,Pointer(m))
    else raise Exception.Create('Funktion [' + registeredName + '] bereits registriert');
end;

procedure  TJobRegister.UnRegisterCall (const registeredName : String);
var idx : Integer;
    p  : pMethod;
begin
 idx := FRegister.IndexOf(registeredName);
 if (idx >= 0 ) then begin
                       p := pMethod(FRegister.Objects[idx]);
                       FreeMem(p);
                     end
                else raise Exception.Create('Ungültiger Versuch [' + registeredName + '] freizugeben');
end;

procedure  TJobRegister.Call(const aFunctionToCall : String);
var idx : Integer;
    p  : pMethod;
    e  : TExecute;
begin
 idx := FRegister.IndexOf(aFunctionToCall);
 if (idx >= 0 ) then begin
                         p := Pointer(FRegister.Objects[idx]);
                         e := TExecute(p^);
                         e();
                     end
                else begin
                       raise Exception.Create('Funtkion [' + aFunctionToCall + '] nicht vorhanden');
                     end;
end;
Die aufzurufenden Routinen musst Du aber selbst verpacken. Das geht aber ziemlich einfach. Das nachfolgende Beispiel zeigt wie.


Delphi-Quellcode:

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
  public
    { Public-Deklarationen }
  published
    procedure execute1;
    procedure execute2;
    procedure execute3;
    procedure execute4;
  end;

var
  Form1: TForm1;

implementation
uses jRegister;

{$R *.dfm}

procedure TForm1.execute1;
begin
 MessageDlg('Test', mtWarning, [mbOK], 0);
end;

procedure TForm1.execute2;
begin
 MessageDlg('Test 2', mtWarning, [mbOK], 0);
end;

procedure TForm1.execute3;
begin
 MessageDlg('Test 3', mtWarning, [mbOK], 0);
end;

procedure TForm1.execute4;
begin
 MessageDlg('Test 4', mtWarning, [mbOK], 0);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 reg := TJobRegister.Create(self);
end;

procedure TForm1.Button1Click(Sender: TObject);
var s : TStringList;
begin
  s := TStringList.Create;
  s.Add('Test=execute1');
  s.Add('Test2=execute2');
 { methoden müssen published sein, Instance muss von TPersistent
   oder TComponent abgeleitet sein }
  jobRegister.RegisterObjectMethods(self,s);
  s.free;

  jobRegister.Call('Test');
  jobRegister.Call('Test2');

 { Instanzen können beliebige Objekte sein, Methoden müssen nicht published sein }
  jobRegister.RegisterObjectMethod('Test 3', self, @TForm1.execute3);
  jobRegister.Call('Test 3');

  { methoden müssen published sein, Instance muss von TPersistent
   oder TComponent abgeleitet sein }
  jobRegister.RegisterObjectMethodByName('Test 4', self, 'execute4' );
  jobRegister.Call('Test 4');
end;

end.
Die Funktion jobregister ist zentral definiert und sollte nur einmal vorhanden. Die Methoden die verpackt werden sollen dürfen in beliebigen anderen Objekten sein, die nicht zwingend von TComponent oder TPersistent abgeleitet sein müssen. Das Registrieren und Deregistrieren von Methoden wäre am besten im Constructor bzw. Destrukter der Objekte untergebracht die diese Methoden aufrufen - das Beispiel ist aber so das Du es verstehen solltest und ähnlich wie das bis jetzt von Dir verwendete.

Schön ist aber trotzdem anders.

hanvas 23. Feb 2015 19:43

AW: Routine mit Namen aufrufen
 
Habe leider zwei Fehler eingebaut. Bei Destroy fehlt der geerbte Destructor also bitte lieber so:

Delphi-Quellcode:


Destructor TJobRegister.Destroy;
var i : Integer;
    p : pMethod;
begin
 for i := 0 to FRegister.Count-1 do
  begin
    p := pMethod(FRegister.Objects[i]);
    FreeMem(p);
  end;
 inherited Destroy;
end;

und im Beispiel gehört sich FormCreate gestrichen.

Sigi55 24. Feb 2015 23:15

AW: Routine mit Namen aufrufen
 
Hallo Ha-Jö !!

ist ja der Wahnsinn, was für ne Arbeit :-)

Zitat:

Zitat von hanvas (Beitrag 1291175)
Delphi-Quellcode:
Destructor TJobRegister.Destroy;
var i : Integer;
    p : pMethod; // Mag er nicht, Undeclared Indentifier ????
begin
 for i := 0 to FRegister.Count-1 do
  begin
    p := pMethod(FRegister.Objects[i]);
    FreeMem(p);
  end;
 inherited Destroy;
end;

Sonst sieht alles gut aus, aber ich hab keine Ahnung was ich mit "pMethod"
machen soll ...

Danke für die Mühe, jetzt soll's aber auch laufen !

Gruß

Sigi

P.S.: ist D2010

DeddyH 25. Feb 2015 07:03

AW: Routine mit Namen aufrufen
 
Ich rate mal:
Delphi-Quellcode:
type
  pMethod = ^TMethod;

Sigi55 25. Feb 2015 16:46

AW: Routine mit Namen aufrufen
 
Moin,

mir sagt das Alles garnichts :-) und wird es auch wohl nie ...

Delphi-Quellcode:
  procedure RegisterCall (const registeredName : String; m : pMethod); virtual;
                                                             ^^^^^^^
// Mag er nicht, Undeclared Indentifier ???

Ich kann mir da leider nicht ansatzweise weiterhelfen, da hört's
echt auf.
Ich bin mehr so der Datenschauffler im kfm. Bereich, so von einer DB
in die andere, Plausibilitätsprüfungen, etc.

Aber das ist nicht meine Welt ... sry.

@DaddyH, das war es leider nicht :-(

Gruß

Sigi

hanvas 25. Feb 2015 17:28

AW: Routine mit Namen aufrufen
 
Zitat:

Zitat von Sigi55 (Beitrag 1291521)
Moin,

mir sagt das Alles garnichts :-) und wird es auch wohl nie ...

Delphi-Quellcode:
  procedure RegisterCall (const registeredName : String; m : pMethod); virtual;
                                                             ^^^^^^^
// Mag er nicht, Undeclared Indentifier ???

@DaddyH, das war es leider nicht :-(

Gruß

Sigi

Doch natürlich war es das! Aber eigentlich sollte pMethod in der Unit system ohnehin deklariert sein, möglicherweise ist das von Version zu Version unterschiedlich.

Wo hast Du das

Delphi-Quellcode:
  type pMethod = TMethod;
denn hingeschrieben. Dir Typdeklaration gehört vor die erste Verwendung also

Delphi-Quellcode:

unit jRegister;
interface
uses classes;

type pMethod = TMethod;

     TJobRegister = class(TComponent)
 .....
cu Ha-Jö

Sigi55 25. Feb 2015 18:43

AW: Routine mit Namen aufrufen
 
Hi,

Zitat:

... denn hingeschrieben. Dir Typdeklaration gehört vor die erste Verwendung also
Delphi-Quellcode:

unit jRegister;
interface
uses classes;

type pMethod = TMethod;

     TJobRegister = class(TComponent)
 .....
Hatte ich auch so gemacht, nur hatte ich "type pMethod = ^TMethod" wie DaddyH
es geschrieben hatte ...

Jetzt, ohne "^" ist es OK, nur eines noch ..

Delphi-Quellcode:
function jobRegister : TJobRegister;
begin
 if not Assigned(reg) then
    reg := TJobRegister.Create(Application);
 result := reg;            // ^^^^^^^^^^^
end;
Fehler: Application? Undeclared Indentifier ???

Das ist jetzt aber der Letzte ...

Und nochmal für Blö..., wo genau an welcher Stelle soll das
"FormCreate" gestrichen werden ??

Danke :-)

Sigi

himitsu 25. Feb 2015 19:19

AW: Routine mit Namen aufrufen
 
Zitat:

Zitat von Sigi55 (Beitrag 1291543)
Fehler: Application? Undeclared Indentifier ???

[F1] kennst du aber?

Delphi-Referenz durchsuchenApplication -> http://docwiki.embarcadero.com/Libra...ms.Application
In der Hilfe steht, in welcher Unit etwas steht.

Aber man muß hier nicht Application verwenden, denn dem Delphi-Referenz durchsuchenTComponent.Create gibt man einen Owner mit, also den, welcher sich um das Freigeben kümmert.
Meistens nimmt man die Form, aber es kann jeder TComponent-Nachfahre sein, oder wenn man sich definitiv immer selber um die Freigabe kümmert, dann kann man auch nil nehmen.

hanvas 25. Feb 2015 19:37

AW: Routine mit Namen aufrufen
 
Zitat:


Hatte ich auch so gemacht, nur hatte ich "type pMethod = ^TMethod" wie DaddyH
es geschrieben hatte

Es gehört sich mit ^, das Fehlen war Prellen meiner Tastatur.


Delphi-Quellcode:
function jobRegister : TJobRegister;
begin
 if not Assigned(reg) then
    reg := TJobRegister.Create(Application);
 result := reg;            // ^^^^^^^^^^^
end;
Zitat:


Fehler: Application? Undeclared Indentifier ???

Du musst die Unit Forms einbinden wenn Du Application verwenden willst.

Zitat:


Und nochmal für Blö..., wo genau an welcher Stelle soll das
"FormCreate" gestrichen werden ??

Mein ursprüngliches Posting bestand aus einer Unit jRegister und einer in der ein Formular zu Testzwecken verwendet wurde. In der Unit der ich das Formular zum Testen hatte, hatte ich auch "Quickn Dirty" enen Aufruf/Implementierung von FormCreate der nicht reingehört bzw nicht mehr notwendig ist. Wenn Du dieses Testformular nicht nachbaust und nur die andere Unit verwendest dann gibt es kein auch kein FormCreate.

Entschuldige die Fehler die beim Copy / Paste entstanden sind (bzw. das Fehlen von PMethod ist bei meinem Delphi kein Fehler)

cu Ha-Joe


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:48 Uhr.
Seite 4 von 5   « Erste     234 5      

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