Параллелизм графики в реальном времени и остальных элементов в JavaFX?

Итак, это мои первые шаги с JavaFX. Я пытаюсь создать простое настольное приложение на JavaFx, которое эмулирует гистограмму в реальном времени, обновляясь каждую секунду, чтобы добавить часть полосы, которая представляет состояние каждого датчика (выключено). , не работает, работает нормально...). Мне нужно реализовать некоторые кнопки/текстовые поля/элементы меню для отправки информации как на датчик, так и на приложение.

Поэтому я использую метод, который вызывается из метода start() непосредственно перед добавлением холста в сцену, откуда я вызываю TimerTask для рисования графика каждую секунду. , и он работает нормально. При этом, когда я пытаюсь установить этот холст в центре BorderPane и добавить другие элементы в другую часть панели, на их работу влияет задержка TimerTask, даже когда этот timerTask предположительно выполняется другим потоком.

Как я могу отделить рисование в реальном времени от остальной части приложения в разных потоках?? Должен ли я использовать другой класс, отличный от «TimerTask»??

Код примерно такой:

@Override
public void start(Stage primaryStage) {
    this.primaryStage = primaryStage;
    BorderPane bp = new BorderPane();
    Group root = new Group();

    // create a canvas node
    Canvas canvas = new Canvas();

    // bind the dimensions when the user resizes the window.
    canvas.widthProperty().bind(primaryStage.widthProperty());
    canvas.heightProperty().bind(primaryStage.heightProperty());

    // obtain the GraphicsContext (drawing surface)
    final GraphicsContext gc = canvas.getGraphicsContext2D();

    //Invoke the real time graph drawing
    draw(gc);

    // add the single node onto the border pane
    bp.setCenter(canvas);
    MenuBar bar = new MenuBar();
    Menu sensorsMenu = new Menu("Sensors");
    bar.getMenus().add(sensors);
    for(int i=0; i<nDetect; i++){
        sensorsMenu.getItems().add(new CheckMenuItem("Sensor " + (i+1)));
    }
    //add the menu bar to top
    bp.setTop(bar);
    root.getChildren().add(bp);

    Scene scene = new Scene(root);
    primaryStage.setScene(scene);
    primaryStage.show();
}

public void draw(GraphicsContext gc){
    c = new SerialPortConection();

    c.establishConnection("COM1", 2400, 8, 1, 1);
    LinkedList<String> resp = null;

        .
        .
        .

    timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            javafx.application.Platform.runLater(new Runnable() {
            @Override
            public void run() {
                //Send request to sensor
                try {
                    resp = c.sendStatusRequest();
                } catch (WrongFormatException ex) {
Logger.getLogger(Sensor.class.getName()).log(Level.SEVERE, null, ex);
                }
                //Update sensor status
                for(int i=0; i<nSensors; i++){
                    sensors.get(i).update(resp.get(37+i));
                }

                //Draw sensors status
                for(int i=0; i<nSensors; i++){
                    sensors.get(i).draw(gc);
                }
                //Paint axis
                .
                .
                .
            }
        });
        }
    }, 0, 1000);
}

person Juan    schedule 10.03.2015    source источник
comment
Что такое респ и датчики?   -  person ItachiUchiha    schedule 10.03.2015
comment
resp — это ответ на запрос последовательного порта (в виде списка шестнадцатеричных строк, представляющих значение каждого байта). датчики — это список всех датчиков, а датчик — это список прямоугольников разного цвета, который представляет различное состояние датчиков во времени (есть класс датчиков и класс прямоугольников, но, поскольку рисунок работает нормально, я думаю, они могут не влезайте в тему)   -  person Juan    schedule 10.03.2015
comment
Затем resp = c.sendStatusRequest(); может потребоваться некоторое время для выполнения, так как он ожидает запроса. Не так ли? Если да, вы можете убрать его из Platform.runLater(), так как вы блокируете поток пользовательского интерфейса, ожидая ответа. Поместив его в Platform.runLater, он выполняется в том же потоке пользовательского интерфейса, а не в другом потоке.   -  person ItachiUchiha    schedule 10.03.2015
comment
Точно, около 650-700 мс, чтобы получить ответ, я не знал об этой проблеме с Platform.runLater(). Спасибо за ваш ответ   -  person Juan    schedule 10.03.2015
comment
Это не проблема, а то, как Platform.runLater работает.   -  person ItachiUchiha    schedule 10.03.2015
comment
Плохо, вместо этого я буду использовать факты ;)   -  person Juan    schedule 10.03.2015


Ответы (1)


Вы можете посмотреть на этот ответ:

периодическая фоновая задача JavaFX

Использование TimerTask допустимо. Вы должны использовать поток таймера (фоновый поток) для вызова вашего запроса к внешней службе и поток JFX для обновления графика:

    timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            // call external service in the background thread
            resp = c.sendStatusRequest();
            javafx.application.Platform.runLater(new Runnable() {
            @Override
            public void run() {
                // update the graphics in the JFX thread
            }
        });
        }
    }, 0, 1000);
person gontard    schedule 10.03.2015