Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht (https://www.delphipraxis.net/210669-wecker-elegante-loesung-mit-abbruch-via-button-gesucht.html)

NicoleWagner 24. Mai 2022 14:59

Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht
 
Hallo Leute,

mein Problem ist zweifellos schon zig-fach gelöst. Doch wo genau?
Ich brauche nichts als einen Wecker für 10 Minuten.

1) Es gibt einen "Startknopf", um den Countdown zu beginnen, dessen Methode hier drunter steht.
2) Und es gibt einen "Abbruch-Button", zu dem es noch gar keine Methode gibt.


Delphi-Quellcode:
// Ausführungsprogramm des Countdowns
procedure TForm_KalenderMain.Panel_CountdownClick(Sender: TObject);
Var Startzeit: TTime;
begin
  Startzeit:=DateTimePicker_Alarm;
.... * hier soll irgendwie abgefragt werden, ob seit der Startzeit bereits 10 Minuten vergangen sind. *
  Panel_Alarm.Color:=clGreen;
end;
Meine erste Frage ist die Funttion des Countdowns:
Wie löse ich den Countdown am Elegantesten?
Mit Sleep?
Oder indem ich jede Sekunde die Zeit neu abfrage?
Oder indem ich ....?

Das kann wohl jeder lösen. Irgendwie.
Der Profi hingegen weiß, wie es zu lösen geht, ohne sinnlos Ressourcen zu blockieren, indem ich ständig die Zeit prüfe.
Wofür ich hier danke.

Dann wird es trickreicher:
Es soll noch eine Button geben, der erlaubt, den Alarm abzubrechen.
Dieser Button wird in ein Click-Event führen.
Doch - was dann?
Ich könnte natürlich die Starzeit als globale Variable führen und sie einfach hochsetzen. Das sieht aber richtig hässlich aus vom Stil her.
Ich könnte eine globale Boolean Variable einführen, die den Alarm hält oder nicht. Allerdings müsste ich die neben der Zeit ständig abfrgen und das nur alle 1 Sekunden. Was eine hässliche Verzögerung darstellt.
Ich könnte ein Handle schreiben und gleich ins System greifen. Das sieht mir aber noch hässlicher aus.

Hat hier jemand 2 ELEGANTE Lösungen?
Mit bestem Dank im Voraus.

Nicole

Sherlock 24. Mai 2022 15:01

AW: Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht
 
Nimm einen TTimer, setze die Zeit wie Du sie möchtest, dann reagiere auf OnTimer. Ausserdem kannst Du TTimer auch aktivieren und Deaktivieren. Der Rest ist trivial.

NicoleWagner 24. Mai 2022 17:23

AW: Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht
 
Danke für den Tipp!
Der Timer ist jetzt Teil meines Projekts und startet jetzt.
mit
Timer1.Intervall:=...;
Timer1.Enabeled:=true;

So weit so fein.
Wie bringe ich ihn dazu, am Ende einen Sound abzuspielen (bzw. piep piep zu machen) und das Panel rot zu färben?

Mit anderen Worten:
Ich bräuchte ein OnEndTimer-Event.
Das dürfte es auch geben, doch eine Vorlage zu haben, wie ich es schreibe, wäre toll.
Die Schnipsel auf Stackoverflow usw. sind mir nicht so leicht verständlich bzw. recht unübersichtlich.

peterbelow 24. Mai 2022 17:54

AW: Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht
 
Zitat:

Zitat von NicoleWagner (Beitrag 1506340)
Danke für den Tipp!
Der Timer ist jetzt Teil meines Projekts und startet jetzt.
mit
Timer1.Intervall:=...;
Timer1.Enabeled:=true;

So weit so fein.
Wie bringe ich ihn dazu, am Ende einen Sound abzuspielen (bzw. piep piep zu machen) und das Panel rot zu färben?

Mit anderen Worten:
Ich bräuchte ein OnEndTimer-Event.

Den gibt's doch, wie Sherlock in seiner Antwort angab: OnTimer.

Delphi.Narium 24. Mai 2022 18:00

AW: Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht
 
Der Timer hat ein OnTimer-Event.

