Autor Beitrag
mick
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 159



BeitragVerfasst: Sa 28.03.09 00:08 
hallo zusammen.

ich programmiere ein primitives zufallszahlenspiel. nach einem klick auf den start/stop-button soll in einem panel eine zufallszahl "rotieren", d.h. im paar millisekundentakt wird darin eine neu generierte zufallszahl zw. 1 und 6 angezeigt (auf der gleichen stelle wie die vorige, man sieht also immer nur eine ziffer). dies soll prinzipiell unendlich lange laufen, zumindest so lange, bis der user wieder auf den SELBEN start/stop-button klickt (im spielerischen sinne des programms in dem moment, wenn die hoechste zufallszahl im panel angezeigt wurde, aber soviel nur zur prog-logik nebenbei). mein problem: wie formuliere ich das? wenn man naemlich auf den start/stop-button zum ersten mal drueckt, das onclick-ereignis ausgeloest wird und die schleife zur zufallszahlenerzeugung und -ausgabe durchlaeuft, soll abgebrochen werden durch erneuten klick auf den selben button. doch dessen onclick-ereignis wird als prozedur doch grade ausgefuehrt. wie kann das klappen? eine spezielle bedingung in der repeat-schleife? fuer profis sicherlich ein leichtes, dies zu loesen, ich danke im voraus.

sofern nicht zu verwirrend, hier ein quellcode-auszug:

ausblenden volle Höhe 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:
procedure TForm1.BitBtnStartStopClick(Sender: TObject);

  procedure Verzoegerung;
  const
    Dauer = 70;  { Verzoegerung in Millisekunden }
  var
    ZeitAnfang,ZeitEnde: Longint;
  begin
    ZeitAnfang := GetTickCount;
    repeat
      Application.ProcessMessages;  { Sichert, dass andere Programme weiterlaufen }
      ZeitEnde := GetTickCount;
    until (ZeitEnde-ZeitAnfang > Dauer);
  end;

  procedure Auswertung;
  begin
    {  Auswertung }
    if User > Computer then  { Sieg User }
      MessageDlg('Herzlichen Glückwunsch!' + #13 + 'Sie haben eine ' + IntToStr(User) +
      ' gewürfelt, der Computer nur eine ' + IntToStr(Computer) + '.' + #13 + #13 +
      'Sie haben gewonnen!',mtInformation,[mbOK],0)
    else if User < Computer then  { Sieg Computer }
      MessageDlg('Schade!' + #13 + 'Sie haben eine ' + IntToStr(User) +
      ' gewürfelt, der Computer hingegen eine ' + IntToStr(Computer) + '.' + #13 + #13 +
      'Sie haben leider verloren.',mtInformation,[mbOK],0)
    else  { Unentschieden }
      MessageDlg('Unentschieden!' + #13 + 'Der Computer hat ebenso wie Sie eine ' + IntToStr(User) +
      ' gewürfelt.' + #13 + #13 +
      'Entscheiden Sie das Duell in einer erneuten Runde!',mtInformation,[mbOK],0);
  end;
  
var
  i: Integer;  
begin
  if BitBtnStartStop.Caption = '&Start' then begin  { Starten des User-Wuerfelwurfs }
    { BitButton }
    BitBtnStartStop.Kind := bkCancel;
    BitBtnStartStop.Caption := '&Stop';

    { Wuerfeln }
    User := Random(6) + 1(* BAUSTELLE!!! HIER "ROTIERT" Z.Z. NOCH NICHTS, NUR SIMPLE ERZEUGUNG EINER Z-ZAHL *)
    PnlUser.Caption := IntToStr(User);
  end
  else begin  { Starten des Computer-Wuerfelwurfs }
    { BitButton }
    BitBtnStartStop.Enabled := False;

    { Wuerfeln }
    for i := 1 to 50 do begin  { 50 Zufallszahlen erzeugen }
      Computer := Random(6) + 1;
      PnlComputer.Caption := IntToStr(Computer);
      Verzoegerung;
    end;

    Auswertung;
  end;
end;


screenshot:

Moderiert von user profile iconNarses: Bild als Anhang hochgeladen

ciao,
ltmick.
Einloggen, um Attachments anzusehen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 28.03.09 00:23 
Zur "Verzögerung" nimm am besten dieses Delay:
www.delphipraxis.net/topic7355.html

