Von Objekt auf übergeordnetes Objekt zugreifen

Dalai

Grand Admiral Special
Mitglied seit
14.06.2004
Beiträge
7.420
Renomée
262
Standort
Meiningen, Thüringen
Hallo Forum :).

Leider lässt sich mein Problem schwierig beschreiben, deswegen auch dieser etwas seltsame Titel. Noch ein Hinweis vorweg: die Fettschreibungen im Code habe ich aus Gründen der Lesbarkeit gemacht, also so eine Art Syntax Highlighting ;).

Folgendes: ich habe eine Klasse gebastelt, die diverse VCL-Objekte beinhaltet.
Rich (BBCode):
type
  TLaunch = class
  private
      // Standard-Variablen
      sCaption          : string;
      sText             : string;
      sExecFile         : string;
      sExecParams       : string;
      dwExecFlag        : DWORD;

      // VCL-Objekte
      btnButton         : TMyButton;
      lblText           : TLabel;

  public
     constructor Create(AOwner: TComponent);
     destructor Destroy; override;

  published
      procedure SetLaunchClick(event: TNotifyEvent);
end;
Diese Klasse befindet sich - wie sich das gehört - in einer eigenen Unit (bei C/++ wäre sie in einem Header). Im Hauptprogramm werden nun Instanzen dieser Klasse erzeugt und in einem (dynamischen) Feld gespeichert - soweit so schön :).

Das OnClick-Ereignis des Buttons wird mithilfe der Methode SetLaunchClick zugewiesen. Ausgeführt wird dann beim Klick auf einen der Buttons eine Methode aus dem Hauptprogramm:
Rich (BBCode):
procedure TMainForm.LaunchClick(Sender: TObject);
var SEI: TShellExecuteInfo;
    tmyb: TMyButton;
begin
    tmyb:= (Sender as TMyButton);
    FillChar(SEI, SizeOf(SEI), 0); // Wipe the record to start with
    SEI.cbSize:= SizeOf(SEI);
    SEI.fMask:= SEE_MASK_NOCLOSEPROCESS;
    SEI.Wnd:= Application.Handle;
    SEI.lpFile:= PChar(ExtractFileName(tmyb.Exec));
    SEI.lpDirectory:= PChar(ExtractFileDir(tmyb.Exec));
    SEI.nShow:= tmyb.Flags;
    SEI.lpParameters:= PChar(tmyb.Params);
    ShellExecuteEx(@SEI);
end;
Das Problem hierbei: Sender ist vom Typ TMyButton, also ein "Unterobjekt" meiner Klasse TLaunch. Nun muss ich aber auf diverse Eigenschaften meiner Klasse TLaunch zugreifen. Wie bekomme ich das (sinnvoll) mit wenig Aufwand hin?