Dort schaltest Du als erstes den Timer aus:
Delphi-Quellcode:
Timer1.Enabled := false;
und dann machst Du in dem Ereignis, was immer Du willst.
Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  timer1.Enabled := false;
  Panel1.Color := clRed;
  // ... weiter, wie in jedem beliebigen andern OnClick- oder On...-Ereignis auch.
end;

venice2 24. Mai 2022 18:02

AW: Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht
 
Zitat:

Den gibt's doch, wie Sherlock in seiner Antwort angab: OnTimer.
Genau!
Example

Zitat:

Wie bringe ich ihn dazu, am Ende einen Sound abzuspielen.
Addiere eine Wave-Datei zur Ressource.
Addiere MMSystem zu den Uses..

Führe diese Funktion aus.
Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  timer1.Enabled := false;
  PlaySound('SOUND1', hInstance, SND_RESOURCE or SND_ASYNC);
  Panel1.Color := clRed;
end;

Davon ab würde ich gar keinen Timer nehmen sondern einen Thread dafür verwenden.
Delphi-Quellcode:
var
  EndAlarm : BOOL;
Delphi-Quellcode:
procedure Alarm(Delay: Integer); stdcall;
var
  //...
begin
  //...

  Repeat
    //... Was auch immer du für die Zeit Berechnung benötigst.
    // Wenn Bedingung erfüllt.
    if (bla = bla) then
    begin
      EndAlarm := True;
      PlaySound('SOUND1', hInstance, SND_RESOURCE or SND_ASYNC);
      Panel1.Color := clRed;
    end;
    Sleep(Delay);
  Until (EndAlarm = True); // globale variable EndAlarm Definieren und über Button auf True setzen. Oder darauf warten bis Bedingung erfüllt
end;
Delphi-Quellcode:
function StartAlarm(Delay: Integer): Integer;
var
  Return: Integer;
  hThread, dwThreadId: DWORD;
begin
  Return := LB_ERR;
  hThread := CreateThread(nil, 0, @Alarm, Pointer(Delay), 0, dwThreadId);

  if (hThread <> 0) then
  begin
    Return := LB_OKAY;
    Sleep(100);
  end;

  CloseHandle(hThread);
  Result := Return;
end;
Aufruf!

Delphi-Quellcode:
if (StartAlarm(60) = LB_OKAY) then
          // bla, bla

himitsu 24. Mai 2022 18:50

AW: Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht
 
Den Sound kann man Async abspielen, somit hat der Hauptthread garnichts zu tun und ein Thread ist garnicht nötig.

Fazit: Die eleganzeste Lösung ist ein Timer.

venice2 24. Mai 2022 18:56

AW: Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht
 
Zitat:

Zitat von himitsu (Beitrag 1506346)
Den Sound kann man Async abspielen, somit hat der Hauptthread garnichts zu tun und ein Thread ist garnicht nötig.

Fazit: Die eleganzeste Lösung ist ein Timer.

Du weist doch gar nicht was alles noch innerhalb des Threads behandelt werden soll.
Abfrage der Zeiten und..und..und
Fazit: Daher ist die eleganteste Lösung diese mit der Sie am besten zurecht kommt Code bedingt.

Ich Render zum Beispiel noch einige Bilder innerhalb des Thread deshalb habe ich ihn umgeschrieben und hier angeboten.
Glaube es oder nicht der hat genug zu tun. (In meiner Anwendung)
Delphi-Quellcode:
procedure Animate(Delay: Integer); stdcall;
var
  Brush: HBrush;
  StepX: Integer;
  DesktopDC: HDC;
  lpSize: TSize;
  graphics: LONG_PTR;
  rc: TRect;
  rw: TRect;
  bf: BLENDFUNCTION;
  lp, ptSrc: TPoint;
//  label DoLoop;
begin

  GetWindowRect(gP.Handle, rc);
  lpSize.cx := rc.right - rc.left;
  lpSize.cy := rc.bottom - rc.top;
  SetRect(rc, 0, 0, lpSize.cx, lpSize.cy);

  if (gP.img = 0) then
    exit;

  bf.BlendOp := AC_SRC_OVER;
  bf.BlendFlags := 0;
  bf.AlphaFormat := AC_SRC_ALPHA;
  bf.SourceConstantAlpha := 255;

