Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Update eines Labels aus einer Verarbeitungsschleife (https://www.delphipraxis.net/115131-update-eines-labels-aus-einer-verarbeitungsschleife.html)

p80286 6. Jun 2008 12:33


Update eines Labels aus einer Verarbeitungsschleife
 
Hallo zusammen,

die meisten Programme, die ich schreibe, beschäftigen sich damit, Dateien zu lesen, die Daten zu verarbeiten und wieder neue Dateien zu schreiben. Da diese Dateien oft etwas größer als 100 MB sind, dauert die Verarbeitung auch etwas. Dann ist es kein Fehler den Benutzer über einen Satzzähler oder einen Fortschritsbalken oä zu informieren.
Da ich versuche die Verarbeitungsschritte von der Oberfläche zu trennen habe ich das Problem den Zähler an die Oberfläche zu übergeben.
Bisher habe ich zwei Wege beschritten:

a) Mit Hilfe des Timers lese ich eine Zählervariable in der Verarbeitungsunit aus,
b) Ich übergebe ein Label/Fortschrittbalken an die Verarbeitungsroutine. Ist der Wert des Labels <> nil dann wird der Zähler ausgegeben.

Beide Wege funktionieren.

Nun hätte ich gerne einen Tip wie ich ohne großen Overhead Oberfläche und Verarbeitung stärker entkoppeln kann. Wichtig ist daß die meiste Rechenzeit wirklich für die Verarbeitung und nicht für die Oberfläche genutzt wird.

Vielen Dank im voraus
K-H

SirThornberry 6. Jun 2008 12:43

Re: Update eines Labels aus einer Verarbeitungsschleife
 
ich würde die Verarbeitung in einen Thread auslagern und von diesem per PostMessage ab und zu eine Statusmeldung an den Hauptthread schicken.

hoika 6. Jun 2008 12:44

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Hall,

was ist denn an b) so verkehrt?
Ähnlich mache ich es auch.


Heiko

p80286 6. Jun 2008 13:20

Re: Update eines Labels aus einer Verarbeitungsschleife
 
@Sir Thornberry
Da schreckt mich etwas der Aufwand (naja ich bin ein Datenschafler und von Threads habe ich keine praktische Ahnung)

@hoika
zum einen schleppe ich mir über das uses vollkommen überflüssige units in die verarbeitung ein, zum anderen steuere ich innerhalb der Verarbeitung noch die Oberfläche. Das ist sicher besser als "Man sieht, das man nichts sieht, also arbeitet er" aber die reine Lehre ist das nicht. Was meinst Du was ich geflucht habe als ich TP-Programme nach Delphi portiert habe. Da ist die Methode a) schon etwas wartungsfreundlicher weil das meiste innerhalb der Unit abläuft. Nur Fragst Du dich manchmal "wofür brauch ich eigentlich 'Zähler'".

erst einmal vielen Dank für Eure Reaktion
K-H

mschaefer 6. Jun 2008 13:42

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Moin, moin,

Oft habe ich zur Datenausgabe eine Variable vom Typ TStringList definiert. Die wird im Programm zunächst der Lines Eigenschaft eines TMemos oder TRichEdits zugewiesen. In den Routinen schreibe ich dann Hinweise in meine LokalStringList die in meinen Routinen fest verankert ist. Dadurch brauche ich kein visuelles Objekt in den Rechenroutinen und habe zudem eine mehrzeiliga Ausgabe.

Grüße // Martin

uligerhardt 6. Jun 2008 14:02

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Zitat:

Zitat von p80286
b) Ich übergebe ein Label/Fortschrittbalken an die Verarbeitungsroutine. Ist der Wert des Labels <> nil dann wird der Zähler ausgegeben.

Nimm lieber einen Event a la OnStep. Der kann dann nil sein, Label1.Caption setzen, ein Writeln machen oder sonstwas tun - schön entkoppelt. :-)

HTH,
Uli.

Medium 6. Jun 2008 14:06

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Die Verarbeitung in einen Thread auslagern, der Threadklasse das GUI Fensterhandle überreichen und dann mit Messages arbeiten dürfte der generischste und entkoppelteste Weg sein, den du erreichen kannst. Dabei steht dir dann u.a. auch frei, ob und welche Messages du überhaupt nachher anzeigen lassen willst, und in welcher Form (Text, Gauge, Balken etc.).

