Objekt orientierte Programmierung - Probleme mit Frames

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Helios
Lazarusforum e. V.
Beiträge: 106
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.4 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von Helios »

Hallo Forianer,
immer wenn ich denke ich habe die objektorientierte Programmierung mit Pascal im Griff, passiert soetwas:
Ich möchte meine wiederkehrenden Komponenten (in der späteren Applikation ein Grid und Start/Stop Abfrage
und Export Buttons) schön sauber und ordentlich in einem Frame kapseln und davon später dann mehrere
in der MainForm verwenden.
Wie greife ich denn von einem Child Objekt eines Parent Objektes auf ein anderes Child
Objekt des gleichen Parent Objektes zu. In meinem Beispiel möchte ich aus einem Thread des Frames in die
Statusbar ebendesgleichen Frames eine Timerinformation schreiben. Irgendwie habe ich ein Brett vor dem Kopf.
Bei einem TForm klappt das doch auch. Der kritische Abschnitt ist dieser:

Code: Alles auswählen

procedure TMyThread.ShowStatus;
// this method is executed by the mainthread and can therefore access all GUI elements.
begin
  // Hier soll der Timer innerhalb des Frames in der Statusbar angezeigt werden
  //TFrame1.StatusBar1.SimpleText := fStatusText;         // Compilierung n.i.O.
  //Form1.TFrame1_1.StatusBar1.SimpleText := fStatusText; // Compilierung n.i.O.
  //Application.Title := fStatusText; // compiliert i.O. aber setzt den Timer in das ShowMessage Fenster Ende des Threads
                                      // es soll aber in die StatusBar1 des Frames!
end;  
Aus meiner Sicht ein klassisches OOP Thema, das sich sicher elegant lösen lässt aber ich komme einfach nicht drauf
(Parent/Self hatte ich auch probiert sind aber aus meiner Sicht nicht passend).
Wer hat hier den Durchblick?
Danke für jede Hilfe und Gruß
Helios
Dateianhänge
FramesOnForm.zip
(127.69 KiB) 73-mal heruntergeladen

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von kupferstecher »

Helios hat geschrieben:
Mi 20. Okt 2021, 22:54

Code: Alles auswählen

  //TFrame1.StatusBar1.SimpleText := fStatusText;         // Compilierung n.i.O.
  //Form1.TFrame1_1.StatusBar1.SimpleText := fStatusText; // Compilierung n.i.O.
 
Du musst die Instanzen ansprechen und nicht die Klassen. Also
Frame1... statt TFrame1...

Code: Alles auswählen

  
  //Application.Title := fStatusText; // compiliert i.O. aber setzt den Timer in das ShowMessage Fenster Ende des Threads
Den Kommentar versteh ich nicht. "Application.Title" ist doch normalerweise der Name im Taskleistensymbol?

Helios
Lazarusforum e. V.
Beiträge: 106
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.4 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von Helios »

Hallo Kupferstecher,
leider funktionieren Frame1 oder Frame1_1 nicht. Mir ist auch nicht klar,wo die eigentliche Instanz von TFrame erzeugt wird.
Unter

Code: Alles auswählen

TForm1 = class(TForm) ... Frame1_1: TFrame1;
steht es ja eigentlich, aber da komme ich nicht "ran".
Das Frame1_1 hängt irgendwie unereicht in der Luft, bzw. ich habe keine echte Instanz vom TFrame.
Das mit dem

Code: Alles auswählen

Application.Title := fStatusText
war nur ein verzweifelter Versuch die Timer Daten in den Titel der Main Applikation zu schreiben.
Hast Du noch eine weitere Idee was ich falsch gemacht haben könnte?
Danke und Gruß
Helios

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von kupferstecher »

Code: Alles auswählen

implementation
uses
  Unit1;
[...]
Form1.Frame1_1.StatusBar1.SimpleText := fStatusText;
hallo Helios,

es hat das "uses Unit1" gefehlt. Dann kannst du auf die Form1 zugreifen und darüber auf das Frame. Das Frame wird von der LCL erzeugt.

Helios
Lazarusforum e. V.
Beiträge: 106
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.4 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von Helios »

Hallo Kupferstecher,
Danke Dir vielmals, das war die Lösung!
Bzgl. des Eintrags der Unit1 bei der Implementation der Unit2 und dem Eintrag Unit2 unter Interface der Unit1 noch die Frage:
Das ist dann kein Zirkelbezug, nicht mal ansatzweise (klar gibt keine Compilerfehlermeldung)?
Nebenwirkungen sind nicht zu erwarten und so wie es jetzt ist, kann man es als gängige Praxis bezeichnen?
Sorry mir fehlt da die praktische Erfahrung und brauche da nochmal (D)eine Bestätigung.
Danke und gute Nacht!
Helios

Socke
Lazarusforum e. V.
Beiträge: 3158
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: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von Socke »

Wenn du in einem Projekt das Frame mehrfach erzeugst, funktioniert die direkte Referenzierung eines bestimmten Forms/Frames nicht mehr.

Besser du übergibst dem Thread einfach das zugehörige Frame:

Code: Alles auswählen

type
  TFrame1 = class; // forward-Deklaration, damit der Name schon für TMyThread bekannt ist.

  { TMyThread }
  TMyThread = class(TThread)
  private
    fStatusText : string;
    fOwnerFrame: TFrame1; // neue Referenz auf den Frame
    procedure ShowStatus;
  protected
    procedure Execute; override;
  public
    Constructor Create(CreateSuspended : boolean);
    property OwnerFrame: TFrame1 read fOnwerFrame write fOwnerFrame;
  end;

procedure TFrame1.Button1Click(Sender: TObject);
begin
  if (not IsThreadRunning) then
  begin
    MyThread := TMyThread.Create(True);
    MyThread.OnTerminate := @OnThreadDone;
    MyThread.OwnerFrame := Self; // Frame an Thread übergeben
    MyThread.Start;
    IsThreadRunning := true;
    Button1.Caption := 'Stop'
  end
  else
  begin
    MyThread.Terminate;
    Button1.Caption := 'Start';
  end;
  Application.ProcessMessages;
end;

procedure TMyThread.ShowStatus;
// this method is executed by the mainthread and can therefore access all GUI elements.
begin
  // Hier soll der Timer innerhalb des Frames in der Statusbar angezeigt werden
  if Assigned(fOwnerFrame) then
    fOwnerFrame.StatusBar1.SimpleText := fStatusText;
end;
Tipp: In der Methode OnThreadDone solltest du noch die Referenz auf den Thread aufräumen.

Code: Alles auswählen

procedure TFrame1.OnThreadDone(Sender: TObject);
begin
  IsThreadRunning := false;
  MyThread := nil; // Thread-Objekt wird durch FreeOnTerminate freigegeben, daher hier nur noch auf nil setzen.
  ShowMessage('TMyThread Stopped');
end;
Tipp 2: Anstatt der Variablen IsThreadRunning kannst du auch einfach den Thread selbst fragen:

Code: Alles auswählen

Function TFrame1.GetThreadIsRunning: Boolean;
begin
  if Assigned(MyThread) then // prüfen, ob der Thread bereits erzeugt wurde
    Result := not MyThread.Finished // Thread läuft noch oder wartet auf die Ausführung von OnThreadDone
  else
    Result := False; // Thread wurde noch nicht gestartet oder ist bereits fertig
 end;
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Helios
Lazarusforum e. V.
Beiträge: 106
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.4 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von Helios »

Guten Morgen Socke,
Hammer!!! Heute morgen bin ich genau mit der Frage (das Frame und die Form sind ja noch gar nicht richtig "entkoppelt" um das Frame als eigenständige Komponemte zu nutzen) aufgewacht und die Antwort steht hier schon im Forum. Weiterhin hat mir die Lösung mit dem "IsThreadRunning" auch noch nicht gefallen und Du schreibst mir die Lösung runter, auf die ich allein nicht gekommen wäre. Ihr seid wirklich Spitze hier, vielen, vielen Dank!
Schönen Tag, bleibt gesund und viele Grüße
Helios

PS: Das "Ticket" werde ich schließen, sobald Eure Ideen funktional eingebaut sind (das schaffe ich zeitlich erst morgen ;-) ).

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6199
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von af0815 »

Ich verwende ein Frame als wirklich strikt getrennten Container. Wenn ich wirklich zwischen 2 Frames kommunizieren muss, so immer über den Elternteil. Daher im Frame rufe ich einen Callback Event auf (zB. OnMySpezialPressed) dieser wird vom Parent dann an das weitere Frame richtig weitergegeben. Das Beispiel von Socke mit dem fOwnerFrame ist so aufgebaut.

Der Vorteil, das Frame lässt sich über die strikten Schnittstellen auch ohne die volle Applikation testen. Ist etwas mehr denkarbeit einmalig, aber dafür kann man dann super arbeiten ohne sich um die ganze Applikation zu kümmern, weil das Frame später dort echt nur hineingehängt wird.

Was auch mit Frames sehr gut geht, ist echte Vererbung. Ich habe mit ein BasisFrame gezimmert in dem meine wiederkehrenden Besonderheiten hinterlegt sind. Das ist für mich die Basis für andere Frames. Das funktioniert super.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Helios
Lazarusforum e. V.
Beiträge: 106
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.4 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von Helios »

Hallo af0815,
hast Du da evtl. ein griffiges Beispiel. Meine Codeschnipsel (hat man vielleicht auch gesehen) sind da meistens den Tutorials aus den Foren oder auf der Lazarus Wiki entnommen und die gehen nicht so in die Tiefe (das können und sollen sie ja i.d.R. nicht) wie man es dann im konkreten Anwendungsfall benötigt.
Allein zu den Thread könnte man ja schon ein Buch schreiben, was es da für Tipps und Tricks gibt.
Das Gleiche gilt wahrscheinlich auch für die (Callback) Events (an die habe ich mich noch nicht richtig "rangetraut").
Danke und Gruß
Helios

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6199
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von af0815 »

Hier einmal ein Beispiel für mein Baseframe. Ein paar zusätzliche Sachen musste ich ausräumen. Aber es zeigt den Fall mal

Erzeugt wird bei mir alles zur Laufzeit in etwas so

Code: Alles auswählen

  if not assigned(FrameMain) then begin
    try
      // Frame Main
      FrameMain:= TFrameMain.Create(TabSheet1);
      FrameMain.Parent:= TabSheet1;
      FrameMain.Connection:= GetConnectionSQL.GetCon; // Hier wird auf eine Connection verwiesen
      FrameMain.Align:= alClient;
      FrameMain.XMLPropStorage:= XMLPropStorage1;          // Über das kann man dann persistent Infos nachladen wenn nötig
    except
      //
    end;
  end;
Bitte die Demo.pas in frbaseframe.pas umbenennen.
Dateianhänge
Demo.pas
(3.52 KiB) 78-mal heruntergeladen
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von kupferstecher »

Helios hat geschrieben:
Do 21. Okt 2021, 00:54
Das ist dann kein Zirkelbezug, nicht mal ansatzweise (klar gibt keine Compilerfehlermeldung)?
Nebenwirkungen sind nicht zu erwarten und so wie es jetzt ist, kann man es als gängige Praxis bezeichnen?
Hallo Helios,

Zirkelbezüge im Implementation-Teil würde ich durchaus als gängige Praxis bezeichnen, es gibt da definitiv keine Nebenwirkungen. Allerdings wie ja schon angeklungen ist, ist das für eine saubere Architektur nicht unbedingt hilfreich. Insgesamt seh ich das nicht so eng und entscheide je nach Umständen, ob eine vollständige Kapselung mit Callbacks und zusätzlichen Variablen notwendig ist.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6199
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Objekt orientierte Programmierung - Probleme mit Frames

Beitrag von af0815 »

kupferstecher hat geschrieben:
Do 21. Okt 2021, 13:38
Insgesamt seh ich das nicht so eng und entscheide je nach Umständen, ob eine vollständige Kapselung mit Callbacks und zusätzlichen Variablen notwendig ist.
Wenn man sich das mit der Kapselung angewöhnt, ist man immer auf der sicheren Seite, auch wenn das Projekt später wächst. Die Umstände sprechen immer gegen eine Kapselung :-) 'Ist ja eh nur das eine mal, da schnell ........ :mrgreen:
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten