Program do trenigu na bazie Timera

0

Dzień dobry.
Kochani potrzebuje pomoc z poukładaniem timera.
Prosty programik do treningu. Chodzi mi o budowę czegoś takiego:

1 minuta treningu, 40 sekund przerwy i odnowa
na 10 sekund przed końcem treningu czy przerwy odtwarzamy dźwięk mp3
Wszystkie czasy dodajemy w SpinEdittach w tym ilość powtórzeń. Ilość powtórzeń do końca oraz czas pokazujemy w TLabelach

Domyślam się że będą potrzebne dwa zegary a powtórzenia będą Timer.Tag
Na razie mam coś takiego jeden zegar odliczający czas w dół

  private
   intTimerCounter : integer;
  public
  end;
var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
 var
  LHours, LMinutes, LSeconds: Integer;
 begin
  LHours   := HoursSpin.Value   * 3600;
  LMinutes := MinutesSpin.Value * 60;
  LSeconds := SecondsSpin.Value;
  lblTime.Caption := '00:00:00';
  intTimerCounter := LHours + LMinutes + LSeconds;
  timer1.Enabled := True;
 end;


procedure TForm1.Timer1Timer(Sender: TObject);
 Begin
  self.lblTime.Caption := timetostr(self.intTimerCounter/24/3600);
  dec(self.intTimerCounter);
  if self.intTimerCounter > 0 then
    exit;
   self.Timer1.Enabled:=false;
end;

Nie wiem jak w to wrzucić Tag i drugi timer. Jak to złożyć? Pomożecie ?

0

Po pierwsze, mój kod z którego korzystasz, umożliwiał obliczanie ilości milisekund na podstawie wartości z komponentów, a nie sekund. Poza tym, jedna seria ćwiczeń nie będzie trwała dłużej niż godzinę, więc w zupełności wystarczą Ci dwa komponenty - do podania ilości minut i sekund - nic więcej.

Domyślam się że będą potrzebne dwa zegary a powtórzenia będą Timer.Tag

Nie, w zupełności wystarczy jeden timer. Dwa były by potrzebne w sytuacji, gdy w jednym czasie miały by być wykonywane dwa odliczania. Twój program ma na przemian odliczać czas ćwiczeń i czas odpoczynku, więc wykonuje tylko jedno odliczanie w danym momencie (albo ćwiczenia, albo przerwa). Jak bardzo chcesz to możesz sobie użyć dwóch timerów - nic nie stoi na przeszkodzie.

Poza tym, właściwość Tag można wykorzystać do przechowania jednej liczby, a jak jest ich więcej to trzeba je przechowywać gdzieś indziej, np. w kilku polach klasy okna.

na 10 sekund przed końcem treningu czy przerwy odtwarzamy dźwięk mp3

W takim razie potrzebujesz zapisać kod w taki sposób, aby timer wykonywał zdarzenie OnTimer dokładnie co sekundę. Czyli należy wpisać wartość 1000 (bo w milisekundach) do właściwości Interval. Dzięki temu będziesz mogła co sekundę wykonywać jakąś akcję, czyli np.:

  • aktualizować na ekranie etykietę z pozostałym czasem,
  • wykryć moment, w którym pozostało 10 sekund do końca odliczania i odegrać dany dźwięk.

Reszta to obsługa bieżącego całego mechanizmu odliczania w zdarzeniu OnTimer, bez modyfikacji jego właściwości Interval. Tak więc timer zawsze ma wykonywać zdarzenie OnTimer co sekundę, a czas pozostały do końca odliczania ma się znajdować w dodatkowych zmiennych.

0

Tak tutaj timera znalazłam, zrobiłam drugi identyczny ale skoro mówisz ze można to zrobić w jednym i tak to powinno być będę kombinować. Chociaż kompletnie nie mam pomysłu jak w jednym zakończyć jedno odliczanie i rozpocząć drugie a do tego dodać ilość powtórzeń :) No ale nic dziękuje bardzo za rady

0
  1. W zdarzeniu OnTimer możesz nie tylko wyłączyć (Enabled) zegar po wykonaniu pracy ale także zmieniać mu Interval. Z 50 sekund na 10. A potem na 30. A potem na 10, a ponem znowu na 50, żeby zacząć kolejny cykl ćwiczeń. Tylko musisz wiedzieć, na którym etapie cyklu jesteś.
  2. Możesz zadeklarować sobie więcej zmiennych oprócz intTimerCounter. Pewnie się przydadzą.
0

Jeśli to ma być program do ćwiczeń to wręcz obowiązkowym jest wyświetlenie odliczania czasu na ekranie. Gdybym sam miał z czegoś takiego korzystać to chciałbym w każdej chwili wiedzieć ile sekund pozostało.

Dlatego też sugeruję ustawienie timera na jedną sekundę (wartość 1000) i aktualizowanie etykiety w każdym wywołaniu zdarzenia OnTimer. Tylko w ten sposób możliwe będzie wykonywanie kodu (czyli m.in. aktualizacja etykiety) co sekundę. A to w jaki sposób odliczać czas nie jest niczym skomplikowanym - po kliknięciu w przycisk ustawiasz licznik sekund na jakąś wartość, a w zdarzeniu OnTimer dekrementujesz ją o 1. Jak licznik dojdzie do 0 to czas na ćwiczenia lub przerwy skończył się i należy uruchomić kolejne odliczanie. Wszystko w tym zdarzeniu, dosłownie dziesięć linijek kodu.

0

Dziękuję za rady na dwa timery wydziobałam :) na jeden znacznie mi to idzie oporniej. Nie wiem jak po zakończeniu jednego odliczania rozpoczać drugie Ale powolutku damy rade :)

Da rady w ten kod wrzucić plik .wav lub .mp3 z zasobów odtwarzany co sekundę?
chodzi o coś na zasadzie "cykania". jeśli tak to jak to powinno wyglądać?

 procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if TimeStart = 0 then begin
    dec(TimePause);
     self.label1.Caption := timetostr(TimePause/24/3600);
     if TimePause = 0 then begin
      Timer1.Enabled := false;
     end;
    end
  else begin
    dec(TimeStart);
    self.label1.Caption := timetostr(TimeStart/24/3600);
  end;
end;

0

"Da rady w ten kod wrzucić plik .wav lub .mp3 z zasobów odtwarzany co sekundę?"
co znaczy "wrzucić" ?
Timer robi tylko jedno, w odpowiednim momencie odpala procedurę podpiętą pod obsługę zdarzenia "ontimer"
"wrzucenie" takiego czy innego pliku musisz oprogramować w tej proceudrze

0

Przepraszam terminologie.
To jak to fachowo oprogramować?

0

pod zdarzenie 'ontimer' obiektu klasy TTimer podpinasz swoją procedurę obsługi zdarzenia np. ..

procedure MyForm.TimerTimer(Sender: TObject);
begin
   // tutaj obsługa zdarzenia , np wyświetlenie obrazka 
end;
0

Najprościej będzie skorzystać z dźwięku .wav, dlatego że zsynchronizowane odegranie dźwięku (nie zamrażające aplikacji) będzie możliwe do wykonania na podstawie funkcji PlaySound z flagą SND_ASYNC. Funkcja ta umożliwia odgrywanie dźwięku z zasobów, więc nadaje się idealnie.

0

Zdarzenie OnTimer już mam z odliczaniem czasu, tylko nie wiem jak do niego oprogramować i wywołać odtwarzanie dźwięku w nim co sekundę najlepiej z zasobów tupu mp3 lub wav .

0

Już Ci to tłumaczyłem w poprzednich swoich postach. Tak więc wróć na pierwszą stronę wątku i jeszcze raz przeczytaj uważnie wszystkie posty.

0

Zdarzenie OnTimer już mam z odliczaniem czasu, tylko nie wiem jak do niego oprogramować i wywołać odtwarzanie dźwięku w nim co sekundę najlepiej z zasobów tupu mp3 lub wav .>

obsługa zdarzenia OnTimer niczym się nie różni od np. obsługi zdarzenia onClick buttona. Jedyna różnica (oprócz Sendera) to taka że że onClick buttona jest wyzwalany kliknięciem myszką w button a onTimer jest wyzwalany cyklicznie przez systemowy zegar

0

Z dźwiękiem przepraszam z panikowałam masz racje zrobiłam to bez głowy nie dokładnie czytając, z tym sobie poradzę tak wave to najlepsze wyjście możecie pomóc jak tu zrobić pętle albo inaczej jak by dodać tu ilość powtórzeń nie wiem próbuję z
while i repeat zamiennie ale coś zawsze nie wychodzi
Nie jestem programistką nie mam szkoły w tym kierunku trochę próbuje sama coś wystukać. Po prostu nie wiem jak poprawnie wrócić po wykonaniu drugiego obliczenia do pierwszego i czy dobrze kombinuje robiąc to z ```Timer.Tag`` Pomożecie jak poprawnie ułożyć kod nawet puste instrukcje warunkowe bez kodu ale poukładane porządnie będą drogowskazem. Ja zatrzymałam się tutaj i za nic nie potrafię z tond wybrnąć i dołożyć poprawnie x powtórzeń, chociaż wiem że to proste ale nie mam mózgu operacyjnego. staram się na ile potrafię

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if TimeStart = 0 then begin
    dec(TimePause);
     self.label1.Caption := timetostr(TimePause/24/3600);
     if TimePause = 0 then begin
      Timer1.Enabled := false; 
     end;
    end
  else begin
    dec(TimeStart);
    self.label1.Caption := timetostr(TimeStart/24/3600);
  end;
end;
0

Najprościej będzie, jak zadeklarujesz sobie kilka zmiennych do przechowywania danych początkowych. Czyli przyda się kilka zmiennych (lub pól klasy) dla:

  • liczby sekund trwania treningu,
  • liczby sekund trwania przerwy,
  • liczby sekund, dla której ma być odegrany dźwięk.

Wartości tych trzech zmiennych powinny być inicjowane po kliknięciu w przycisk rozpoczynający odliczanie. Dla liczby sekund dla odegrania dźwięku wystarczy jeden komponent, np. klasy TSpinEdit. Natomiast dla czasu trwania treningu i dla czasu trwania przerwy przydadzą się po dwa komponenty (też mogą być TSpinEdit) - jeden dla sekund, drugi dla minut. Czas trwania treningu nie trudno policzyć - liczbę minut pomnożyć razy 60 i dodać liczbę sekund. To samo wykonać dla czasu trwania przerwy.

Zmienne wylistowane wyżej posłużą jedynie do przechowywania danych. Teraz przyda się jeszcze kilka zmiennych, ale takich, których wartości będą modyfikowane. Dlatego też przydadzą się zmienne dla:

  • pozostałej liczby powtórzeń treningu,
  • pozostałej liczby sekund trwania akcji (treningu albo przerwy),
  • wartości wyliczeniowej (enum), określającej czy w danej chwili trwa trening czy przerwa.

Wartości tych zmiennych też należy zainicjować po kliknięciu w przycisk, przy czym czas trwania treningu można przepisać ze zmiennej służącej tylko do odczytu (coby drugi raz nie liczyć tego samego). Po ustawieniu wszystkich wartości należy odpalić timer, aby rozpocząć odliczanie.

Hipotetyczna inicjalizacja wartości zmiennych (bo nie mam czasu odpalać IDE i bawić się z kontrolkami):

type
  TActionKind = (akTraining, akBreak);

type
  TMainForm = class(TForm)
  {..}
  private
    { read only }
    FTrainingTime: Integer;
    FBreakTime: Integer;
    FTimeToSound: Integer;
  private
    { read and write }
    FAction: TActionKind;
    FActionTime: Integer;
    FRepetitions: Integer;
  end;

procedure TMainForm.StartButtonClick(Sender: TObject);
begin
  { read only }
  FTrainingTime := TrainingMinutesSpin.Value * 60 + TrainingSecondsSpin.Value;
  FBreakTime    := BreakMinutesSpin.Value * 60 + BreakSecondsSpin.Value;
  FTimeToSound := TimeToSoundSpin.Value;

  { read and write }
  FAction := akTraining;
  FActionTime := FTrainingTime;
  FRepetitions := RepetitionsSpin.Value;

  { timer }
  FActionTimer.Enabled := True;
end;

Tak mniej więcej powinna wyglądać inicjalizacja danych i odpalenie timera. Timer powinien wywoływać handler OnTimer co sekundę, więc jego właściwość Interval należy ustawić na 1000. Dzięki temu będzie możliwe wykonanie jakiejś akcji w każdym ticku zegara (czyli np. raz na sekundę zaktualizować etykietę służącą do wyświetlania pozostałego czasu).

Teraz czas na zdarzenie OnTimer zegara:

procedure TMainForm.ActionTimerTimer(Sender: TObject);
begin
  FActionTime -= 1;

  if FActionTime = FTimeToSound then
    PlaySound({..})
  else
    if FActionTime = 0 then
    case FAction of
      akTraining:
      begin
        FRepetitions -= 1;

        if FRepetitions = 0 then
          ActionTimer.Enabled := False
        else
        begin
          FAction := akBreak;
          FActionTime := FBreakTime;
        end;
      end;
      akBreak:
      begin
        FAction := akTraining;
        FActionTime := FTrainingTime;
      end;
    end;

  UpdateTimerLabel();
end;

To tak z grubsza, bo pisane z palca - nie testowałem, ale powinno działać. Ostatnim krokiem jest napisanie metody, która to będzie umożliwiała aktualizację etykiety wyświetlającej czas, na podstawie stanu zegara i wartości zmiennych. Przykładowy kod takiej metody poniżej:

procedure TMainForm.UpdateTimerLabel();
begin
  if ActionTimer.Enabled then
  begin
    case FAction of
      akTraining: TimerLabel.Font.Color := IfThen(FActionTime > FTimeToSound, clRed, clBlue);
      akBreak:    TimerLabel.Font.Color := IfThen(FActionTime > FTimeToSound, clRed, clGreen);
    end;

    TimerLabel.Caption := FormatTime('NN:SS', EncodeTime(0, FActionTime div 60, FActionTime mod 60));
  end
  else
  begin
    TimerLabel.Font.Color := clLtGray;
    TimerLabel.Caption := '00:00';
  end;
end;

Powyższy kod zmienia kolor etykiety oraz ustawia w Caption aktualny czas akcji (treningu lub przerwy).

To w sumie tyle - teraz musisz sobie ten kod przeczytać, zrozumieć, a następnie przenieść do swojego projektu. Nie da się go ot tak przekopiować i skompilować, bo nie wiem jakie nazwy posiadają kontrolki w Twoim projekcie, ale to już pozostawiam Tobie.

0

Cześć wybaczcie ze odświeżam temat szukam czegoś podobnego i natknąłem się na to:
Mam dwa pytania odnośnie ostatniej procedury:

  1. jako co trzeba zadeklarować IfThen
akTraining: Timer
Label.Font.Color := IfThen(FActionTime > FTimeToSound, clRed, clBlue);

to powyżej z ciekawości, zrozumienia i nauki.
2. Coś podobnego chciałem zaadoptować u siebie tylko nie rozumiem gdzie tu jest błąd:

TimerLabel.Caption := FormatTime('NN:SS', EncodeTime(0, FActionTime div 60, FActionTime mod 60));

tu akurat ze zmiennymi coś ogarniam tak mi się wydaje zmienną FormatTime zadeklarowałem jako typ **TDataTime ** ale wyskakują błędy przy kompilacji:

Missing operator or semicolon
Not enough actual parameters

Dlaczego?

0
  1. jako co trzeba zadeklarować IfThen

[..]

to powyżej z ciekawości, zrozumienia i nauki.

Po jakiemu to? Bo raczej nie po polsku. Funkcja IfThen to zwykła funkcja - ma ona służyć jako operator warunkowy (trójargumentowy), którego składnia języka póki co nie przewiduje. Kliknij w link i poczytaj, jeśli nie rozumiesz jak ona działa.

  1. Coś podobnego chciałem zaadoptować u siebie tylko nie rozumiem gdzie tu jest błąd:

TimerLabel.Caption := FormatTime('NN:SS', EncodeTime(0, FActionTime div 60, FActionTime mod 60));

Nigdzie nie ma błędu - ten kod jest prawidłowy.

tu akurat ze zmiennymi coś ogarniam tak mi się wydaje zmienną FormatTime zadeklarowałem jako typ **TDataTime ** ale wyskakują błędy przy kompilacji:

Missing operator or semicolon
Not enough actual parameters

FormatTime to jest funkcja, a nie zmienna. Jak nie chcesz mieć problemów to nie deklaruj zmiennej o takiej nazwie.

0

Co do pierwszego może brakować modułu System.Math

A do drugiego:

TimerLabel.Caption := FormatTime('NN:SS', EncodeTime(0, FActionTime div 60, FActionTime mod 60));

> 
> Nigdzie nie ma błędu - ten kod jest prawidłowy.
>** FormatTime to jest funkcja**, a nie zmienna. Jak nie chcesz mieć problemów to nie deklaruj zmiennej o takiej nazwie.

Mimo wszystko wydaje mi się że są i to dwa, nie FormatTime tylko **FormatDateTime** oraz brakuje czwartego parametru w funkcji **EncodeTime** - milisekund. Zwykłe przeoczenie pewnie.

```delphi
TimerLabel.Caption := FormatDateTime('NN:SS', EncodeTime(0, FActionTime div 60, FActionTime mod 60,0));

1 użytkowników online, w tym zalogowanych: 0, gości: 1