Zugriff auf TMemo von einem nichtgrafischen Objekt
-
- Beiträge: 843
- Registriert: Sa 12. Sep 2015, 12:10
- OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
- CPU-Target: Win 32/64, Linux64
- Wohnort: Wien
Zugriff auf TMemo von einem nichtgrafischen Objekt
Hallo!
Klassischer Ansatz bei einer Applikation mit MainForm und einem mit Ereignisprozedur erzeugten Objekt (in eine eigene Unit ausgelagert) in dem irgend etwas passiert von dem der Benutzer in Kenntnis gesetzt werden soll. In diesem Fall einfach mit einer neuen Zeile in ein TMemo auf dem MainForm.
Das Mainform in die Objektunit eingebunden und schon kann direkt darauf zugegriffen werden.
Im Bestreben Programmlogik samt deren Wiederverwendbarkeit in ein eigenes Objekt in eine getrennte Unit auszulagern (um sie in anderen Applikationen unverändert weiter verwenden zu können) aber leider keine elegante Lösung.
Ich dachte da an ein Property etc. im Objekt dem ich das TMemo von außen zuweise. Innerhalb des Objektes wird ins Memo geschrieben wenn das entsprechende Property zugewiesen wurde.
Mag sein dass ich da auf dem Holzweg bin, denn das will einfach so nicht klappen. An sich sollte das nicht nur mit einem TMemo sondern evtl auch mit einem Progressbar funktionieren.
Bin für Anregungen zu einer eleganten Lösung dankbar, denn derartige Anforderungen werden sicher nicht neu sein.
Danke im Voraus
CharlyTango
Klassischer Ansatz bei einer Applikation mit MainForm und einem mit Ereignisprozedur erzeugten Objekt (in eine eigene Unit ausgelagert) in dem irgend etwas passiert von dem der Benutzer in Kenntnis gesetzt werden soll. In diesem Fall einfach mit einer neuen Zeile in ein TMemo auf dem MainForm.
Das Mainform in die Objektunit eingebunden und schon kann direkt darauf zugegriffen werden.
Im Bestreben Programmlogik samt deren Wiederverwendbarkeit in ein eigenes Objekt in eine getrennte Unit auszulagern (um sie in anderen Applikationen unverändert weiter verwenden zu können) aber leider keine elegante Lösung.
Ich dachte da an ein Property etc. im Objekt dem ich das TMemo von außen zuweise. Innerhalb des Objektes wird ins Memo geschrieben wenn das entsprechende Property zugewiesen wurde.
Mag sein dass ich da auf dem Holzweg bin, denn das will einfach so nicht klappen. An sich sollte das nicht nur mit einem TMemo sondern evtl auch mit einem Progressbar funktionieren.
Bin für Anregungen zu einer eleganten Lösung dankbar, denn derartige Anforderungen werden sicher nicht neu sein.
Danke im Voraus
CharlyTango
Re: Zugriff auf TMemo von einem nichtgrafischen Objekt
charlytango hat geschrieben:Mag sein dass ich da auf dem Holzweg bin, denn das will einfach so nicht klappen.
Was bedeutet das?
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: Zugriff auf TMemo von einem nichtgrafischen Objekt
TMemo ist ein Nachfolger von TStrings.
Du kannst das Memo z.B. an eine Funktion über einen Parameter mit TStrings übergeben und dort mit den Funktionalitäten von TStrings bearbeiten.
Die Unit mit dieser Funktion braucht dann keine grafischen Units zu usen. (Wenn es das ist, was Du meinst...)
-Michael
Du kannst das Memo z.B. an eine Funktion über einen Parameter mit TStrings übergeben und dort mit den Funktionalitäten von TStrings bearbeiten.
Die Unit mit dieser Funktion braucht dann keine grafischen Units zu usen. (Wenn es das ist, was Du meinst...)
-Michael
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2636
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Zugriff auf TMemo von einem nichtgrafischen Objekt
mschnell hat geschrieben:TMemo ist ein Nachfolger von TStrings.
Das ist Quark. TMemo benutzt TStrings, leitet aber nicht davon ab.
Aber zur eigentlichen Frage. Für maximale Trennung und Wiederverwendbarkeit, bietet sich ein Interface an. Nehmen wir mal an, deine Programmlogik besteht aus einer Klasse TMyService mit der Methode DoSomething. Wird die Methode aufgerufen, dann soll ein Zähler von 0 bis 200 hochzählen. Bei jedem Schritt soll sich ein ProgressBar bewegen und in einem Memo eine neue Zeile hinzugefügt werden. Aber wie du ja schon richtig erkannt hast, ist diese grafische Ausgabe in einem anderen Programm vielleicht völlig anders. Dann gehen wir den Weg über ein Interface:
Code: Alles auswählen
unit Service;
{$MODE ObjFpc}
{$H+}
{$INTERFACES CORBA}
interface
uses
Classes, SysUtils;
type
IListener = interface
procedure Step;
procedure AddLogline(Line: String);
end;
TMyService = class(TObject)
private
FListener: IListener;
public
property Listener: IListener read FListener write FListener;
public
procedure DoSomething;
end;
implementation
procedure TMyService.DoSomething;
var
i: Integer;
begin
for i := 0 to 200 do begin
Sleep(100);
FListener.AddLogline('We are in cycle #' + IntToStr(i));
FListener.Step;
end;
end;
end.
Das Interface kann von jeder beliebigen Klasse implementiert werden, das heißt diese Klasse muss dann die beiden Methoden Step und AddLogline anbieten. Das sieht in einem einfachen Form mit Button, Progressbar und Memo dann so aus:
Code: Alles auswählen
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls,
Service;
type
TForm1 = class(TForm, IListener)
Button1: TButton;
Memo1: TMemo;
ProgressBar1: TProgressBar;
procedure Button1Click(Sender: TObject);
public
procedure Step;
procedure AddLogline(Line: String);
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
procedure TForm1.Button1Click(Sender: TObject);
var
MyService: TMyService;
begin
try
MyService := TMyService.Create;
MyService.Listener := Self;
MyService.DoSomething;
finally
FreeAndNil(MyService);
end;
end;
procedure TForm1.Step;
begin
ProgressBar1.StepIt;
Application.ProcessMessages;
end;
procedure TForm1.AddLogline(Line: String);
begin
Memo1.Append(Line);
Application.ProcessMessages;
end;
end.
Willst du deinen Service dann in einem anderen Programm wiederverwenden, musst du dort nur das Interface implementieren wie oben dargestellt.
Soweit erst einmal der grobe Überblick. Bei Fragen => fragen.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
-
- Beiträge: 843
- Registriert: Sa 12. Sep 2015, 12:10
- OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
- CPU-Target: Win 32/64, Linux64
- Wohnort: Wien
Re: Zugriff auf TMemo von einem nichtgrafischen Objekt
Erstmal danke für die ausführliche Antwort!
Elegant ist die Lösung allemal, wenngleich etwas mehr Aufwand als ich erwartet habe
Den vorgeschlagenen Code habe ich ohne Änderung in eine Applikation zum Test umgewandelt.
Ganz klar ist mir der Zusammenhang zwischen dem Mainform und dem Interface nicht.
Woher weiß das Mainform welches Interface zum Tragen kommt?
Bloss durch die Zuweisung
im Mainform und die namensgleichen Funktionen in der public-Sektion des Mainforms?
im übrigen wird die Zeile vom Kompiler bemängelt:
die Verbindung in der Unit services zum Interface ist klar, indem in TMyService.DoSomething die Interface-Prozeduren aufgerufen werden.
Bloß die Verbindung zum TMemo im Mainform erschließt sich mir nicht -> daher frage ich nochmal um Erklärung nach
LG
Elegant ist die Lösung allemal, wenngleich etwas mehr Aufwand als ich erwartet habe
Den vorgeschlagenen Code habe ich ohne Änderung in eine Applikation zum Test umgewandelt.
Ganz klar ist mir der Zusammenhang zwischen dem Mainform und dem Interface nicht.
Woher weiß das Mainform welches Interface zum Tragen kommt?
Bloss durch die Zuweisung
Code: Alles auswählen
MyService.Listener := Self;
im Mainform und die namensgleichen Funktionen in der public-Sektion des Mainforms?
im übrigen wird die Zeile vom Kompiler bemängelt:
Code: Alles auswählen
Projekt kompilieren, Ziel: testinterface.exe: Exit code 1, Fehler: 1
fmain.pas(39,27) Error: Incompatible types: got "TForm1" expected "IListener"
die Verbindung in der Unit services zum Interface ist klar, indem in TMyService.DoSomething die Interface-Prozeduren aufgerufen werden.
Bloß die Verbindung zum TMemo im Mainform erschließt sich mir nicht -> daher frage ich nochmal um Erklärung nach
LG
- Dateianhänge
-
- test_Interface.zip
- (1.81 KiB) 63-mal heruntergeladen
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2636
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Zugriff auf TMemo von einem nichtgrafischen Objekt
Da hast du wohl eine Kleinigkeit übersehen:
Das sagt dem Compiler, dass TForm1 von der Klasse TForm abgeleitet ist und das Interface IListener implementiert (weitere Interfaces könnten komma-getrennt hinzugefügt werden). Das in Verbindung mit den implementierten Methoden erlaubt dir auch die Zuweisung, an der momentan bei dir der Compiler stolpert.
Code: Alles auswählen
type
TForm1 = class(TForm, IListener)
Das sagt dem Compiler, dass TForm1 von der Klasse TForm abgeleitet ist und das Interface IListener implementiert (weitere Interfaces könnten komma-getrennt hinzugefügt werden). Das in Verbindung mit den implementierten Methoden erlaubt dir auch die Zuweisung, an der momentan bei dir der Compiler stolpert.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
-
- Beiträge: 843
- Registriert: Sa 12. Sep 2015, 12:10
- OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
- CPU-Target: Win 32/64, Linux64
- Wohnort: Wien
Re: Zugriff auf TMemo von einem nichtgrafischen Objekt
Von wegen Kleinigkeit
da war ich wohl eher blind wie der sprichwörtliche Maulwurf.
Danke für den Hinweis --- somit klappt alles.
Danke für die Hilfe ! Jetzt hab ich Eleganz und Funktion.
Für die Suchenden habe ich den funktionierenden Source nochmal attached.
CASE CLOSED
da war ich wohl eher blind wie der sprichwörtliche Maulwurf.
Danke für den Hinweis --- somit klappt alles.
Danke für die Hilfe ! Jetzt hab ich Eleganz und Funktion.
Für die Suchenden habe ich den funktionierenden Source nochmal attached.
CASE CLOSED
- Dateianhänge
-
- test_Interface.zip
- (1.81 KiB) 54-mal heruntergeladen
-
- Beiträge: 49
- Registriert: So 4. Jan 2015, 21:34
- OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
- CPU-Target: xxBit
Re: Zugriff auf TMemo von einem nichtgrafischen Objekt
Du kannst mit einer Referenz auf eine Funktion/Methode arbeiten. Beispiele sind OnClick, OnPaint in Formularen.
PS.: Sorry, daß ich dir keinen Code posten kann. Arbeite mich selbst noch in Lazarus ein.
Du hast eine Unit. In dieser Unit definierst du dein TOnProgress. Das wird irgendwas wie ein TNotifyEvent sein - keine Ahnung wie es in Lazarus genau heißt. In dieser Unit hast dann entweder eine globale Variable OnProgress (var OnProgress: TOnProgress;) oder eben als ein Member in deiner Klasse. Du initialisierst es mit nil. Derjenige (bzw. du in deinem "Hauptprogramm"), der deine Unit benutzt, bindet deine Unit mit uses ein. Er definiert in seiner Unit eine Funktion MeldeMirDeinenProgress die vom Typ TOnProgress ist. Dieses MeldeMirDeinenProgress weist er dann der OnProgress-Variable deine Unit zu (bzw. wenn er eine Instanz deiner Klasse erstellt hat, dem betreffenden Member in dieser Klasse/Instanz). So ist die "Verknüpfung" dann erstellt.
Oft ist ein recht gutes Vorgehen sogar, überhaupt keine Parameter zu übergeben. Nur das "Event" wird "ausgelöst". Der Nutzer deiner Unit/Klasse/Framework kennt deine Unit und weiß, wo er sich dann die Daten holen kann, wenn das Event eintritt. Er holt sich dann auch nur das, was er tatsächlich in nur dem jeweiligen Kontext braucht.
In deiner Unit arbeitest du dann so:
if Assigned(FOnProgress) then
FOnProgress(ParameterFallsDuWelcheDefiniertHast);
PS.: Sorry, daß ich dir keinen Code posten kann. Arbeite mich selbst noch in Lazarus ein.
Du hast eine Unit. In dieser Unit definierst du dein TOnProgress. Das wird irgendwas wie ein TNotifyEvent sein - keine Ahnung wie es in Lazarus genau heißt. In dieser Unit hast dann entweder eine globale Variable OnProgress (var OnProgress: TOnProgress;) oder eben als ein Member in deiner Klasse. Du initialisierst es mit nil. Derjenige (bzw. du in deinem "Hauptprogramm"), der deine Unit benutzt, bindet deine Unit mit uses ein. Er definiert in seiner Unit eine Funktion MeldeMirDeinenProgress die vom Typ TOnProgress ist. Dieses MeldeMirDeinenProgress weist er dann der OnProgress-Variable deine Unit zu (bzw. wenn er eine Instanz deiner Klasse erstellt hat, dem betreffenden Member in dieser Klasse/Instanz). So ist die "Verknüpfung" dann erstellt.
Oft ist ein recht gutes Vorgehen sogar, überhaupt keine Parameter zu übergeben. Nur das "Event" wird "ausgelöst". Der Nutzer deiner Unit/Klasse/Framework kennt deine Unit und weiß, wo er sich dann die Daten holen kann, wenn das Event eintritt. Er holt sich dann auch nur das, was er tatsächlich in nur dem jeweiligen Kontext braucht.
In deiner Unit arbeitest du dann so:
if Assigned(FOnProgress) then
FOnProgress(ParameterFallsDuWelcheDefiniertHast);
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: Zugriff auf TMemo von einem nichtgrafischen Objekt
m.fuchs hat geschrieben:TMemo benutzt TStrings, leitet aber nicht davon ab.
Sorry für den Irrtum. Die Übergabe der Lines Property an nicht grafische Units (das war ja wohl die Frage) ist davon aber unabhängig.
-Michael