Diskuze: 5 minutový countdown (v JavaFX)

Java Java 5 minutový countdown (v JavaFX)

Avatar
Vojtěch Bešťák:

Zdravím, snažím se vytvořit 5 minutový countdown za pomoci kódu, který mi poradil Atrament
Zde je můj dosavadní zdrojový kód:

@FXML
    private void handlestartButtonAction(ActionEvent event)
    {


        casSekundy.setCycleCount(countDownSeconds2); //nastaví se počet opakování, tedy pošet sekund k odpočtu
        casSekundy.play(); //a jedeme...
        startButton.setVisible(false);

    }
private int countDownSeconds2 = 59; // bude se odpočítávat od 3 do nuly
    private final StringProperty casSekundyValue = new SimpleStringProperty(countDownSeconds2 + ""); //StringProperty countDownValue se později 'přibinduje' k countdownLabel, když se změní hodnota  countDownValue, změní se i countdownLabel
    private final StringProperty casMinutyValue = new SimpleStringProperty(4 + "");
//nyní vytvoříme timeline s duration 1 sekunda
    private final Timeline casSekundy = new Timeline(new KeyFrame(Duration.seconds(1), (e) -> {

        int i = Integer.parseInt(casSekundyValue.getValue()) - 1; //koukneme jaka je hodnota countDownValue a snížíme o jedna
        casSekundyValue.setValue(i + "");//nastavíme countDownValue novou hodnotu
        if (i == 0)
        {
            casSekundyValue.setValue("59");
            odeberMinuty();
            cas();
        }




}));
    public void cas()
        {
            casSekundy.setCycleCount(countDownSeconds2); //nastaví se počet opakování, tedy pošet sekund k odpočtu
            casSekundy.play(); //a jedeme...
        }

    public void odeberMinuty()
    {
        int j = Integer.parseInt(casMinutyValue.getValue()) - 1;
        casMinutyValue.setValue(j + "");
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        countdownLabel.textProperty().bind(countDownValue);
        casSekundyLabel.textProperty().bind(casSekundyValue);
        casMinutyLabel.textProperty().bind(casMinutyValue);
        countdownLabel.setVisible(false);


    }

Moje představa byla taková, že se nejdříve odečte 59 sekund z

casSekundyValue

a poté se díky metodě

odeberMinuty()

a

cas()

odebere 1 minuta a znovu se spustí odpočítávání 59 sekund.

Ovšem výsledek byl takový, že po spuštění aplikace tlacitkem se odečetlo prvních 59 sekund, poté se minuty změnili ze 4 na 3 a sekundy se vrátili zpět na 59. Ale odpočítávání další minuty nezačalo.
Pomůže mi prosím někdo, a řekne mi co mám špatně?

 
Odpovědět 21. května 10:10
Avatar
Odpovídá na Vojtěch Bešťák
Petr Štechmüller:

Ahoj, co na to jít trochu jinak. Pokud chceš odpočet 5 minut, tak ten interval čas sekundy nastav na hodnotu 5*60. Pak místo kontroly, zda-li i==0 můžeš kontrolovat něco ve stylu i%60==0. Tímto zkontrolujes, jestli je hodnota i násobek 60, neboli jestli ubehla minuta. Pokud se podmínka splní, tak můžeš odečíst minutu a nemusí s restartovat žádném timer...

Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
Nahoru Odpovědět 21. května 12:25
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Elisse
Člen
Avatar
Odpovídá na Vojtěch Bešťák
Elisse:

Ahoj ahoj, nechci ti tu myšlenku nějakou celou rozbíjet, ale nešlo by vyjít z aktuálního systémového času a založit to na tom? :)

 
Nahoru Odpovědět 21. května 13:16
Avatar
Odpovídá na Petr Štechmüller
Vojtěch Bešťák:

Děkuji dobrý nápad, zkusil jsem to nějak předělat:

    @FXML
    private void handlestartButtonAction(ActionEvent event)
    {
        cas();
        startButton.setVisible(false);
    }
    private int zbyvaMinut = 5;
    private int zbyvaSekund = zbyvaMinut*60;
    private int zbyvaMinutAktualne = zbyvaMinut;
    private int zbyvaSekundAktualne = zbyvaSekund;

    private final StringProperty casSekundyValue = new SimpleStringProperty(zbyvaSekund + "");
    private final StringProperty casMinutyValue = new SimpleStringProperty(zbyvaMinut + "");

    private final Timeline casSekundy = new Timeline(new KeyFrame(Duration.seconds(1), (e) -> {
        zbyvaSekundAktualne--;
        int vytisk = (zbyvaSekundAktualne - ((zbyvaMinutAktualne - 1) * 60)) -1;
        casSekundyValue.setValue(String.format("%02d", vytisk));


        if(zbyvaSekundAktualne == zbyvaSekund - 1)
        {
            odeberMinuty();
        }
        if(zbyvaSekundAktualne == 241 || zbyvaSekundAktualne == 181 || zbyvaSekundAktualne == 121 || zbyvaSekundAktualne == 61)
        {
            odeberMinuty();
            zbyvaMinutAktualne--;
        }




}));


    public void cas()
    {
        casSekundy.setCycleCount(zbyvaSekund); //nastaví se počet opakování, tedy počet sekund k odpočtu
        casSekundy.play();

    }


    public void odeberMinuty()
    {
        int j = Integer.parseInt(casMinutyValue.getValue()) - 1;
        casMinutyValue.setValue(String.format("%02d", j));
        zbyvaMinut--;
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        countdownLabel.textProperty().bind(countDownValue);
        casSekundyLabel.textProperty().bind(casSekundyValue);
        casMinutyLabel.textProperty().bind(casMinutyValue);
        countdownLabel.setVisible(false);

Po tomto to již ve své podstatě odpočítává 5 minut, ale na úplném začátku před zmáčknutí tlačítka se zobrazuje: viz. obrazek - 5 minut 300 sekund (tedy počáteční hodnoty countdownu)

Po zmáčknutí tlačítka se 1 sekudnu nic neděje, a pak se najednou objeví 04:58. To znamená, že z nějakého důvodu nezobrazí 59.

Další věc, která je tak trochu rozbitá je přechod jednotlivých minut. casMinutyLabel se v GUI zmenší o 1 ve chvíly, kdy v casSekundyLabel je teprve 00.

Nezná prosím někdo řešení těchto problémů?

Editováno 21. května 15:53
 
Nahoru Odpovědět 21. května 15:53
Avatar
Atrament
Člen
Avatar
Odpovídá na Vojtěch Bešťák
Atrament:

Já bych na to šel ještě trochu jinak :) Změnil bych nastavení té timeline tak aby neodpočítávala konkrétní počet cyklů, ale aby běžela do nekonečna setCycleCount(Ti­meline.INDEFI­NITE). Tím by mi vlastně odtikávala sekundy. Při každém 'tiknutí' bych zkontroloval jestli jsou minuty a sekundy už nula, a když jo tak bych tu timeline stopnul a provedl to co chceš provést po skončení odpočtu. Když ne tak bych ubral jednu sekundu, pokud by se tím dostal počet sekund na nulu tak bych koukl jestli jsou minuty víc než 0 a když jo tak bych ubral minutu a nastavil na sekundách 59.

 
Nahoru Odpovědět  +1 21. května 17:00
Avatar
Odpovídá na Atrament
Petr Štechmüller:

Tak to je podobné, co jsem já navrhoval s tím rozdílem, že znám předem dobu, jak dlouho to poběží...

Nahoru Odpovědět 21. května 17:10
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Vojtěch Bešťák:

Z nějakého důvodu mi tento kód hází po zmáčnkutí tlačítka chybu:
Kód:

    @FXML
    private void handlestartButtonAction(ActionEvent event)
    {
        countdownLabel.setVisible(true);
        cas();
        startButton.setVisible(false);
    }

    private final StringProperty casSekundyValue = new SimpleStringProperty();
    private final StringProperty casMinutyValue = new SimpleStringProperty();

    private final Timeline casSekundy = new Timeline(new KeyFrame(Duration.seconds(1), (e) -> {
        int s = Integer.parseInt(casSekundyValue.getValue());
        int m = Integer.parseInt(casMinutyValue.getValue());
        if(s == 0 && m == 0)
        {
            stopTimeLine();
            System.out.println("Odpočet úspěšně dokončen");
        }
        else
            if (s != 0)
            {
                casSekundyValue.setValue(String.format("%02d", s - 1));
            }
        else
            {
                casMinutyValue.setValue(String.format("%02d", m - 1));
                casSekundyValue.setValue(String.format("%02d", 59));
            }
}));

    public void stopTimeLine()
    {
        casSekundy.stop();
    }

    public void cas()
    {
        casSekundy.setCycleCount(Timeline.INDEFINITE);
        casSekundy.play();


    }
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        countdownLabel.textProperty().bind(countDownValue);
        casSekundyLabel.textProperty().bind(casSekundyValue);
        casMinutyLabel.textProperty().bind(casMinutyValue);
        countdownLabel.setVisible(false);
    }

Chyba:

ant -f "C:\\Users\\Vojta\\Dropbox\\Java\\Programy - NetBeans\\Objektově orientované programování\\STIGA-Scoreboard" jfxsa-run
init:
Deleting: C:\Users\Vojta\Dropbox\Java\Programy - NetBeans\Objektově orientované programování\STIGA-Scoreboard\build\built-jar.properties
deps-jar:
Updating property file: C:\Users\Vojta\Dropbox\Java\Programy - NetBeans\Objektově orientované programování\STIGA-Scoreboard\build\built-jar.properties
Compiling 1 source file to C:\Users\Vojta\Dropbox\Java\Programy - NetBeans\Objektově orientované programování\STIGA-Scoreboard\build\classes
compile:
Detected JavaFX Ant API version 1.3
Launching <fx:jar> task from C:\Program Files\Java\jdk1.8.0_77\jre\..\lib\ant-javafx.jar
Warning: From JDK7u25 the Codebase manifest attribute should be used to restrict JAR repurposing.
         Please set manifest.custom.codebase property to override the current default non-secure value '*'.
