![]() |
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ö |
AW: Routine mit Namen aufrufen
Moin Ha-Jö
Zitat:
Zitat:
Ich glaub ich mach das mit den Fähnchen ...(Sparkasse) :-D Ich bin eher so der "Auto-Zusammen-Schrauber", sprich, fertige Komponenten zusammenbauen, aber wenn es dann (für mich) ins "Eingemachte" geht muss ich passen. Aber vielen Dank für Deine Mühe ! cu Sigi |
AW: Routine mit Namen aufrufen
So wie ich das verstehe, liegt Dein Problem nicht bei "anderen Units" sondern bei "anderen Instanzen".
Zeig doch mal noch einen Auszug aus Deiner Datenbank, wie die Jobs definiert sind. Wenn Du als JobNamen jetzt "DatensicherungStarten" ermittelst und dann in einem Objekt der Klasse TForm1 interpretierst um eine Methode "DatensicherungStarten" zu finden funktioniert das´, da Du Dich auf das Objekt "Self" beziehst. Wenn Du aber mit einem anderen Objekt arbeiten willst, musst Du dessen Instanz mitgeben. Da reicht es nicht, eine Unit zu kennen. Also ich denke, Du hast da noch einen Ansatz, der nicht ganz passt. Versuch doch mal meinen oben genannten Ansatz. Offenbar hast Du ja nicht viele in Frage kommenden Möglichkeiten, welche Jobs aufgerufen werden können. Dann könnte so ein "Übersetzer" schon Sinn machen. Du übergibst eine Objektinstanz und den Methodennamen und führst dann etwas passendes dazu aus. Vom Prinzip könntest Du dann auch statt dem Methodennamen einen Code verwalten (42 = "DatensicherungStarten"). Dann siehst Du schon mal, dass Du eine Objektinstanz kennen musst, damit das funktionieren kann. Ich denke, dass es derzeit bei Dir daran scheitert. Zeig einfach noch ein bissl mehr, dann können wir das auch besser nachvollziehen. |
AW: Routine mit Namen aufrufen
Zitat:
Delphi-Quellcode:
procedure TForm1.Button4Click(Sender: TObject);
begin ExecuteRoutine(Application.FindComponent('Form2'), 'Hello_World'); end; |
AW: Routine mit Namen aufrufen
Hallo Stali,
Zitat:
Delphi-Quellcode:
Das können ein- oder mehrere Jobs sein die nacheinander abgearbeitet
while not eof do
begin ExecuteRoutine(Form1,dmLOG.tbl_JobsLinkedPreUpdate.FieldByName('Command').AsString); next; end; werden, z.B.: Angebote ausdrucken und versenden, Datenbanken abgleichen, etc. Das ist auch nicht wirklich ein Problem, so wie es jetzt ist, ist es eigentlich OK, aber ich dachte halt, ich könnte mir den quasi "doppelt gemoppelten" Aufruf einer Procedure sparen, wenn die Procedure in irgendeiner anderen unit liegt. Gruß Sigi |
AW: Routine mit Namen aufrufen
Hallo BadenPower,
Zitat:
in einer "formlosen" unit. Vielen Dank und Gruß Sigi |
AW: Routine mit Namen aufrufen
Zitat:
Vielleicht lässt sich das einfach umbiegen. |
AW: Routine mit Namen aufrufen
Oder Du machst aus der anderen Unit einfach eine "Form-Unit", welche Du nicht einmal anzeigen lassen musst.
kleines Copy-und-Paste Beispiel MainForm
Delphi-Quellcode:
Unit2
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Buttons, Dialogs, StdCtrls; type TForm1 = class(TForm) procedure Job1(); procedure Job2(); procedure Job3(); procedure Button1Click(Sender: TObject); private procedure ExecuteJobs(); procedure ExecuteRoutine(AInstance: TObject; AName: string); public Memo1: TMemo; Button1: TButton; ListBox1: TListBox; constructor Create(AOwner: TComponent); override; end; var Form1: TForm1; implementation {$R *.dfm} type TExecute = procedure of object; constructor TForm1.Create(AOwner: TComponent); begin inherited; Position := poScreenCenter; Height := 500; Width := 600; Memo1 := TMemo.Create(Self); Memo1.Parent := Self; Memo1.Left := 300; Memo1.Top := 10; Memo1.Width := 280; Memo1.Height := 400; Button1 := TButton.Create(Self); Button1.Parent := Self; Button1.Left := 100; Button1.Top := 420; Button1.Width := 100; Button1.Height := 25; Button1.Caption := 'Jobs starten'; Button1.OnClick := Button1Click; ListBox1 := TListBox.Create(Self); ListBox1.Parent := Self; ListBox1.Left := 10; ListBox1.Top := 10; ListBox1.Width := 280; ListBox1.Height := 400; ListBox1.Items.Add('Form1/Job1'); ListBox1.Items.Add('Form1/Job2'); ListBox1.Items.Add('Form1/Job3'); ListBox1.Items.Add('Form2/Job1'); ListBox1.Items.Add('Form2/Job2'); ListBox1.Items.Add('Form2/Job3'); end; procedure TForm1.Button1Click(Sender: TObject); begin ExecuteJobs(); end; procedure TForm1.ExecuteJobs(); var liZ1: Integer; lObjectName: String; lProcedureName: String; lPos: Integer; begin for liZ1 := 0 to ListBox1.Count - 1 do begin if ListBox1.Items[liZ1] <> '' then begin lObjectName := ''; lProcedureName := ''; lPos := Pos('/', ListBox1.Items[liZ1]); lObjectName := Copy(ListBox1.Items[liZ1], 1, lPos - 1); lProcedureName := Copy(ListBox1.Items[liZ1], lPos + 1, MaxInt); if ((lObjectName <> '') and (lProcedureName <> '')) then begin Memo1.Lines.Add('Methode ' + lProcedureName + ' in ' + lObjectName + ' starten.'); ExecuteRoutine(Application.FindComponent(lObjectName), lProcedureName); Memo1.Lines.Add('Methode ' + lProcedureName + ' in ' + lObjectName + ' beendet.'); end; end; end; end; procedure TForm1.ExecuteRoutine(AInstance: TObject; AName: string); var lRoutine: TMethod; lExecute: TExecute; begin lRoutine.Data := Pointer(AInstance); lRoutine.Code := AInstance.MethodAddress(AName); if (lRoutine.Code = nil) then Exit; lExecute := TExecute(lRoutine); lExecute; end; procedure TForm1.Job1(); begin ShowMessage('Form1 - Job1'); end; procedure TForm1.Job2(); begin ShowMessage('Form1 - Job2'); end; procedure TForm1.Job3(); begin ShowMessage('Form1 - Job3'); end; end.
Delphi-Quellcode:
unit Unit2;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TForm2 = class(TForm) procedure Job1(); procedure Job2(); procedure Job3(); private public end; var Form2: TForm2; implementation {$R *.dfm} procedure TForm2.Job1(); begin ShowMessage('Form2 - Job1'); end; procedure TForm2.Job2(); begin ShowMessage('Form2 - Job2'); end; procedure TForm2.Job3(); begin ShowMessage('Form2 - Job3'); end; end. |
AW: Routine mit Namen aufrufen
Hallo BadenPower,
Zitat:
Vielen Dank für Deine Mühe, euch anderen auch. Hier wird man echt geholfen. Meistens kann ich ja meine Wissenslücken in Bezug auf Delphi über Google oder durch Suche hier im Forum auffüllen, aber in diesem Fall .... Danke nochmal und Gruß Sigi |
AW: Routine mit Namen aufrufen
Zitat:
Es wurde doch genau gesagt, was man braucht. > Published und/oder {$M+} (also TPersistent/TComponent) |
AW: Routine mit Namen aufrufen
Zitat:
Ich steh' grad' auf dem Schlauch. |
AW: Routine mit Namen aufrufen
Man kann natürlich aus einer Mücke einen Elefanten machen.
Statt
Delphi-Quellcode:
nimmt man ein TRichEdit,
var s: string;
bzw. statt einer TStringList nimmt man ein TMemo und statt TPersistent eine ganze Form, (wenn schon, dann maximal ein TDataModul) statt TBitmap/TPicture nimmst du ein TImage, statt mit dem Smart machst du deinen Freitagseinkauf mit einem 80-Tonner usw. |
AW: Routine mit Namen aufrufen
Zitat:
Ja klar, ein Datenmodul geht ja auch. Es wird beim Programmstart auch automatisch erzeugt und es muss auch in Form1 nie etwas geändert werden, da ja die Units mit den Funktionen nicht in Form1 bekannt gemacht werden müssen. Bei Erweiterungen des Programms entweder ein Datenmodul oder eben eine Form, wenn die Funktionen in einem Fenster enthalten sind, welches sowieso benutzt wird. Würde der TE etwas anderes benutzen, dann müsste er immer selbst dafür sorgen, dass der entsprechende Container auch erzeugt wird. So kann er einfach ein neues Fenster oder Datenmodul erstellen und braucht an keiner anderen Stelle etwas zu ändern. Unit3 als Datenmodul:
Delphi-Quellcode:
unit Unit3;
interface uses SysUtils, Classes, Dialogs; type TDataModule3 = class(TDataModule) procedure Job1(); procedure Job2(); procedure Job3(); private { Private-Deklarationen } public { Public-Deklarationen } end; var DataModule3: TDataModule3; implementation {$R *.dfm} procedure TDataModule3.Job1(); begin ShowMessage('DataModule3 - Job1'); end; procedure TDataModule3.Job2(); begin ShowMessage('DataModule3 - Job2'); end; procedure TDataModule3.Job3(); begin ShowMessage('DataModule3 - Job3'); end; end. zum Test dieses noch in den Constructor Form1.Create der Form1 hinzufügen
Delphi-Quellcode:
und man sieht, es geht selbstverständlich auch.
ListBox1.Items.Add('DataModule3/Job1');
ListBox1.Items.Add('DataModule3/Job2'); ListBox1.Items.Add('DataModule3/Job3'); |
AW: Routine mit Namen aufrufen
Zitat:
und wie das geht, ist das jetzt der Ansatz den himitsu meinte ?? Gruß Sigi |
AW: Routine mit Namen aufrufen
Zitat:
Hätte allerdings einen erhöhten Programmieraufwand zur Folge und dies immer dann, wenn Du auf Funktionen in einer neuen Klasse zugreifen wolltest. Und ob dies dann wirklich weniger Speicher benötigt ist eher ungewiss. Mit dem Datenmodul ist es ein sehr guter Kompromiss, da das DM weniger Speicher belegt, als eine extra Form, wenn Du die Form selbst eigentlich nicht benötigst. Wie gesagt: einfach neues Datenmodul oder neue Form mit den Proceduren anlegen und fertig. |
AW: Routine mit Namen aufrufen
Zitat:
seh ich auch so, hab ich getest und löppelt super :-) Für mich als "DummProgger" gerade richtig :-) Dann werd ich mal an's umbauen gehn ... Danke nochmal. Sigi |
AW: Routine mit Namen aufrufen
Kann man über diesen Weg auch z.B. Destroy aufrufen*? Das konnte spaßig sein :angel2:
* Sry, kein Delphi zur Hand. |
AW: Routine mit Namen aufrufen
Zitat:
Wenn Du das aber möchtest dann so:
Delphi-Quellcode:
type
TForm1 = class(TForm) procedure Job1(); procedure Button1Click(Sender: TObject); private procedure ExecuteJobs(); procedure ExecuteRoutine(AInstance: TObject; AName: string); public published procedure Destroy; end; var Form1: TForm1; implementation {$R *.dfm} type TExecute = procedure of object; procedure TForm1.Destroy; begin inherited Destroy; end; |
AW: Routine mit Namen aufrufen
Das Problem bei Ansätzen dieser Art(*) erblickt in seiner ganzen Wucht in dem Augenblick das Licht der Welt, in dem die Namen der aufzurufenden Prozeduren abgespeichert werden und anschließend ein Refactoring der Prozedurnamen erfolgt (= Methode umbenennen). Dann funktioniert nämlich gar nichts mehr.
Angenommen im Beispiel des TE kommt jemand auf die Idee, das '_' in Prozedurnamen ein NoGo sind (was nicht abwegig ist, denn sie sind es :stupid:). Eben wurde gespeichert, das 'Hello_World' aufgerufen werden soll, dann wird umbenannt und dann geht gar nichts mehr und im ungünstigsten Fall werden die abgespeicherten Aufrufe (als String) komplett unbrauchbar. Alternativen? Z.B. Methodenattribute einführen, d.h. 'Hello_World' wird mit dem Attribute 'HELLOWORLD' dekoriert. Dann ist das Verfahren immun gegen Refactorings. Natürlich: Wer Attributparameter verändert, hat selbst schuld. Mit Sicherheit gibt es bessere Ideen für eine robustere Umsetzung der Anforderung. (*) Ein anderer Ansatz der gleichen Art: 'FindComponent' :wall: |
AW: Routine mit Namen aufrufen
Zitat:
cu Ha-Jö |
AW: Routine mit Namen aufrufen
:thumb: Oder so. Hab ich doch glatt überlesen.
|
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 |
AW: Routine mit Namen aufrufen
Zitat:
Delphi-Quellcode:
Die aufzurufenden Routinen musst Du aber selbst verpacken. Das geht aber ziemlich einfach. Das nachfolgende Beispiel zeigt wie. 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;
Delphi-Quellcode:
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.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. Schön ist aber trotzdem anders. |
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. |
AW: Routine mit Namen aufrufen
Hallo Ha-Jö !!
ist ja der Wahnsinn, was für ne Arbeit :-) Zitat:
machen soll ... Danke für die Mühe, jetzt soll's aber auch laufen ! Gruß Sigi P.S.: ist D2010 |
AW: Routine mit Namen aufrufen
Ich rate mal:
Delphi-Quellcode:
type
pMethod = ^TMethod; |
AW: Routine mit Namen aufrufen
Moin,
mir sagt das Alles garnichts :-) und wird es auch wohl nie ...
Delphi-Quellcode:
// Mag er nicht, Undeclared Indentifier ???
procedure RegisterCall (const registeredName : String; m : pMethod); virtual;
^^^^^^^ 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 |
AW: Routine mit Namen aufrufen
Zitat:
Wo hast Du das
Delphi-Quellcode:
denn hingeschrieben. Dir Typdeklaration gehört vor die erste Verwendung also
type pMethod = TMethod;
Delphi-Quellcode:
cu Ha-Jöunit jRegister; interface uses classes; type pMethod = TMethod; TJobRegister = class(TComponent) ..... |
AW: Routine mit Namen aufrufen
Hi,
Zitat:
Delphi-Quellcode:
Hatte ich auch so gemacht, nur hatte ich "type pMethod = ^TMethod" wie DaddyHunit jRegister; interface uses classes; type pMethod = TMethod; TJobRegister = class(TComponent) ..... es geschrieben hatte ... Jetzt, ohne "^" ist es OK, nur eines noch ..
Delphi-Quellcode:
Fehler: Application? Undeclared Indentifier ???
function jobRegister : TJobRegister;
begin if not Assigned(reg) then reg := TJobRegister.Create(Application); result := reg; // ^^^^^^^^^^^ end; Das ist jetzt aber der Letzte ... Und nochmal für Blö..., wo genau an welcher Stelle soll das "FormCreate" gestrichen werden ?? Danke :-) Sigi |
AW: Routine mit Namen aufrufen
Zitat:
![]() ![]() In der Hilfe steht, in welcher Unit etwas steht. Aber man muß hier nicht Application verwenden, denn dem ![]() 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. |
AW: Routine mit Namen aufrufen
Zitat:
Delphi-Quellcode:
function jobRegister : TJobRegister;
begin if not Assigned(reg) then reg := TJobRegister.Create(Application); result := reg; // ^^^^^^^^^^^ end; Zitat:
Zitat:
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 04:43 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