JavaFX e controle de threads

7 respostas
javafxjava
S

Eu gostaria de travar a Thread atual do meu programa enquanto executo uma segunda thread, pois preciso de seu retorno, para ilustrar meu problema segue o código abaixo:

Task task = new Task() {
            @Override
            protected Object call() {
                try {
                    this.updateMessage("carregando teste...");
                    for (int i = 1; i <= 10; i++) {
                        System.out.println("Número: " + i);
                        Thread.sleep(1000);
                    }
                    this.updateMessage("fim");
                    return "Eba!!!!";
                } catch (InterruptedException ex) {
                    new Logger().erro(this.getClass(), "start(Stage stage)", ex);
                    return null;
                }
            }
        };
        this.abreStageDoJavaFX();
        new Thread(task).start();
        this.fechaStageDoJavaFX();

Quando eu faço o comando new Thread(task).start(); ele inicia a thread mas continua a atual, logo, ele abre e fecha minha tela imediatamente após iniciar a thread. Eu tentei fazer o seguinte:

abreStageDoJavaFX();
        new Thread(task).start();
        while(!task.isDone()){
            Thread.sleep(1000);
        }
        this.fechaStageDoJavaFX();

E realmente a Thread principal do meu programa ficou presa no while enquanto a segunda thread não terminou, porém, o método this.abrirStageDoJavaFX(); foi executado sem que a tela aparecesse, é como se a view só fosse atualizada após o fim da execução de todo o método que chamou ela, e como esperado o método this.fechaStageDoJavaFX() fechou a tela (que nem chegou a abrir) após sair do while… Alguém sabe como abrir um Stage, iniciar uma thread, esperar até o fim dela, e depois fechar esse stage?

7 Respostas

A

Já tentou usar um Service, ele possui métodos start, succedede failed, em ambos você pode executar ações na UI, há também um método createTask onde vc executa o processamento através de uma Task e esse estará disponível no succeded.

Exemplo:

Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

    Scene scene = new Scene(root);

    stage.setScene(scene);

    new Service<Integer>() {
        @Override
        public void start() {
            super.start();
            stage.show();
        }

        @Override
        protected Task<Integer> createTask() {
            return new Task<Integer>() {
                @Override
                protected Integer call() throws Exception {
                        Thread.sleep(3000);
                        return 1;
                }
            };
        }

        @Override
        protected void succeeded() {
            // getValue(); Obtem o valor processado na Task
           stage.close();
        }
        
    }.start();
S

Obrigado por responder @Andrauss, Quanto ao service eu nem sabia que ele existia kkkk, mas enfim, a primeira coisa que estou achando estranho é que você abre a GUI dentro do service, e basicamente quem controla a GUI desse stage no seu exemplo é a segunda thread, e isso não se encaixa bem com o conceito que quero implementar. usando seu exemplo eu gostaria de fazer isso:

Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

    Scene scene = new Scene(root);

    stage.setScene(scene);
    //Esse stage é modal
    stage.show();

    Service service = new Service<Integer>() {
        @Override

public void start() {
            super.start();
        }

@Override
        protected Task<Integer> createTask() {
            return new Task<Integer>() {
                @Override
                protected Integer call() throws Exception {
                        Thread.sleep(3000);
                        return 1;
                }
            };
        }

@Override
        protected void succeeded() {
            // getValue(); Obtem o valor processado na Task
           stage.close();
        }
        
    };
service.start();
//Enquanto o service não terminar sua execução nem tente recuperar o retorno
Pessoa retornoDaThread = (Pessoa) service.get();
//Se o service não travar o fluxo atual e esse comando for executado a saída será nula
System.out.println(retornoDaThread.getNome());

Não sei se ficou claro… Mas o controle da GUI ficar dentro da segunda Thread não é um grande problema, pois acredito que mesmo dentro da segunda thread eu ainda consigo um efeito de stage.initModality.APPLICATION_MODAL, meu real problema é dar start na thread, esperar pelo retorno que ela vai gerar, e só depois continuar o fluxo (mas claro, sem interferir na GUI =D), acho que vendo somente as 5 ultimas linhas do exemplo acima você entende, e novamente muito obrigado pelo retorno.

A

Então basicamente o que quer é que uma tela aguarde a execução em outra tela e receba o retorno da mesma?

S

Exatamente, o método que quero executar é exatamente esse:

public void setTask(Stage stage, Task task) {
        stage.show();
        lbMensagem.progressProperty().unbind();
        lbMensagem.progressProperty().bind(task.progressProperty());
        new Thread(task).start();
        //aqui deveria esperar o fim da execução
        stage.close();
        retorno = task.get();
    }

Eu recebo o stage e a task prontas de outra classe, não dá pra enfiar a stage dentro da task nesse ponto… então tento inciar a GUI fora da thread, esperar a thread finalizar, e depois fechar, pra tornar o retorno disponível

E

com base nisso o stage.showAndWait() resolve o problema

S

@Eduardo_Maranata10 seguindo sua ideia ficaria assim:

public void setTask(Stage stage, Task task) {
        lbMensagem.progressProperty().unbind();
        lbMensagem.progressProperty().bind(task.progressProperty());
        new Thread(task).start();
        stage.showAndWait();
        retorno = task.get();
    }

mas quem daria o stage.close() quando o task terminasse?

E

Tem como tu colocar a classe completa

De longe sua solução seria colocar no método succeeded

http://stackoverflow.com/questions/13784333/platform-runlater-and-task-in-javafx

Criado 18 de maio de 2017
Ultima resposta 20 de mai. de 2017
Respostas 7
Participantes 3