![]() |
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:
Jetzt möchte ich von der Hauptform eine Routine (Prozedure) aus einer
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; 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 |
AW: Routine mit Namen aufrufen
Zitat:
Zitat:
Warum nicht den normalen Weg?
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin Hello_World(Self); end; |
AW: Routine mit Namen aufrufen
Das hier ist der wichtige Teil:
Zitat:
|
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:
Das geht natürlich nur, wenn die möglichen Klassen und Methoden relativ übersichtlich sind.
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; |
AW: Routine mit Namen aufrufen
Zitat:
Der Standard ist "public", außer die Klasse oder ein Vorfahre ist mit
Delphi-Quellcode:
compiliert, wie z.B. TPersistent/TComponent, wo es dann "published" wird.
{$M+}
|
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:
Und die 2. Unit
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.
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. |
AW: Routine mit Namen aufrufen
Zitat:
|
AW: Routine mit Namen aufrufen
Delphi-Quellcode:
Und schon hat jemand Mist gebaut, denn die Signaturen stimmen nicht überein.
procedure TForm1.Hello_World(Sender: TObject);
TExecute = procedure of object; 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. |
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:
... und ich hätte gern etwas inder Art:
procedure TForm1.Button1Click(Sender: TObject);
begin ExecuteRoutine(Form1, Datensicherung); end; procedure TForm1.Datensicherung(Sender: TObject); begin DatenSicherungStarten; end;
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 |
AW: Routine mit Namen aufrufen
Zitat:
In jedem Fall würde ich dafür sorgen das sich die aufzurufenden Objekte/Methoden selbst bei einer zentralen Instanz "registrieren".
Delphi-Quellcode:
Die Klassen deren Methoden aufgerufen werden sollen müssten dann die Unit Register verwenden und sich dort anmelden, beispielsweise sounit 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;
Delphi-Quellcode:
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.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; cu Ha-Jö |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:31 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz