[gelöst] Name der aktuellen Prozedur als String

Für Fragen von Einsteigern und Programmieranfängern...
Theozh
Beiträge: 99
Registriert: So 1. Jul 2012, 10:56

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Theozh »

...falls jemand vielleicht etwas Ähnliches sucht, hier noch abschliessend ein funktionierendes Beispiel, mit dem ich nun bis auf Weiteres glücklich bin.
Hier werden 100 Knöpfe zur Laufzeit erzeugt, benannt und platziert. Bei Betätigen eines jeden Knopfes wird eine Prozedur aufgerufen, in welcher rückgemeldet wird, welcher Knopf gedrückt wurde.
Im Nachhinein hätte der Titel vielleicht etwas anders lauten müssen, damit es noch klarer gewesen wäre, was ich genau wollte.

In der Zeile

Code: Alles auswählen

OnClick:= @ButtonClick;
war das '@' für mich nicht offensichtlich, da bei beim manuellen Erstellen der Knöpfe in der .tfm Datei kein '@' steht.
Ich bin dann schließlich in irgendwelchen Foreneinträgen fündig geworden.

Code: Alles auswählen

unit Test_CreateButton_unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure ButtonClick(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
var x,y: integer;
    Coordinates: string;
    NewButton: TButton;
begin
  for y:= 0 to 9 do
  begin
    for x:= 0 to 9 do
    begin
      Coordinates:= Format('%.2d',[y*10+x]);
      NewButton:= TButton.Create(Self);
      with NewButton do
      begin
        Name:= 'Button' + Coordinates;
        Parent := Self;
        Caption := Coordinates;
        Top := y*32+50;
        Left := x*32 + 50;
        Height := 30;
        Width := 30;
        Visible:= true;
        OnClick:= @ButtonClick;   // das @ war für mich nicht offensichtlich
      end;
    end;
  end;
end;
 
procedure TForm1.ButtonClick(Sender: TObject);
begin
  ShowMessage('Hallo, ich bin ' + TComponent(Sender).Name);
end;
 
end.
 

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Michl »

Ich häng mich mal an den Thread mit an, da der Titel genau das ist, was ich will.

Zwei Fragen:
- Im beigefügten Bsp. muss ich händisch immer MethName(@Button3Click) das Event angeben. Gibt es eine automatisierten Caller (sowas, wie "Self")?
- Kann ich den Namen der Methode schneller zurückgeben lassen (definierte String-Konstante / Methode ist über Faktor 20 schneller)?

Code: Alles auswählen

function MethName(E: TNotifyEvent): String; inline;
var
  Method: TMethod;
begin
  Method:=TMethod(E);
  Result:=TObject(Method.Data).MethodName(Method.Code);
end;
 
//{$DEFINE Test}
procedure TForm1.Button3Click(Sender: TObject);
var
  i, Cnt: Int32;
  s: String;
{$IFDEF Test}
const
  MethName = 'Button3Click';
{$ENDIF}
begin
  Cnt:=GetTickCount;
 
  {$IFDEF Test}
  for i:=0 to 10000000 do
    s:=MethName;
  {$ELSE}
  for i:=0 to 10000000 do
    s:=MethName(@Button3Click);
  {$ENDIF}
 
  Caption:=IntToStr(GetTickCount - Cnt);
end;

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Socke »

Der Compiler definiert kein Compiler-Makro, aus dem man solche Informationen holen könnte.

Aus den Debugging-Informationen kann man sich ebenfalls die Daten holen; Das Programm muss dann aber mit -gl kompiliert werden und diese auch mit verteilt werden.
Nachteil auch hier: irgendwie muss man an eine Adresse kommen (Methode selbst oder in eine Adresse innerhalb der Methode).

Code: Alles auswählen

 
uses lineinfo;
// ...
procedure TForm1.FormCreate(Sender: TObject);
var
  n: shortstring;
  l: longint;
  s: Shortstring;
begin
  // Adresse über Exception erfragen
 try
   raise Exception.Create('test');
 except
   on e: Exception do
   begin
     n := '';
     l := 0;
     s := '';
     GetLineInfo(Ptruint(ExceptAddr), n, s, l);
     ShowMessage(n+' '+inttoStr(l)+' '+s);
   end;
 end;
 
  // Adresse der Methode selbst
  n := '';
  l := 0;
  s := ''; 
  GetLineInfo(Ptruint(TMethod(@FormCreate).Code), n, s, l);
  ShowMessage(n+' '+inttoStr(l)+' '+s);
end;
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Michl »

Erstmal danke für die Erklärung, so ähnliche Hinweise hatte ich auch schon in den Suchmaschinenfunden gelesen. Prinzipiell wäre das, wie die geworfene Exception das, wie ich es mir vorgstellt hätte, nur als eine eigene Methode. Leider würde dann ja immer die Methode an sich aufgerufen werden und dessen Name dargestellt.

Scheint so, die einfachste/schnellste Möglichkeit ist eine händische Eingabe der Methodennamen als Const-String innerhalb der jeweiligen Methode (puh, bedeutet für mich ne Menge Schreibkram :| ).

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Socke »

Michl hat geschrieben:Erstmal danke für die Erklärung, so ähnliche Hinweise hatte ich auch schon in den Suchmaschinenfunden gelesen. Prinzipiell wäre das, wie die geworfene Exception das, wie ich es mir vorgstellt hätte, nur als eine eigene Methode. Leider würde dann ja immer die Methode an sich aufgerufen werden und dessen Name dargestellt.

Scheint so, die einfachste/schnellste Möglichkeit ist eine händische Eingabe der Methodennamen als Const-String innerhalb der jeweiligen Methode (puh, bedeutet für mich ne Menge Schreibkram :| ).
In einer Exception kannst du auch den Stack nach oben abarbeiten und die aufrufende Methode ermitteln.

Die Eingabe kannst du dir über Code Templates vereinfachen; ich habe mir z.B. ein Template mit folgendem Inhalt erstellt:

Code: Alles auswählen

raise ENotImplemented.CreateFmt('Method %s not implemented.', ['$ProcedureName()']);
Im Code Editor kann ich dann das vergebene Code-Wort (2 Buchstaben) mit Strg+J erweitern und schon steht da:

Code: Alles auswählen

raise ENotImplemented.CreateFmt('Method %s not implemented.', ['TForm1.FormCreate']);
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Michl »

Interessant, werde mal sehen, ob ich das so realisiert bekomme,ob das so geht, wie ich wünsche und wie hoch der Zeitverlust zur Laufzeit ist. Die Anregung ist auf jeden Fall erstmal sehr gut!

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Michl »

Hey Socke,

Du bist der Größte!

Ich hatte gestern mich mit
Socke hat geschrieben:In einer Exception kannst du auch den Stack nach oben abarbeiten und die aufrufende Methode ermitteln.
eher erfolglos herumgeschlagen.

Doch der Hinweis
Socke hat geschrieben:Die Eingabe kannst du dir über Code Templates vereinfachen
, eine Nacht darüber geschlafen und ein wenig herumexperimentiert, ist genau das, was ich brauchte! Obwohl ich die die Code Templates schon kannte, habe ich sie bisher nie eingesetzt, da die Codevervollständigung bisher immer sehr nützlich war.

Vielen Dank! :) :) :)

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Michl »

Ganz neu im FPC-Trunc implementiert ist die Möglichkeit der Ausgabe eines Methodennamens:

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage({$I %CURRENTROUTINE%});  //Gibt "Button1Click" aus
end; 
Damit ist es noch einfacher einen einfachen Log zu machen (falls man nicht die Debuginfo auslesen will), siehe: http://lists.lazarus.freepascal.org/pip ... 92266.html

Find ich gut, hätte es diese Möglichkeit schon damals gegeben, hätte ich meinen Log wahrscheinlich anders aufgebaut.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Patito
Beiträge: 203
Registriert: Di 22. Sep 2009, 13:08
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Patito »

Michl hat geschrieben:Ganz neu im FPC-Trunc implementiert ist die Möglichkeit der Ausgabe eines Methodennamens:

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage({$I %CURRENTROUTINE%});  //Gibt "Button1Click" aus
end; 
Schon wieder neue Orchideen-Syntax...
Warum schreibt man hier nicht einfach "Button1Click" statt "{$I %CURRENTROUTINE%}"?

Pascal war mal bekannt dafür, dass die Syntax einfach und nicht völlig daneben ist...

marcov
Beiträge: 1102
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von marcov »

Patito hat geschrieben:
Michl hat geschrieben:Ganz neu im FPC-Trunc implementiert ist die Möglichkeit der Ausgabe eines Methodennamens:

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage({$I %CURRENTROUTINE%});  //Gibt "Button1Click" aus
end; 
Schon wieder neue Orchideen-Syntax...
Warum schreibt man hier nicht einfach "Button1Click" statt "{$I %CURRENTROUTINE%}"?
Meistens hat man ein festes Prologe und Epiloge zu einen Prozedur/Methode. Die können komplizierter sein, und werden also oft rund kopiert. Damit ist es ein Risiko das die Namen nicht korrigiert werden.

Patito
Beiträge: 203
Registriert: Di 22. Sep 2009, 13:08
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Patito »

marcov hat geschrieben:
Patito hat geschrieben:
Michl hat geschrieben:Ganz neu im FPC-Trunc implementiert ist die Möglichkeit der Ausgabe eines Methodennamens:

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage({$I %CURRENTROUTINE%});  //Gibt "Button1Click" aus
end; 
Schon wieder neue Orchideen-Syntax...
Warum schreibt man hier nicht einfach "Button1Click" statt "{$I %CURRENTROUTINE%}"?
Meistens hat man ein festes Prologe und Epiloge zu einen Prozedur/Methode. Die können komplizierter sein, und werden also oft rund kopiert. Damit ist es ein Risiko das die Namen nicht korrigiert werden.
Prozedur und Unit-Namen sind Debug-Informationen und gehören gar nicht in den Usercode.
Wenn man beim Debuggen Spezialsyntax gegen Probleme beim Kopieren benötigt, hat man eh schon verloren.

Der echte WFT ist aber, dass jemand die Syntax für Include-Files überladen hat... {$I %

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von mse »

Patito hat geschrieben: Der echte WFT ist aber, dass jemand die Syntax für Include-Files überladen hat... {$I %
So abwegig finde ich das nicht. {$I ...} meint "füge Quellcode ein", entweder aus einer Datei oder aus einer internen Quelle mit "%...%".

Patito
Beiträge: 203
Registriert: Di 22. Sep 2009, 13:08
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von Patito »

mse hat geschrieben:
Patito hat geschrieben: Der echte WFT ist aber, dass jemand die Syntax für Include-Files überladen hat... {$I %
So abwegig finde ich das nicht. {$I ...} meint "füge Quellcode ein", entweder aus einer Datei oder aus einer internen Quelle mit "%...%".
Also bei $I würde ich eher erwarten, dass er versucht den Filenamen, der sich aus den %...% ergibt zu laden.
Mal schauen... Auf Anhieb finde ich ~40 solche Statements - entspricht < 1% aller Include-Statements.
Ich schätze mal, es gibt mehr Code, der sich mit dem Parsen dieser Statements beschäftigt, als Code, der es sinnvoll nutzt.
-> abwegige und überraschende Orchideen-Syntax

Wenn man sich den Ruf als Programmiersprachen mit sauberer Syntax nicht vermasseln will sollte man versuchen
das Zeug zurückzuschrauben - und es nicht auch noch ausbauen.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von mse »

Einverstanden, das ist auch ein wichtiges Ziel bei MSElang. Durch die Delphi-Kompatibilität sind dem Free Pascal-Team die Hände gebunden, alles was an Delphi kompatiblen Patches angeboten wird muss in Free Pascal integriert werden. Wobei ich jetzt nicht weiss ob ${i %...%} Delphi-kompatibel ist. ;-)

marcov
Beiträge: 1102
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: [gelöst] Name der aktuellen Prozedur als String

Beitrag von marcov »

Patito hat geschrieben:
Prozedur und Unit-Namen sind Debug-Informationen und gehören gar nicht in den Usercode.
Code runnt nicht immer im Debugger. Dann kommt Logging im Einsatz.
Wenn man beim Debuggen Spezialsyntax gegen Probleme beim Kopieren benötigt, hat man eh schon verloren.
Wenn du ein nicht triviales Programm mathematisch prüfen kann, dann ist das tatsächlich nicht noetig. :twisted:
Der echte WFT ist aber, dass jemand die Syntax für Include-Files überladen hat... {$I %
Wie schon gesagt, es inlined Code auf der scanner Ebene. File, environment variabele oder interner Informationen, das ist egal.

Antworten