Zugriff auf TMemo von einem nichtgrafischen Objekt
- 
				charlytango
 - Beiträge: 1198
 - 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
Was bedeutet das?charlytango hat geschrieben: Mag sein dass ich da auf dem Holzweg bin, denn das will einfach so nicht klappen.
- 
				mschnell
 - 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: 2855
 - 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
Das ist Quark. TMemo benutzt TStrings, leitet aber nicht davon ab.mschnell hat geschrieben:TMemo ist ein Nachfolger von TStrings.
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.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.Soweit erst einmal der grobe Überblick. Bei Fragen => fragen.
0118999881999119725-3
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
						Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
- 
				charlytango
 - Beiträge: 1198
 - 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 ü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"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) 130-mal heruntergeladen
 
 
- m.fuchs
 - Lazarusforum e. V.
 - Beiträge: 2855
 - 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)0118999881999119725-3
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
						Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
- 
				charlytango
 - Beiträge: 1198
 - 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) 121-mal heruntergeladen
 
 
- 
				SchwabenTom
 - 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);
- 
				mschnell
 - 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
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.m.fuchs hat geschrieben:TMemo benutzt TStrings, leitet aber nicht davon ab.
-Michael