JavaFX: есть текст метки обновления фоновой задачи в окне FXML? - PullRequest
0 голосов
/ 22 февраля 2019

Моя цель - создать окно javaFX, которое при нажатии будет увеличивать счетчик одноэлементного класса.Фоновая задача должна прочитать значение в синглтоне и отобразить его в том же окне.Ниже приведен синглтон.

Singleton.java:

public class Singleton {
    private static Singleton singleton = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return singleton;
    }

    //=====================================

    private int count = 0;

    public void increment() {
        count++;
        System.out.println(count);
    }

    public int getCount() {
        return count;
    }

}

Чтобы создать фоновый поток, я попытался создать задачу с помощью метода initialize () . JavaFX.INITIALIZABLE , но это приводит к ошибке « Не в потоке приложения FX ».Ниже приведено основное, которое захватывает FXML и запускает окно.

main.java:

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
            primaryStage.setTitle("Hello World");

            Scene scene = new Scene(root,400,400);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();

        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Sample.fxml - Здесь я определяю структуру окна.Обратите внимание на fx: id = "counter" для первой метки.

<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="199.0" prefWidth="230.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
   <children>
      <AnchorPane layoutX="22.0" layoutY="9.0" prefHeight="182.0" prefWidth="186.0">
         <children>
            <Button layoutX="14.0" layoutY="76.0" mnemonicParsing="false" onAction="#buttonClicked" text="Increment" />
            <Label fx:id="counter" layoutX="131.0" layoutY="81.0" text="0" />
            <Label layoutX="28.0" layoutY="34.0" text="First JavaFX Project" />
         </children>
      </AnchorPane>
   </children>
</Pane>

Controller.java - И, наконец, контроллер.Функция initialize создает новый поток для запуска задачи, необходимой для получения значения счетчика, но не может редактировать исходное окно.

public class Controller implements Initializable {

    // Links to Singleton classes
    private Singleton sin = Singleton.getInstance();


    // Links to FXML elements
    @FXML
    private Label counter;

    public void buttonClicked() {
        System.out.print("Click");
        sin.increment();
    }

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {

        MyTask myTask = new MyTask();
        Thread myTaskThread = new Thread(myTask);
        myTaskThread.start();
    }

    class MyTask extends Task<Void>{

        @Override
        protected Void call() throws Exception {
            while(true) {
                int count = sin.getCount();
                counter.setText(Integer.toString(count));


            }
        }

    }
}

Как получить этот поток для периодического обновления элементов FXML назапущенное приложение?

Ответы [ 2 ]

0 голосов
/ 23 февраля 2019

В вашем сценарии использования не требуется фоновый поток, вам просто нужно использовать двустороннюю привязку javafx и StringProperty


public class Controller implements Initializable {

  // Links to Singleton classes
  private Singleton sin = Singleton.getInstance();

  // Links to FXML elements
  @FXML
  private Label counter;

  private StringProperty singletonCounter;

  @Override
  public void initialize(URL url, ResourceBundle resourceBundle) {
    singletonCounter = new SimpleStringProperty();
    singletonCounter.set(sin.getCount() + "");
    counter.textProperty().bind(singletonCounter);
  }

  public void buttonClicked() {
    sin.increment();
    singletonCounter.setValue(sin.getCount() + "");
  }

}
0 голосов
/ 22 февраля 2019

Я полагаю, что ваша строка, пытающаяся обновить текст, должна использоваться внутри этого кода

Platform.runLater(() -> {insert your code here});

Вот как должен выглядеть ваш класс MyTask при обновлении текстового значения:

class MyTask extends Task<Void>{

    @Override
    protected Void call() throws Exception {
        while(true) {
            int count = sin.getCount();
            Platform.runLater(() -> {
               counter.setText(Integer.toString(count));
            });
        }
    }

}

При попытке обновить что-либо в пользовательском интерфейсе вы должны быть в потоке приложения.Приведенный выше код говорит программе выполнить код в потоке приложения.

...