Was du machen müsstest ist eine Schleife, die bis zum Abbruch läuft. Das geht z.B. mit Tag. Beispiel, hier zähle ich einfach eine Zahl hoch:
ausblenden volle Höhe 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:
procedure TForm1.Button1Click(Sender: TObject);

  procedure Delay(Milliseconds: Integer);
  var
    Tick: DWord;
    Event: THandle;
  begin
    Event := CreateEvent(nil, False, False, nil);
    try
      Tick := GetTickCount + DWord(Milliseconds);
      while (Milliseconds > 0and
            (MsgWaitForMultipleObjects(1, Event, False, Milliseconds, QS_ALLINPUT) <> WAIT_TIMEOUT) do
      begin
        Application.ProcessMessages;
        if Application.Terminated then Exit;
        Milliseconds := Tick - GetTickcount;
      end;
    finally
      CloseHandle(Event);
    end;
  end;

var
  Value: Integer;
begin
  if not (Sender is TButton) then
    Exit;
  if TButton(Sender).Tag = 1 then
  begin
    TButton(Sender).Tag := 0;
    TButton(Sender).Caption := 'Start';
  end
  else
  begin
    Value := 0;
    TButton(Sender).Tag := 1;
    TButton(Sender).Caption := 'Abbrechen';
    while TButton(Sender).Tag <> 0 do
    begin
      Inc(Value);
      Caption := IntToStr(Value);
      Delay(100);
    end;
  end;
end;
GTA-Place
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
EE-Regisseur
Beiträge: 5248
Erhaltene Danke: 2

WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
BeitragVerfasst: Sa 28.03.09 11:14 
Ein wenig OT: Ein großes Lob für die Formulierung der Frage und für den bisherigen Quelltext. So gut formatiert sieht man das selten!

Und die Lösung hat ja jaenicke nun auch schon formuliert :)

_________________
"Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
mick Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 159



BeitragVerfasst: Sa 28.03.09 18:31 
vielen dank fuer die antwort. habe es jetzt folgendermassen umgesetzt:

ausblenden volle Höhe 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:
59:
60:
61:
62:
63:
64:
65:
66:
procedure TForm1.BitBtnStartStopClick(Sender: TObject);

  procedure Verzoegerung;
  const
    Dauer = 100;  { Verzoegerung in Millisekunden }
  var
    ZeitAnfang,ZeitEnde: Longint;
  begin
    ZeitAnfang := GetTickCount;
    repeat
      Application.ProcessMessages;  { Sichert, dass andere Programme weiterlaufen }
      ZeitEnde := GetTickCount;
    until (ZeitEnde-ZeitAnfang > Dauer);
  end;

  procedure Auswertung;
  begin
    {  Auswertung }
    if User > Computer then  { Sieg User }
      MessageDlg('Herzlichen Glückwunsch!' + #13 + 'Sie haben eine ' + IntToStr(User) +
        ' gewürfelt, der Computer nur eine ' + IntToStr(Computer) + '.' + #13 + #13 +
        'Sie haben gewonnen!',mtInformation,[mbOK],0)
    else if User < Computer then  { Sieg Computer }
      MessageDlg('Schade!' + #13 + 'Sie haben eine ' + IntToStr(User) +
        ' gewürfelt, der Computer hingegen eine ' + IntToStr(Computer) + '.' + #13 + #13 +
        'Sie haben leider verloren.',mtInformation,[mbOK],0)
    else  { Unentschieden }
      MessageDlg('Unentschieden!' + #13 + 'Der Computer hat ebenso wie Sie eine ' + IntToStr(User) +
        ' gewürfelt.' + #13 + #13 +
        'Entscheiden Sie das Duell in einer erneuten Runde!',mtInformation,[mbOK],0);
  end;

var
  i: Integer;
begin
  (* if not (Sender is TBitBtn) then Exit; *)

  { Anm.: Nummer des BitBtn-Prozeduraufrufs zaehlen bzw. erkennen mittels einer Flag (Wert) in der Eigenschaft "Tag". }
  if BitBtnStartStop.Tag = 0 then begin  { Starten des User-Wuerfelwurfs }
    { BitButton }
    BitBtnStartStop.Tag := 1;
    BitBtnStartStop.Kind := bkCancel;
    BitBtnStartStop.Caption := '&Stop';

    { Wuerfeln }
    while BitBtnStartStop.Tag <> 0 do begin
      User := Random(6) + 1;
      PnlUser.Caption := IntToStr(User);
      Verzoegerung;
    end;
  end
  else begin  { Starten des Computer-Wuerfelwurfs }
    { BitButton }
    BitBtnStartStop.Tag := 0;
    BitBtnStartStop.Enabled := False;

    { Wuerfeln }
    for i := 1 to 50 do begin  { 50 Zufallszahlen erzeugen }
      Computer := Random(6) + 1;
      PnlComputer.Caption := IntToStr(Computer);
      Verzoegerung;
    end;

    Auswertung;
  end;
end;


werde trotzdem meine art der verzoegerung nutzen - dies ist vllt. nicht so effizient, aber leichter verstaenidlich und ich denke fuer diesen zweck zielfuehrend, oder?

darueber hinaus: wie zu sehen, habe ich

ausblenden Delphi-Quelltext
1:
if not (Sender is TBitBtn) then Exit;					


einkommentiert. es klappt naemlich auch so. oder brauche ich das wirklich? habe naemlich noch nicht ganz verstanden, warum das ganze funktioniert. die eigenschaft "tag" ist mir klar - hier als eine art flag genutzt. aber wie funktioniert das mit den onclick-ereignissen? ueberlagert der zweite klick den ersten? und wird der erste nach beendigung des zweiten an der stelle fortgesetzt, wo er durch den zweiten klick unterbrochen wurde, oder wie?