//  DoLoop:
  Repeat
    if (gP.bitmap = 0) then
    begin
      DesktopDC := GetDC(0);
      gP.DC := CreateCompatibleDC(DesktopDC);
      gP.bitmap := CreateDIBSection32(gP.DC, lpSize.cx, lpSize.cy);
      SelectObject(gP.DC, gP.bitmap);
      ReleaseDC(0, DesktopDC);
    end;

    if (gP.bitmap <> 0) then
    begin
      GetWindowRect(gP.Handle, rw);

      StepX := 1;
      lp.y := rw.top;

      if (rw.right > GetSystemMetrics(0)) and (HideIt = 0) then
      begin
        lp.x := rw.left - StepX;
      end else
      if (Sound = 0) then
      begin
        Sound := -1;

        inc(PlayThis);
        if (PlayThis = 2) then
          PlaySound('SOUND2', gP.instance, SND_RESOURCE or SND_ASYNC)
        else if (PlayThis < 2) then
          PlaySound('SOUND1', gP.instance, SND_RESOURCE or SND_ASYNC);
      end;

      if (PlayThis > 2) then
        Playthis := 3;

      if (HideIt = 3) then
      begin
        if rw.left < GetSystemMetrics(0) - 25 then
          lp.x := rw.left + StepX
        else
        begin
          HideIt := 0;
          Sound := 0;
        end
      end;

      Brush := CreateSolidBrush(0);
      SelectObject(gP.DC, Brush);
      FillRect(gP.DC, rc, Brush);
      DeleteObject(Brush);

      if (GDIP_CreateFromHDC(gP.DC, graphics) = OK) then
      begin
        inc(gP.frametouse);
        if (gP.frametouse > gP.framecount) then
        begin
          gP.frametouse := 1;
          if rw.right < GetSystemMetrics(0) + 1 then
          inc(HideIt);
        end;

        if (gP.img <> 0) then
          GDIP_DrawImageRectRectI(graphics, gP.img, 0, 0, lpSize.cx, lpSize.cy,
            lpSize.cx * gP.frametouse - lpSize.cx, 0, lpSize.cx, lpSize.cy, 2, nil, nil, nil);

        GDIP_DeleteGraphics(graphics);
      end;

      UpdateLayeredWindow(gP.Handle, 0, @lp, @lpSize, gP.DC, @ptSrc, 0, @bf, ULW_ALPHA);
      Sleep(Delay);
    end;

  Until (EndAnimate = True);
//  Goto DoLOOP;

end;
Wie gesagt kann nicht riechen was ihr da so vorschwebt!
Aber eine allgemeine Aussage was richtig ist oder falsch muß sie selbst entscheiden.
So hat Sie auf jedenfalls einen anderen Ansatz.

Rollo62 24. Mai 2022 19:44

AW: Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht
 
Ich würde auf jeden Fall empfehlen das mit TDateTime zu machen, und zum Beispiel die Differenz (Now - StartDatum) als Trigger zu nehmen, oder auf eine Ablaufzeit FEndTime zu vergleichen.

Delphi-Quellcode:

type
    TMyForm = class
        FStartTime : TDateTime;
    end;

procedure TMyForm.Start;
begin
    FStartTime := Now;
end;

procedure TMyForm.OnTick;
begin
  if MilliSecondsBetween(Now, FStartTime) > 10000 then // if Now >= FEndTime then //<== Alternativ
  begin
     Alarm;
  end;
end;
Diese Abfrage dann regelmäßig mit DoTick triggern lassen, wie unten beschrieben, über Timer, Thread oder sonstwas.
Der Vorteil ist das der Wecker dann immer beliebig genau ist nach der Systemzeit, egal wie genau der Timer ist.
Dem Timer traue ich da über große Zeiträume eher weniger zu, der könnte auch mal irgendwo hängen bleiben, aber als zyklischer "Ticker" ist der super..

NicoleWagner 25. Mai 2022 09:31

AW: Wecker - ELEGANTE Lösung mit Abbruch via Button gesucht
 
Danke für die Antworten!
Ich werde sie alle durchforsten und wohl ganz viel davon einbauen.
Die vielen Codeschnipsel sind enorm nützlich.

Wer hier eines Tages nachliest, der soll auch noch dieses Link zum Thema finden:
https://docwiki.embarcadero.com/Code...ontrol_(Delphi)


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:45 Uhr.
Seite 1 von 2  1 2      

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