Bisher habe ich es so gemacht, dass ich einen Feldindex beim Erzeugen von TLaunch übergeben und der Eigenschaft Tag des TMyButton zugewiesen habe. Dann kann man beim Klicken diese Eigenschaft auslesen und hat den Feldindex. Aber ich denke mir, dass das unsicher sein könnte.
In obigem Code habe ich dem TMyButton zusätzliche Eigenschaften zugeordnet, die ich auslese. Aber das wird natürlich affig, wenn ich an viele Variablen/Eigenschaften meiner Klasse TLaunch ran muss :(.

Geht das irgendwie besser?

MfG Dalai
 
Zuletzt bearbeitet:
Hab ich das Problem zu umständlich/unverständlich beschrieben? Oder hat keiner ne Idee? :-/ Sollte doch kein Problem sein, dass es Delphi ist, oder? Irgendjemand war doch sicherlich schon in einer solchen/ähnlichen Situation...

Zur weiteren Erklärung: die Ereignisbehandlung OnClick muss im Hauptprogramm stehen, weil ich Daten auf die GUI schreiben muss (bisher noch nicht implementiert). Sowas von einer Unit aus zu machen ist ja nicht so die feine Art. Ich möchte die Programmlogik möglichst von der GUI trennen. Da das Ausgeben der Daten aber recht zeitkritisch geschehen muss, reicht auch keine Methode mit Rückgabe eines Strings o.ä.

MfG Dalai
 
Zuletzt bearbeitet:
Versuchs mal mit "parent".
Parent ist vom Typ TForm (eben die Form, auf dem der Button dargestellt wird) und nicht vom Typ TLaunch. Der Parent muss auch ein VCL-Objekt sein, damit der Button sichtbar wird.

Inzwischen habe ich eine Lösung gefunden (ereignisbasiert), habe aber noch keine Zeit gehabt, sie hier zu posten. Ich werde es aber in jedem Fall noch tun, wenn ich Zeit dafür finde!

MfG Dalai
 
So, ab geht's zur Lösung :D.

Erklärung des Ganzen: das OnClick-Ereignis des Buttons btnButton wird auf ein Ereignis OnButtonClick der Klasse TLaunch umgeleitet. Oder anders ausgedrückt: wenn man den Button klickt, wird das Ereignis OnClick des Buttons und damit das Ereignis OnButtonClick von TLaunch ausgelöst. Dazu brauchen wir:
  • eine Methode zur Behandlung des Ereignisses OnButtonClick (private)
  • ein public TNotifyEvent, um von außen eine Ereignis-Zuweisung machen zu können
  • im Hauptprogramm eine Zuweisung und eine Methode für die Behandlung des Ereignisses
Die Klasse TLaunch sieht dann so aus (benötigte neue Sachen farbig markiert):
Rich (BBCode):
type
  TLaunch = class
  private
      // Standard-Variablen
      sCaption          : string;
      sText             : string;
      sExecFile         : string;
      sExecParams       : string;
      dwExecFlag        : DWORD;

      // VCL-Objekte
      btnButton         : TButton;
      lblText           : TLabel;

      procedure ButtonClick(Sender: TObject); // Methode zur Ereignisbehandlung

  public
     constructor Create(AOwner: TComponent);
     destructor Destroy; override;

     OnButtonClick: TNotifyEvent; // Ereignis deklarieren

  published
      property ExecFile: string
                     read sExecFile;
      property ExecParams: string
                     read sExecParams;
      property ExecWorkDir: string
                     read sExecWorkDir;
      property ExecFlag: DWORD
                     read dwExecFlag;
end;
Die Implementation der Methode ButtonClick sieht dann so simpel aus:
Code:
procedure TLaunch.ButtonClick(Sender: TObject);
begin
    if Assigned(OnButtonClick) then OnButtonClick(Self);
end;
Damit beim Klick auf den Button auch was passiert, kann man z.B. im Konstruktor von TLaunch diese Zuweisung machen:
Code:
Self.btnButton.OnClick:= ButtonClick;
Damit wird die Methode ButtonClick aufgerufen und diese wiederum ruft die Methode auf, die von außerhalb der Klasse auf das Ereignis OnButtonClick zugewiesen wurde. Diese Zuweisung des Ereignisses (im Hauptprogramm) sieht folgendermaßen aus:
Code:
var launch: TLaunch;
launch:= TLaunch.Create(MainForm);
launch.OnButtonClick:= MainForm.LaunchClick; // Ereignisbehandlungsroutine zuweisen
Damit ändert sich die Methode LaunchClick wie folgt:
Rich (BBCode):
// --- Ereignisbehandlung für OnButtonClick
procedure TMainForm.LaunchClick(Sender: TObject);
var
    // normale Ausführung
    SEI: TShellExecuteInfo;
    obj: TLaunch;
begin
    obj:= (Sender as TLaunch);
    FillChar(SEI, SizeOf(SEI), 0); // Wipe the record to start with
    SEI.cbSize:= SizeOf(SEI);
    SEI.fMask:= SEE_MASK_NOCLOSEPROCESS;
    SEI.Wnd:= Application.Handle;
    SEI.lpFile:= PChar(ExtractFileName(obj.ExecFile));
    SEI.lpDirectory:= PChar(obj.ExecWorkDir);
    SEI.nShow:= obj.ExecFlag;
    SEI.lpParameters:= PChar(obj.ExecParams);
    ShellExecuteEx(@SEI);
end;
Damit ist sichergestellt, dass man ein TLaunch-Objekt bekommt und kann dann auf die Eigenschaften desselben zugreifen :). Das Schöne daran: man kann das mit beliebigen Ereignissen ergänzen, wenn nötig, also z.B. OnLabelClick o.ä. Man braucht dann wieder die gleichen Sachen wie oben zu sehen.

Wenn man einmal die Ereignisse begriffen hat, geht's eigentlich ganz einfach ;D.

MfG Dalai
 
Zuletzt bearbeitet:
Zurück
Oben Unten