danke fuer die nachhilfe,

ciao,
mick.
JayEff
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: Sa 28.03.09 18:33 
user profile iconmick hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
Application.ProcessMessages;  { Sichert, dass andere Programme weiterlaufen }					

Genau genommen sorgt diese Zeile dafür, dass dein Programm (nicht andere ;) ) die Nachrichten, die es bekommt (wie zum Beispiel auch Maus-Ereignisse!) weiterhin verarbeitet, also es sorgt dafür, dass dein Programm nicht komplett einfriert, während die Schleife läuft.

_________________
>+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 28.03.09 18:36 
user profile iconmick hat folgendes geschrieben Zum zitierten Posting springen:
werde trotzdem meine art der verzoegerung nutzen - dies ist vllt. nicht so effizient, aber leichter verstaenidlich und ich denke fuer diesen zweck zielfuehrend, oder?
Das funktioniert auch, lastet aber den Rechner mehr aus.

user profile iconmick hat folgendes geschrieben Zum zitierten Posting springen:
darueber hinaus: wie zu sehen, habe ich

ausblenden Delphi-Quelltext
1:
if not (Sender is TBitBtn) then Exit;					


einkommentiert. es klappt naemlich auch so. oder brauche ich das wirklich?
Dann bekommst du Probleme, wenn da aus Versehen mal ein falschs Objekt drin steckt. Wenn du die Methode z.B. auch einem Click-Ereignis einer anderen Komponente zuweist.
Als Sender wird nämlich die auslösende Komponente übergeben (es sei denn du rufst die Methode mit einem anderen Parameter manuell auf).

user profile iconmick hat folgendes geschrieben Zum zitierten Posting springen:
ueberlagert der zweite klick den ersten?
Ja. Wie JayEff schon sagte werden die Botschaften bei dem ProcessMessages verarbeitet und dabei eben auch der neue Klick registriert und verarbeitet.
mick Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 159



BeitragVerfasst: Sa 28.03.09 18:59 
danke fuer den hinweis mit

ausblenden Delphi-Quelltext
1:
Application.ProcessMessages;					


habe es in meinen unterlagen geaendert.

dann aber nochmals zu den ereignissen: der zweite klick ueberlagert also den ersten. die prozedur des ersten klicks wird nach beendigung der prozedur des zweiten klick dort weiter ausgefuehrt, wo sie unterbrochen wurde. ok. wenn dem so ist, koennte dann nicht folgender unerwuenschter effekt auftreten? sagen wir, in

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
while BitBtnStartStop.Tag <> 0 do begin
  User := Random(6) + 1;
  PnlUser.Caption := IntToStr(User);
  Verzoegerung;
end;


wird die while-schleife dann unterbrochen, wenn grade der befehl

ausblenden Delphi-Quelltext
1:
User := Random(6) + 1;					


ausgefuehrt wird. dann kommt der durchlauf fuer den zweiten klick, und wenn danach an der zuvor unterbrochenen stelle in obiger while-schleife weitergemacht wird, muesste doch noch

ausblenden Delphi-Quelltext
1:
2:
PnlUser.Caption := IntToStr(User);
Verzoegerung;


ausgefuehrt werden. das wiederum haette zur folge, dass ganz am ende nochmals eine unerwuenschte ausgabe im PnlUser getaetigt wuerde, oder?

ciao,
mick.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 28.03.09 19:06 
Die "Unterbrechung" passiert genau da, wo du die Abarbeitung der angekommenen Mausbotschaften erlaubst. Nämlich mit Application.ProcessMessages in Verzoegerung.
mick Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 159



BeitragVerfasst: Sa 28.03.09 19:40 
ah, dann ist eine "unterbrechung" also nur bei

ausblenden Delphi-Quelltext
1:
Application.ProcessMessages;					


moeglich - mein oben geschilderter fall kann also nicht eintreten. das bedeutet auch, dass wenn ich die zeile oben aus dem code loesche, mein programm zwar noch compiliert wird, aber beim button-klick abstuerzen wird.

danke,

ciao,
mick.
JayEff
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: Sa 28.03.09 19:44 
user profile iconmick hat folgendes geschrieben Zum zitierten Posting springen:
aber beim button-klick abstuerzen wird.
Nein, nur einfrieren, bis die Schleife abgearbeitet ist - was sie nie sein wird, da der User nicht auf den Button klicken kann ;) Also, ja, Windows wird "Reagiert nicht mehr" melden. Aber abstürzen ist so ein böses Wort, lass uns lieber sagen, es hängt in einer Endlosschleife fest :zustimm:

_________________
>+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 28.03.09 19:44 
Abstürzen ist das falsche Wort, nicht mehr reagieren wird das Programm dann.
mick Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 159



BeitragVerfasst: Sa 28.03.09 19:52 
super, leute, jetzt hab ich's. danke fuer eure hilfe,

ciao,
mick.