Launching <fx:deploy> task from C:\Program Files\Java\jdk1.8.0_77\jre\..\lib\ant-javafx.jar
No base JDK. Package will use system JRE.
No base JDK. Package will use system JRE.
jfx-deployment-script:
jfx-deployment:
jar:
Copying 12 files to C:\Users\Vojta\Dropbox\Java\Programy - NetBeans\Objektově orientované programování\STIGA-Scoreboard\dist\run549448994
jfx-project-run:
Executing C:\Users\Vojta\Dropbox\Java\Programy - NetBeans\Objektově orientované programování\STIGA-Scoreboard\dist\run549448994\STIGA-Scoreboard.jar using platform C:\Program Files\Java\jdk1.8.0_77\jre/bin/java
Exception in thread "JavaFX Application Thread" java.lang.NumberFormatException: null
        at java.lang.Integer.parseInt(Integer.java:542)
        at java.lang.Integer.parseInt(Integer.java:615)
        at stiga.scoreboard.FXMLDocumentController.lambda$new$1(FXMLDocumentController.java:135)
        at com.sun.scenario.animation.shared.TimelineClipCore.visitKeyFrame(TimelineClipCore.java:239)
        at com.sun.scenario.animation.shared.TimelineClipCore.playTo(TimelineClipCore.java:180)
        at javafx.animation.Timeline.impl_playTo(Timeline.java:176)
        at javafx.animation.AnimationAccessorImpl.playTo(AnimationAccessorImpl.java:39)
        at com.sun.scenario.animation.shared.InfiniteClipEnvelope.timePulse(InfiniteClipEnvelope.java:110)
        at javafx.animation.Animation.impl_timePulse(Animation.java:1102)
        at javafx.animation.Animation$1.lambda$timePulse$25(Animation.java:186)
        at java.security.AccessController.doPrivileged(Native Method)
        at javafx.animation.Animation$1.timePulse(Animation.java:185)
        at com.sun.scenario.animation.AbstractMasterTimer.timePulseImpl(AbstractMasterTimer.java:344)
        at com.sun.scenario.animation.AbstractMasterTimer$MainLoop.run(AbstractMasterTimer.java:267)
        at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:506)
        at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
        at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319)
        at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
        at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
        at java.lang.Thread.run(Thread.java:745)
Exception in thread "JavaFX Application Thread" java.lang.NumberFormatException: null
        at java.lang.Integer.parseInt(Integer.java:542)
        at java.lang.Integer.parseInt(Integer.java:615)
        at stiga.scoreboard.FXMLDocumentController.lambda$new$1(FXMLDocumentController.java:135)
        at com.sun.scenario.animation.shared.TimelineClipCore.visitKeyFrame(TimelineClipCore.java:239)
        at com.sun.scenario.animation.shared.TimelineClipCore.playTo(TimelineClipCore.java:180)
        at javafx.animation.Timeline.impl_playTo(Timeline.java:176)
        at javafx.animation.AnimationAccessorImpl.playTo(AnimationAccessorImpl.java:39)
        at com.sun.scenario.animation.shared.InfiniteClipEnvelope.timePulse(InfiniteClipEnvelope.java:110)
        at javafx.animation.Animation.impl_timePulse(Animation.java:1102)
        at javafx.animation.Animation$1.lambda$timePulse$25(Animation.java:186)
        at java.security.AccessController.doPrivileged(Native Method)
        at javafx.animation.Animation$1.timePulse(Animation.java:185)
        at com.sun.scenario.animation.AbstractMasterTimer.timePulseImpl(AbstractMasterTimer.java:344)
        at com.sun.scenario.animation.AbstractMasterTimer$MainLoop.run(AbstractMasterTimer.java:267)
        at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:506)
        at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
        at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319)
        at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
        at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
        at java.lang.Thread.run(Thread.java:745)
Deleting directory C:\Users\Vojta\Dropbox\Java\Programy - NetBeans\Objektově orientované programování\STIGA-Scoreboard\dist\run549448994
jfxsa-run:
BUILD SUCCESSFUL (total time: 11 seconds)
 
Nahoru Odpovědět 21. května 17:39
Avatar
Vojtěch Bešťák:

Děkuji moc :) Už jsem na to přišel, stačilo definovat tyto dvě proměnné:

private final StringProperty casSekundyValue = new SimpleStringProperty(0 + "");
private final StringProperty casMinutyValue = new SimpleStringProperty(5 + "");

Nicméně mám ještě jeden dotaz, jde nějak udělat, aby countdown před zmáčknutím tlačítka vypadal jako po zmáčknutí?
viz obrázky

 
Nahoru Odpovědět 21. května 17:50
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 8 zpráv z 8.