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
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  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));
  // label4.caption.add(inttostr(d));  // wie kann man im Label die Laufvariable "live" mit hochzählen lassen ????
   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

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
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
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  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));
          // label4.caption.add(inttostr(d));  // wie kann man im Label die Laufvariable "live" mit hochzählen lassen
        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

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
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.

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:

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

user profile iconTankard hat folgendes geschrieben Zum zitierten Posting springen:
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 user profile iconNarses: 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

user profile iconplatzwart hat folgendes geschrieben Zum zitierten Posting springen:
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
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  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

{ Mythread }

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