Delphi-PRAXiS
Seite 1 von 5  1 23     Letzte »    

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 20. Feb 2015 15:56

Routine mit Namen aufrufen
 
Hallo,

ich nutze diese kleine Routine um Prozeduren mit Namen zu starten,
das klappt auch alles ganz wunderbar solange sich diese Prozedure
in der gleichen Form befindet ...

Delphi-Quellcode:
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    // Your routines (that you'll run by name) must be here
    procedure Hello_World(Sender: TObject);
  private
    procedure ExecuteRoutine(Instance: TObject; Name: string);
  end;

var
  Form1: TForm1;

type
  TExecute = procedure of object;

procedure TForm1.ExecuteRoutine(Instance: TObject; Name: string);
var
  Routine: TMethod;
  Execute: TExecute;
begin
  Routine.Data := Pointer(Instance);
  // Returns the address of a published method.
  Routine.Code := Instance.MethodAddress(Name);
  if Routine.Code = nil then Exit;
  Execute := TExecute(Routine);
  Execute;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ExecuteRoutine(Form1, 'Hello_World');
end;

procedure TForm1.Hello_World(Sender: TObject);
begin
  ShowMessage('This is a test');
end;
Jetzt möchte ich von der Hauptform eine Routine (Prozedure) aus einer
anderen unit aufrufen.
Und das bekomm ich nicht gebacken ..., da fehlt's mir echt an den
Grundlagen :-(

Kann mit jemand weiterhelfen ?

Danke schonmal.

Gruß

Sigi

BadenPower 20. Feb 2015 16:09

AW: Routine mit Namen aufrufen
 
Zitat:

Zitat von Sigi55 (Beitrag 1290778)
Jetzt möchte ich von der Hauptform eine Routine (Prozedure) aus einer
anderen unit aufrufen.

Dazu musst Du die andere Unit in die Uses-Klausel eintragen.

Zitat:

Zitat von Sigi55 (Beitrag 1290778)
Und das bekomm ich nicht gebacken ..., da fehlt's mir echt an den Grundlagen :-(

Dir fehlt es an Grundlagen und möchtest eine Methode über ihren Namen ansprechen?

Warum nicht den normalen Weg?
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  Hello_World(Self);
end;

Medium 20. Feb 2015 16:26

AW: Routine mit Namen aufrufen
 
Das hier ist der wichtige Teil:
Zitat:

Zitat von Sigi55 (Beitrag 1290778)
Delphi-Quellcode:
  // Returns the address of a published method.

Die RTTI (zumindest die nicht erweiterte, die es bei Delphi 5 auch lange noch nicht gab) ist nur bei published Feldern behilflich, alles was nicht published ist, kennt sie einfach nicht. Daher wird der Aufruf auf diese Weise nicht gehen, auch nicht mit Tricks. (Der Teil direkt unter einer Klassendeklaration ausserhalb der "private, protected, public, published"-Sektionen ist implizit published.)

stahli 20. Feb 2015 16:51

AW: Routine mit Namen aufrufen
 
Nenne am besten erst mal konkret Deine Delphi-Version. Delphi5?

Und was willst Du mit der Funktionalität erreichen bzw. was willst Du dem User ermöglichen? Vielleicht gibt es ja bessere Alternativen.

Methoden nach Namen ermitteln und ausführen ist ab D2010 einfacher - aber immer noch recht komplex.

Evtl. kannst Du das auch einfacher lösen:

Delphi-Quellcode:
procedure TForm1.ExecuteRoutine(Instance: TObject; Name: string);
begin
  if (Name = "DoA") and (Instance is TMyClass) then
  begin
    (Instance as TMyClass).DoA;
    Exit;
  end;
  if (Name = "DoB") and (Instance is TOtherClass) then
  begin
    (Instance as TOtherClass).DoB;
    Exit;
  end;
end;
Das geht natürlich nur, wenn die möglichen Klassen und Methoden relativ übersichtlich sind.

himitsu 20. Feb 2015 16:53

AW: Routine mit Namen aufrufen
 
Zitat:

Zitat von Medium (Beitrag 1290784)
(Der Teil direkt unter einer Klassendeklaration ausserhalb der "private, protected, public, published"-Sektionen ist implizit published.)

Nein und vielleicht auch ja.

Der Standard ist "public", außer die Klasse oder ein Vorfahre ist mit
Delphi-Quellcode:
{$M+}
compiliert, wie z.B. TPersistent/TComponent, wo es dann "published" wird.

BadenPower 20. Feb 2015 17:48

AW: Routine mit Namen aufrufen
 
Der Code funktioniert auch mit 2 Units.

Aber für was er das benötigt ist noch nicht offensichtlich.


Hier mal ein Beispiel mit 2 Units:

1. Unit mit 2 Buttons auf der Form

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Hello_World(Sender: TObject);
  private
    procedure ExecuteRoutine(Instance: TObject; Name: string);
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  unit2;

type
  TExecute = procedure of object;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ExecuteRoutine(Form1, 'Hello_World');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ExecuteRoutine(Form2, 'Hello_World');
end;

procedure TForm1.ExecuteRoutine(Instance: TObject; Name: string);
var
  Routine: TMethod;
  Execute: TExecute;
begin
  Routine.Data := Pointer(Instance);
  // Returns the address of a published method.
  Routine.Code := Instance.MethodAddress(Name);
  if Routine.Code = nil then Exit;
  Execute := TExecute(Routine);
  Execute;
end;


procedure TForm1.Hello_World(Sender: TObject);
begin
  ShowMessage('Form1.Hello_World');
end;


end.
Und die 2. Unit

Delphi-Quellcode:
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm2 = class(TForm)
    procedure Hello_World(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Hello_World(Sender: TObject);
begin
  ShowMessage('Form2.Hello_World');
end;

end.

Medium 20. Feb 2015 18:56

AW: Routine mit Namen aufrufen
 
Zitat:

Zitat von himitsu (Beitrag 1290789)
Zitat:

Zitat von Medium (Beitrag 1290784)
(Der Teil direkt unter einer Klassendeklaration ausserhalb der "private, protected, public, published"-Sektionen ist implizit published.)

Nein und vielleicht auch ja.

Der Standard ist "public", außer die Klasse oder ein Vorfahre ist mit
Delphi-Quellcode:
{$M+}
compiliert, wie z.B. TPersistent/TComponent, wo es dann "published" wird.

Da hatter Recht, über diese Falle bin ich sogar auch schon mal gestolpert, wenn auch in einem anderen Zusammenhang.

himitsu 20. Feb 2015 21:52

AW: Routine mit Namen aufrufen
 
Delphi-Quellcode:
procedure TForm1.Hello_World(Sender: TObject);    

TExecute = procedure of object;
Und schon hat jemand Mist gebaut, denn die Signaturen stimmen nicht überein.

Zum Glück liegt dieser Parameter zufällig in den Registern und nicht auf'm Stack,
so steht da nur Schrott drin und es knallt nicht gleich.

Sigi55 21. Feb 2015 06:21

AW: Routine mit Namen aufrufen
 
Moin erstmal,

also, wozu braucht er das ?

Ich hab mir so eine Art Taskplaner, unix-cron, etc.. geschrieben.
Die jobs lese ich aus einer DB-Tabelle und arbeite sie zeitgesteuert ab.
Der "JobName" ist die Bezeichnung der aufzurufen Procedure den ich per Variable
übergebe.

Das klappt auch alles wunderbar, nur liegen nicht alle Proceduren auf der
Hauptform ...

z.Z. mache ich es über den Umweg

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  ExecuteRoutine(Form1, Datensicherung);
end;

procedure TForm1.Datensicherung(Sender: TObject);
begin
  DatenSicherungStarten;
end;
... und ich hätte gern etwas inder Art:

Delphi-Quellcode:
ExecuteRoutine(Unit??? oder wo auch immer, Datensicherung);

Das muss zwar alles nicht sein, ist auch kein Akt wenn es so nicht
zu machen ist, wäre nur schöner :-D

Gruß

Sigi

hanvas 21. Feb 2015 08:55

AW: Routine mit Namen aufrufen
 
Zitat:

Zitat von Sigi55 (Beitrag 1290823)
Moin erstmal,

Ich hab mir so eine Art Taskplaner, unix-cron, etc.. geschrieben.
Die jobs lese ich aus einer DB-Tabelle und arbeite sie zeitgesteuert ab.
Der "JobName" ist die Bezeichnung der aufzurufen Procedure den ich per Variable
übergebe.

Sigi

Wenn ich das richtig verstehen dann gibt es keine "unbekannten" Prozeduren und Methoden sondern lediglich Objekte/Klassen die sich auf mehrere Units verteilen und die Du einheitlich aufrufen willst, Du weisst aber wo (in welcher Unit/Klasse) diese Funktionen ursprünglich definiert sind. Da du alle Methoden in Deinem Beispiel ohne Parameter aufrufen wolltest gehe ich davon aus das alle aufzurufenden Methoden paramterlos sind.

In jedem Fall würde ich dafür sorgen das sich die aufzurufenden Objekte/Methoden selbst bei einer zentralen Instanz "registrieren".

Delphi-Quellcode:
 

unit register;

....

type TJobRegister = class(TObject)
     private
       FRegister : TStringList;
     public
       procedure registerCall (const registeredName : String; m : pMethod);
       procedure Call(const registeredName : String);      
     end;

function RegisteredJobs : TJobRegister; // singleton für arme

implementation

procedure TJobRegister.registerCall (const registeredName : String; m : pMethod);
begin
 if (FRegister.IndexOf(registeredName)<0) then
     FRegister.AddObject(registeredName,m);
end;

procedure TJobRegister.Call(const registeredName : String);      
var idx : Integer;
begin
 idx := FRegister.IndexOf(registeredName);
 if (idx >= 0 ) then begin
                         TExecute(FRegister.Objects[idx]^).Execute;
                     end
                else begin
                       .....
                     end;
end;
Die Klassen deren Methoden aufgerufen werden sollen müssten dann die Unit Register verwenden und sich dort anmelden, beispielsweise so

Delphi-Quellcode:
 

uses Register;

type TUseable = class(TObject)
     public
      constructor Create;
      procedure TuWas;
     end;

constructor TUseable.Create;
var m : pMethod;
begin
 New(m);
 m.Data := self;
 m.Code := @TuWas;
 register.registeredJobs.registerCall('Irgendwas',m);
end;
Das hätte auch den Vorteil das Du beliebige Namen verwenden kannst. Die Registerklasse müsste sich freilich noch um die Freigabe der pMethod Variablen kümmern, eine Deregistrierung wäre angeraten wenn es passieren kann das Instanzen während der Laufzeit des Programmes zerstört werden etc. Aber wenn Du das so machst, dann kannst Du es auch gleich richtig machen und entweder Interfaces verwenden oder Dir einen Wrapper je aufzurufender Klasse schreiben und dessen Instanzen / Objekte registrieren.

cu Ha-Jö


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:44 Uhr.
Seite 1 von 5  1 23     Letzte »    

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