Flux de sortie de processus vers la zone de texte Java FX avec Défilement automatique


Je construis et l'application qui crée un processus et diffuse sa sortie standard dans une zone de texte javafx. Tout comme les émulateurs de terminaux, je veux que la sortie défile automatiquement jusqu'à la fin de la console si le processus affiche trop de lignes.

Le problème est que la zone de texte ne défile pas jusqu'à la fin du texte, mais reste plutôt en haut. Un autre comportement étrange est que lorsque j'essaie de faire défiler la zone de texte à l'aide de la molette de la souris / du clavier / de la barre de défilement, la zone de texte défile pour le très haut.

J'ai déjà essayé les réponses ici, ici, et ici. Il semble que j'ai quelque chose de mal ailleurs.

Voici le contenu de la méthode void streamToTextArea(java.lang.Process process) - La méthode qui fait le gros du travail en exécutant le processus et en le diffusant vers le consoleTextArea.

Task bgTask = new Task<Void>() {
    @Override
    protected void call() throws Exception {
        InputStream inputStream = process.getInputStream();
        StringBuilder consoleContent = new StringBuilder();

       try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
           String line;
           while((line = reader.readLine()) != null) {
               consoleContent
                   .append(line)
                   .append("\n");
               updateMessage(consoleContent.toString());
               consoleTextArea.appendText(""); // trigger ChangeListener
           }
       } catch (IOException e) { doSomething(e); }
       return null;
    }
};

StringProperty textProperty = consoleTextArea.textProperty();
textProperty.addListener((observable, oldValue, newValue) -> {
    // currently:
    consoleTextArea.selectPositionCaret(consoleTextArea.getLength());
    consoleTextArea.deselect();

    // also tried:
    // consoleTextArea.setScrollTop(Double.MAX);
});
textProperty.bind(bgTask.messageProperty());

// start bgTask as daemon thread
// add event handling when bgTask ended
Author: Community, 2017-03-17

1 answers

Tout d'abord, la méthode Task.call()est pas exécutée dans le thread d'application JavaFX, donc changer tout état de la vue actuelle dans cette méthode est inapproprié. Vous ajoutez "" à consoleTextArea dans le mauvais thread. Vous devriez le faire comme ceci:

Platform.runLater(() -> {
    consoleTextArea.appendText("");
});

Le deuxième problème est que l'appel de consoleTextArea.appendText(""); ne déclenchera pas votre ChangeListener(en fait, cela ne fera rien), car vous liez la propriété de texte consoleTextArea à la propriété de message Task textProperty.bind(bgTask.messageProperty());. Dans ce cas, la zone de texte n'écoutera que le changement de texte dans Task propriété du message. Ajoutez votre écouteur à la propriété message:

bgTask.messageProperty().addListener((observable, oldValue, newValue) -> {
    // currently:
    consoleTextArea.selectPositionCaret(consoleTextArea.getLength());
    consoleTextArea.deselect();

    // also tried:
    // consoleTextArea.setScrollTop(Double.MAX);
});
 1
Author: MBec, 2017-03-17 08:40:35