| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 
 | import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Objects;
import java.util.Optional;
 
public final class Main extends Application {
    public static final void main(final String... args) {
        launch(args);
    }
 
    @Override
    public void start(final Stage primaryStage) throws Exception {
        final var textArea1 = new TextArea();
        textArea1.setEditable(false);
        VBox.setVgrow(textArea1, Priority.ALWAYS);
        final var textArea2 = new TextArea();
        textArea2.setEditable(false);
        VBox.setVgrow(textArea2, Priority.ALWAYS);
        final var vbox = new VBox();
        vbox.getChildren().setAll(new Label("Output"), textArea1, new Label("Error"), textArea2);
        final var startButton = new Button("Start");
        startButton.setOnAction(event -> startProcessAsync(textArea1, textArea2));
        final var stopButton = new Button("Stop");
        stopButton.setOnAction(event -> stopProcess());
        final var toolBar = new ToolBar();
        toolBar.getItems().setAll(startButton, stopButton);
        final var root = new BorderPane();
        root.setTop(toolBar);
        root.setCenter(vbox);
        final var scene = new Scene(root, 800, 800);
        primaryStage.setTitle("Test");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
 
    private static record ProcessHandle(Process process, StreamConsumer outputConsumer, StreamConsumer errorConsumer) {
        public void stop() {
            System.out.println("Killing process.");
            process.destroy();
            outputConsumer.interrupt();
            errorConsumer.interrupt();
        }
    }
 
    private Service<ProcessHandle> backgroundTask;
 
    private void stopProcess() {
        Optional.ofNullable(backgroundTask)
                .ifPresent(Service::cancel);
    }
 
    private void startProcessAsync(final TextArea outputArea, final TextArea errorArea) {
        Optional.ofNullable(backgroundTask)
                .ifPresent(Service::cancel);
        backgroundTask = null;
        final var service = new Service<ProcessHandle>() {
 
            @Override
            protected Task<ProcessHandle> createTask() {
                return new Task<>() {
                    @Override
                    protected ProcessHandle call() throws Exception {
                        System.out.println("Starting process.");
//            final var process = new ProcessBuilder("cmd.exe", "/C", "test.bat").start();
//            final var process = new ProcessBuilder("ipconfig.exe").start();
                        final var process = new ProcessBuilder("ping.exe", "-t", "www.google.com").start();
                        final var t1 = new StreamConsumer(process.getInputStream(), outputArea);
                        final var t2 = new StreamConsumer(process.getErrorStream(), errorArea);
                        final var result = new ProcessHandle(process, t1, t2);
                        updateValue(result);
                        t1.start();
                        t2.start();
                        t1.join();
                        t2.join();
                        return result;
                    }
                };
            }
        };
        service.setOnSucceeded(event -> System.out.println("Success"));
        service.setOnCancelled(event -> {
            System.out.println("Cancelled");
            final ProcessHandle processHandler = (ProcessHandle)event.getSource().getValue();
            Optional.of(processHandler)
                    .ifPresent(ProcessHandle::stop);
        });
        service.setOnFailed(event -> System.out.println("Failed " + event.getSource().getException()));
        backgroundTask = service;
        backgroundTask.start();
    }
 
    private final static class StreamConsumer extends Thread {
        private final TextArea textArea;
        private final InputStream input;
 
        public StreamConsumer(final InputStream input, final TextArea textArea) {
            this.input = input;
            this.textArea = textArea;
            setPriority(Thread.MIN_PRIORITY);
        }
 
        @Override
        public void run() {
            try (final var reader = new BufferedReader(new InputStreamReader(input))) {
                String line = null;
                while (!Thread.currentThread().isInterrupted() && (line = reader.readLine()) != null) {
//                        System.out.println("Error: " + line);
                    final var text = line;
                    Platform.runLater(() -> updateConsoleAtFXAppThread(text));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
 
        }
 
        private final void updateConsoleAtFXAppThread(final String line) {
            var text = textArea.getText();
            text = (Objects.isNull(text) || text.isBlank()) ? line : text + "\n" + line;
            textArea.setText(text);
            textArea.setScrollTop(Double.MAX_VALUE);
        }
    }
} | 
Partager