A ideia é bem simples, um temporizador configurável que pode ser usado como auxílio aos que gostam da técnica pomodoro. Já quem quer aprender JavaFX, esse é só um código de exemplo de uso da classe Animation.
A ideia é bem simples: você escolhe um tempo e o temporizador começa a diminuir aquele tempo tocando um "tick" até chegar a 0 e então um som de bomba explodindo é tocado.
O código não é complexo, veja abaixo e sem seguida uma pequena explicação:
- A aplicação funciona dependendo da classe Animation que é controlada pelo único botão da aplicação. Criamos uma animação sem fim(sem tempo para parar), mas que a sua execução é controlada pelo botão;
- Para que seja executado código a cada um segundo, adicionamos um KeyFrame na animação que é executado a cada 1 segundo e tem por ação o método atualizaValores;
- Quando o botão é clicado, verificamos o estado atual dele (se ele está com texto PARAR ou Começar) e de acordo com esse valor paramos ou iniciamos a animação e também pegamos o atual valor selecionado no slider;
- No método atualizaValores é onde tudo acontece. Nele atualizamos o valor do label, atualizamos o tempo restante e também tocamos o áudio;
- O método atualizaLabelTempo é responsável por pegar o valor em segundos e transformar no formato mm:ss, para que seja mostrado no label;
Essa é a ideia básica dessa app feita em menos de 1 hora. Você pode pegar o código no github e melhorar para adicionar mais funcionalidades! Veja abaixo o código final:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.aprendendojavafx.timer; | |
import javafx.animation.Animation; | |
import javafx.animation.Animation.Status; | |
import javafx.animation.KeyFrame; | |
import javafx.animation.Timeline; | |
import javafx.application.Application; | |
import javafx.geometry.Pos; | |
import javafx.scene.Scene; | |
import javafx.scene.control.Button; | |
import javafx.scene.control.Label; | |
import javafx.scene.control.Slider; | |
import javafx.scene.layout.VBox; | |
import javafx.scene.media.Media; | |
import javafx.scene.media.MediaPlayer; | |
import javafx.scene.text.Font; | |
import javafx.scene.text.FontWeight; | |
import javafx.stage.Stage; | |
import javafx.util.Duration; | |
public class Main extends Application { | |
final String SOM_TICK = "/sons/tick.mp3"; | |
final String SOM_GRANADA = "/sons/granada.mp3"; | |
final String COMECAR = "Começar"; | |
final String PARAR = "PARAR"; | |
private Slider sldValor; | |
private Label lblValor; | |
private Button btnAcao; | |
// temporiza o tempo do slider | |
private Timeline temporizador; | |
int tempoFaltante; | |
private MediaPlayer mpTick; | |
private MediaPlayer mpGranada; | |
public static void main(String[] args) { | |
launch(); | |
} | |
@Override | |
public void start(Stage palco) throws Exception { | |
inicializacoes(); | |
VBox vbRaiz = constroiInterface(); | |
// não pode alterar o slider se já estiver tocando | |
sldValor.disableProperty().bind( | |
temporizador.statusProperty().isEqualTo(Status.RUNNING)); | |
ajustaLabel(); | |
// ajustes finais | |
palco.setScene(new Scene(vbRaiz)); | |
palco.setWidth(600); | |
palco.setHeight(400); | |
palco.setTitle("Temporizador (parado)"); | |
palco.show(); | |
// deve existir forma melhor e fazer isso | |
lblValor.textProperty().addListener(i -> { | |
if(btnAcao.getText().equals(COMECAR)) { | |
palco.setTitle("Temporizador (parado)"); | |
} else { | |
palco.setTitle("Temporizador (" + lblValor.getText() + ")"); | |
} | |
}); | |
} | |
private void inicializacoes() { | |
temporizador = new Timeline(); | |
temporizador.setCycleCount(Animation.INDEFINITE); | |
String arquivoTick = Main.class.getResource(SOM_TICK).toString(); | |
String arquivoGranada = Main.class.getResource(SOM_GRANADA).toString(); | |
mpTick = new MediaPlayer(new Media(arquivoTick)); | |
// para evitar flood no play, só para qunado parar de tocar a mídia de vez | |
mpTick.setOnEndOfMedia(() -> { | |
mpTick.stop(); | |
}); | |
mpGranada = new MediaPlayer(new Media(arquivoGranada)); | |
} | |
private VBox constroiInterface() { | |
// inicializando nossos elementos de interface ativos | |
lblValor = new Label(); | |
sldValor = new Slider(0, 30 * 60, (30 * 60) / 2); | |
btnAcao = new Button(COMECAR); | |
// configura as marquinhas do slider | |
sldValor.setMajorTickUnit(100); | |
sldValor.setBlockIncrement(1f); | |
sldValor.setSnapToTicks(true); | |
sldValor.setShowTickMarks(true); | |
// configuraÇão do label | |
lblValor.setFont(Font.font("", FontWeight.BOLD, 90)); | |
// o valor do label muda se mexermos o slider | |
sldValor.valueProperty().addListener(l -> ajustaLabel()); | |
VBox vbRaiz = new VBox(50, lblValor, sldValor, btnAcao); | |
// alinha os elementos ao centro | |
vbRaiz.setAlignment(Pos.CENTER); | |
// registra o listener do botão | |
btnAcao.setOnAction(e -> acao()); | |
return vbRaiz; | |
} | |
private void ajustaLabel() { | |
// só pode ajudar assim se for ajuste manual do slider | |
if(sldValor.isDisable() == false) { | |
int segundos = sldValor.valueProperty().intValue(); | |
atualizaLabelTempo(segundos); | |
} | |
} | |
public void acao() { | |
if (btnAcao.getText().equals(COMECAR)) { | |
btnAcao.setText(PARAR); | |
int segundos = sldValor.valueProperty().intValue(); | |
final KeyFrame frameSegundos = new KeyFrame(Duration.seconds(1), | |
e -> atualizaValores()); | |
temporizador.getKeyFrames().setAll(frameSegundos); | |
temporizador.playFrom(Duration.seconds(segundos)); | |
tempoFaltante = segundos; | |
} else { | |
btnAcao.setText(COMECAR); | |
temporizador.stop(); | |
} | |
} | |
public void atualizaValores() { | |
if(tempoFaltante < 1) { | |
temporizador.stop(); | |
btnAcao.setText(COMECAR); | |
mpGranada.stop(); | |
mpGranada.play(); | |
return; | |
} | |
tempoFaltante--; | |
mpTick.play(); | |
atualizaLabelTempo(tempoFaltante); | |
sldValor.setValue(tempoFaltante); | |
} | |
private void atualizaLabelTempo(int segundos) { | |
String txtMinutos = String.format("%02d", segundos / 60); | |
String txtSegundos = String.format("%02d", segundos % 60); | |
lblValor.setText(txtMinutos + ":" + txtSegundos); | |
} | |
} |