Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Hochzählende Variable während Laufzeit in Label anzeigen
Efrel - So 10.10.10 22:28
Titel: Hochzählende Variable während Laufzeit in Label anzeigen
Hi,
ich möchte gern eine Variable (die während eines Rechenprozesses nach oben zählt) "live" zur Laufzeit in einer Label.caption anzeigen lassen.
Habe jetzt schon ein bisschen was probiert, aber bekomme es nicht hin.
Am Code-Beispiel:
Es wird ein Zahlenbereich angegeben, von dem alle Primzahlen ermittelt und in einem Memofeld ausgegeben werden (soweit so gut).
Parallel dazu wird eine Variable (sinnigerweise "Laufvariable" benannt) mitzählen wie viele Primzahlen nacheinander entdeckt werden, also je neue Primzahl inc(Laufvariable).
Dieses Anwachsen soll "live" angezeigt werden.
Hier der Einfachheit halber der Gesamtcode (dort wo die Fragezeichen sind, hänge ich fest):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54:
| unit primzahlunit;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
type TForm1 = class(TForm) Edit1: TEdit; Memo1: TMemo; Panel1: TPanel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Button1: TButton; Edit2: TEdit; Label4: TLabel; procedure Button1Click(Sender: TObject); private public end;
var Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject); var pz:boolean;a,b,e1,e2,Laufvariable:integer; begin d:=0; e1:=strtoint(Edit1.Text); e2:=strtoint(Edit2.Text); if e2<=e1 then Application.MessageBox('Zweite Zahl ist zu klein','Fehler',MB_ICONERROR+MB_OK) else begin memo1.Lines.Clear; for a:=e1 to e2 do begin pz:=true; for b:=2to a div 2 do if a mod b=0 then pz:=false; if pz then begin inc(Laufvariable); memo1.lines.Add(inttostr(a)); end; end; end; end. |
Wäre super, wenn jemand einen Tipp hätte, wie man das Problem lösen kann.
Besten Dank im Voraus!
Efrel
PS: Kann man das Programm während des Rechenprozesses auch stoppen bzw. danach mit "Weiter" auch weiterrechnen lassen?
Tankard - So 10.10.10 22:31
quick and dirty.
application.processmessages;
in der schleife aufrufen.
ist aber unsauber. besser in einen eigenen thread auslagern.
Delete - So 10.10.10 22:33
Formatiere deinen Quelltext bitte mal richtig, damit man auch was erkenne kann.
Efrel - So 10.10.10 22:40
Luckie hat folgendes geschrieben : |
Formatiere deinen Quelltext bitte mal richtig, damit man auch was erkenne kann. |
Sorry, hier noch einmal etwas übersichtlicher:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55:
| unit primzahlunit;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
type TForm1 = class(TForm) Edit1: TEdit; Memo1: TMemo; Panel1: TPanel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Button1: TButton; Edit2: TEdit; Label4: TLabel; procedure Button1Click(Sender: TObject); private public end;
var Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject); var pz:boolean;a,b,e1,e2,Laufvariable:integer; begin d:=0; e1:=strtoint(Edit1.Text); e2:=strtoint(Edit2.Text); if e2<=e1 then Application.MessageBox('Zweite Zahl ist zu klein','Fehler',MB_ICONERROR+MB_OK) else begin memo1.Lines.Clear; for a:=e1 to e2 do begin pz:=true; for b:=2to a div 2 do if a mod b=0 then pz:=false; if pz then begin inc(Laufvariable); memo1.lines.Add(inttostr(a)); end; end; end;
end. |
Delete - So 10.10.10 22:57
Sorry, das sieht genauso grausam aus wie vorher. Zwei Dinge. Wenn es eine lokale Variable ist und die Routine immer wieder neu aufgerufen wird, behält sie ihren Wert nicht. Zweitens musst du der Oberfläche auch die Zeit und die Möglichkeit geben sich neu zu zeichen.
Efrel - So 10.10.10 23:05
Luckie hat folgendes geschrieben : |
Sorry, das sieht genauso grausam aus wie vorher. Zwei Dinge. Wenn es eine lokale Variable ist und die Routine immer wieder neu aufgerufen wird, behält sie ihren Wert nicht. |
Das leuchtet ein, denn der WErt ändert sich ja fortlaufend.
Luckie hat folgendes geschrieben : |
Zweitens musst du der Oberfläche auch die Zeit und die Möglichkeit geben sich neu zu zeichen. |
Hmm, hier hänge ich scheinbar. Klar, das Aufzählen erfolgt richtig schnell (halt PC-Geschwindigkeit).
Willst Du damit sagen, dass eine Anzeige über Label gar nicht sinnvoll ist, weil es das von der Leistungsfähigkeit der Anzeige nicht schaffen kann?
Welches Element könnte man alternativ verwenden? (Edit-Feld fiele mir auf Anhieb ein...)
Man findet im Net auch leider kein Programmbeispiel für solch eine ähnliche Funktion, wo man sich ein wenig Inspiration holen kann... :(
delphi10 - So 10.10.10 23:07
Tankard hat folgendes geschrieben : |
quick and dirty.
application.processmessages;
in der schleife aufrufen.
ist aber unsauber. besser in einen eigenen thread auslagern. |
Es ist auf jeden Fall pragmatisch. ABER es ist ein bösartiger Performance-killer wenn man es in einer Schleife verwendet. Edit: Natürlich kann die Anzeige das schaffen, es wird halt langsamer.
Efrel - Mo 11.10.10 17:57
Moderiert von
Narses: Komplett-Zitat des letzten Beitrags entfernt.
Kann man das anhand irgendeiner Größe quantifizieren, um wieviel % die Leistung dadurch geschälert wird?
Ich weiß, das ist querfeldein geschätzt und hängt wahrscheinlich auch mit der zu errechnenden Routine + PC-Leistung + aktuelles Wetter usw. zusammen, aber vielleicht gibts ja ein Bauchgefühl aus Euren Erfahrungswerten. Ist ja ein Unterschied, ob es ca. 10-20% oder sogar 50%+ sind.
Danke für die Hilfe an alle. Mit application.processmessages; habe ich es auch hinbekommen.
Ich würde jedoch gern noch einmal meine im Eingangspost gestellte Frage in den Raum bringen:
Kann man alle Rechenprozesse (egal ob application.processmessages zur Anzeuge verwendet werden oder nicht) einer Routine auch stoppen (z. B. mittels Button) und dann an der gleichen Stelle die Berechnung fortsetzen (wieder mit Button). Alle Daten der Routine, die möglicherweise im RAM abgelegt wurden, sollen natürlich erhalten bleiben während des Stopps.
platzwart - Mo 11.10.10 18:02
Wenn du das ganze in einen Thread auslagerst, dann ja. Denn kannst du starten (execute), anhalten (suspend), weiterlaufen lassen und killen...
Efrel - Mo 11.10.10 18:04
platzwart hat folgendes geschrieben : |
Wenn du das ganze in einen Thread auslagerst, dann ja. Denn kannst du starten (execute), anhalten (suspend), weiterlaufen lassen und killen... |
Puhhh... Noch nie was davon gehört.
Kannst Du mir aus dem Stehgreif einen Hinweis geben wie sowas geht oder wo man sowas gut nachschlagen kann.
Edit: OK - grad was dazu gefunden:
http://www.delphi-treff.de/tutorials/objectpascal/threads/einleitung/
Sieht nicht ganz einfach aus... :?
bummi - Mo 11.10.10 18:34
Ein kleines (sinnloses) Demo
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TForm1 = class(TForm) Button1: TButton; Label1: TLabel; Button2: TButton; Button3: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject);
private public end;
var Form1: TForm1;
implementation uses Threadtest; {$R *.dfm}
var L_Mythread:TMythread;
Procedure CallBack(i:Integer); begin Form1.Label1.Caption := IntToStr(i); end;
procedure TForm1.Button1Click(Sender: TObject); begin L_Mythread:=TMythread.create(@CallBack); end;
procedure TForm1.Button2Click(Sender: TObject); begin L_Mythread.Suspend; end;
procedure TForm1.Button3Click(Sender: TObject); begin L_Mythread.Resume; end;
end. |
und der Thread dazu
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48:
| unit Threadtest;
interface uses windows,classes; type TCallBackProc=Procedure(Zahl:Integer);
TMythread=Class(TThread)
Procedure Execute;override; Constructor Create(CallBack: TCallBackProc); overload; Private FDummy : Integer; FCallBackProc:TCallBackProc; procedure DoCallBack;
End; implementation
Constructor TMythread.Create(CallBack: TCallBackProc); begin inherited Create(false); FDummy := 0; FCallBackProc := CallBack; FreeOnTerminate := true; end;
procedure TMythread.DoCallBack; begin FCallBackProc(FDummy); end;
procedure TMythread.Execute; begin while not Terminated do begin sleep(100); inc(FDummy); if Assigned(FCallBackProc) then Synchronize(DoCallBack);
end; end;
end. |
platzwart - Mo 11.10.10 18:38
Ja, ist in der Tat nicht ganz trivial. Aber wenn man es einmal verstanden hat, kann man damit wunderbare Dinge programmieren...
Efrel - Mo 11.10.10 18:39
Vielen Dank, Bummi (wie die alte Kinderzeitschrift :?: )
Werde ich ausführlich anschauen. Das benötigt eine kleine Einarbeitung.
Herzlichen Dank nochmal an alle Helfer!
Efrel
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!