Noch weiter gedacht, könnte man sich vorstellen, dass man mehrere Fenster(handles) in der Threadklasse hinterlegt, so dass evtl. sogar jeder Signaltyp (wenn man mal mehr als nur einen Counter hat) theoretisch an ein anderes Fenster gesendet werden kann. Damit könnte man dann sogar realisieren, dass eine von TEdit abgeleitete Klasse selbst auf eine Message aus dem Thread reagiert und die Anzeige übernimmt, ohne dass in einem zentralen Formular eine Verteilungslogik her müsste. Einfach direkt an diese Klasse senden lassen.

Ich denke schon, dass es sich langfristig sehr lohnen würde, sich mit Threads zu beschäftigen. Viele machen sich bei dem Thema auch oft zu viel in die Hose; es ist wirklich nicht kompliziert, wird aber wie so oft heuertage durch eine ganz tolle hochtrabende Begriffswelt verklausuliert, die erstmal nur erdrückend aussieht. Die Konzepte hinter Synchronizing, Locking, Priority, WaitForSingleObject und so weiter sind an sich recht trivial - zumindest wenn man nicht grad letzte Woche seinen ersten Compiler gekauft hat ;)

p80286 6. Jun 2008 14:16

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Hallo zusammen,

danke für Eure Tips, da ist das Wochenende ja gerettet.

Ich werde das alles mal ausprobieren, vielleicht sind Threads ja wirklich DIE Lösung!

viele Grüße und ein schönes Wochenende
K-H

Bernhard Geyer 6. Jun 2008 14:28

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Zitat:

Zitat von Medium
Die Verarbeitung in einen Thread auslagern, der Threadklasse das GUI Fensterhandle überreichen und dann mit Messages arbeiten dürfte

Ob das nicht auch kracht, da die problematische VCL und Threadproblematik an der Win32-GUI liegt da Fensterhandle eine Thread-Affinität besitzen: Sie dürfen nur im erzeugenden Thread angesprochen werden.

Luckie 6. Jun 2008 15:10

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Und wenn die den Overhead eines Thread vermeiden willst, ruf in der Schleife regelmäßig, aber nicht zu oft, Application.ProcessMessages auf. Dieser Aufruf veranlasst das Fenster seine Nachrichtenschleife abzuarbeiten. dies hat eben auch zur Folge, dass dein Label aktualisiert wird.

p80286 14. Aug 2008 09:47

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Hallo Zusammen,

auch wenn es etwas her ist, habe ich trotzdem vor mich hingebastelt.
Folgende Lösung scheint recht tauglich zu sein:
Delphi-Quellcode:

{-- Diese Procedure koppelt die Anzeige im Form und den Counter in der Daten-Unit }
procedure CNT_ANZEIGE(instr:string);
begin
  form1.Label1.Caption:=instr;    {ein String kann auch mehr sein als eine Zahl }
  application.ProcessMessages;    {sonst gibts keine Anzeige                    }     
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  starttime,
  endtime   : tdatetime;
begin
  starttime:=now;
  READ_DATA('c:\temp\paend.txt');
  endtime:=now;
  form1.Label2.Caption:='Laufzeit: '+timetostr(endtime-starttime)+' HH:MM:SS';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  SHOWCNT:=CNT_ANZEIGE;
end;
Delphi-Quellcode:
interface
var
  SHOWCNT: procedure (instr:string);

procedure READ_DATA(efile:string);

implementation
uses
  sysutils;

procedure READ_DATA(efile:string);
var
  tdat : textfile;
  cnt  : integer;
  dummy : string;
begin
  cnt:=0;
  assignfile(tdat,efile);
  reset(tdat);
  repeat
    readln(tdat,dummy);
    inc(cnt,1);
    if cnt and $F=0 then            { damit die Ausgabe nicht zu oft aufgerufen wird }
    if assigned(SHOWCNT) then       { läuft auch wenn in der Form-Unit keine Anzeige/Ausgabe erfolgt}
      SHOWCNT(inttostr(cnt));
  until eof(tdat);
  closefile(tdat);
end;

end.
Der besondere Charme liegt meiner Meinung darin, daß die Daten-Unit nicht weiß ob sie in einer Consolen oder Windowsanwendung läuft. Falls die Kopplungsprozedur zugewiesen wurde, wird nur ein String übergeben der von der Oberflächen Unit verarbeitet wird oder nicht.
Ist Sie nicht zugewiesen, stört das die Daten-Unit überhaupt nicht, sie ist also volkommen unabhängig von der Oberflächen-Unit.
Darum habe ich das TNotifyEvent auch nicht benutzt, da dann auf jeden Fall eine OO-Oberfläche vorhanden sein muß und ich wollte mir alle Optionen offen halten.
Die Einbindung in das Form ist nicht optimal, erfüllt aber seinen Zweck.

Den Lösungsansatz mit Threads werde ich mal aufgreifen wenn ich richtig fette Dateien zu lesen habe.

Vielen Dank nochmal für Eure Tips und Anregungen.

Grüße
K-H

uligerhardt 14. Aug 2008 10:13

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Zitat:

Zitat von p80286
Darum habe ich das TNotifyEvent auch nicht benutzt, da dann auf jeden Fall eine OO-Oberfläche vorhanden sein muß und ich wollte mir alle Optionen offen halten.

TNotifyEvent bedeutet ja nicht zwangsweise VCL-Oberfläche. Ich würde schon versuchen, entweder eine "procedure(...) of object" zu nehmen oder zumindest deinem SHOWCNT einen zusätzlichen Parameter a la "Data: Pointer" zu verpassen, damit du später auch einen Kontext in deinen Callback-Routinen hast.

p80286 15. Aug 2008 16:58

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Hallo Uli,

ich hab im Augenblick gut zu tun, darum reagiere ich etwas langsam.
Leider verstehe ich Deine Einlassungen nicht.

Wenn ich mich richtig erinnere beinhaltet TNotifyEvent zwei Adressen, die der Routine und die des besitzenden Objektes, da ich aber von OO unabhängig sein will ,was nicht deckungsgleich mit VCL ist, habe ich diese "Sparversion" gewählt.

Das Callback verstehe ich überhaupt nicht. Die Anzeige ist ja nur nettes Beiwerk für den Benutzer. Die eigentliche Verarbeitung soll ja davon vollkommen unberührt sein. Der ist es egal ob eine Anzeige erfolgt.

Gruß
K-H

uligerhardt 18. Aug 2008 08:20

Re: Update eines Labels aus einer Verarbeitungsschleife
 
Morgen, K-H!

Zitat:

Zitat von p80286
ich hab im Augenblick gut zu tun, darum reagiere ich etwas langsam.

Kein Problem. :-D

Zitat:

Zitat von p80286
Leider verstehe ich Deine Einlassungen nicht.

Kommt öfter vor. Irgendwie bin ich im Erklären nicht sooo gut. :wink:

Zitat:

Zitat von p80286
Wenn ich mich richtig erinnere beinhaltet TNotifyEvent zwei Adressen, die der Routine und die des besitzenden Objektes, da ich aber von OO unabhängig sein will ,was nicht deckungsgleich mit VCL ist, habe ich diese "Sparversion" gewählt.

Das Callback verstehe ich überhaupt nicht. Die Anzeige ist ja nur nettes Beiwerk für den Benutzer. Die eigentliche Verarbeitung soll ja davon vollkommen unberührt sein. Der ist es egal ob eine Anzeige erfolgt.

Mit Callback hab ich einfach dein CNT_ANZEIGE gemeint. Und in deinem Beispiel holst du dir das upzudatende Label ja über die globale Variable Form1. Das wäre halt IMHO etwas "sauberer", wenn du dir diese Information über die (impliziten) Self-Variablen eines TNotifyEvent oder einen expliziten Data-Pointer besorgst, etwa so:
Delphi-Quellcode:
procedure CNT_ANZEIGE(instr:string; Data: Pointer);
begin
  TForm1(Data).Label1.Caption:=instr;    {ein String kann auch mehr sein als eine Zahl }
  application.ProcessMessages;    {sonst gibts keine Anzeige                    }     
end;
Das ist aber alles Geschmackssache, also ignoriere meinen "Senf", wenn deine Lösung funktioniert. :mrgreen:

Uli.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:17 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz