Привязка метки JavaFX к StringProperty

В моем приложении JavaFX у меня есть метка, которую я хочу обновить с помощью StringProperty другого класса, который определяет функциональность сервера.

В классе сервера у меня есть StringProperty, как показано ниже:

public class eol_server {

     private StringProperty serverMessagesProperty;
     etc..

У меня есть способ вернуть StringProperty по запросу:

    public StringProperty serverMessagesProperty() {
    if (serverMessagesProperty == null) {
        serverMessagesProperty = new SimpleStringProperty();
    }
    return serverMessagesProperty;
}

В основном классе графического интерфейса, метод Start (), я создаю сцену, а затем создаю экземпляр нового объекта сервера. После этого я обновляю одну из меток в моем графике сцены, привязывая ее к StringProperty объекта сервера:

public void start(Stage primaryStage) {
    ...set up all the gui components
     primaryStage.show();
     dss = new eol_server();
     lbl_dssMessage.textProperty().bind(dss.getServerMessagesProperty());
}

Когда я запускаю приложение, сцена отображается так, как я ожидал, и для текста lbl_dssMessage устанавливается значение, установленное в конструкторе eol_server. Но с этого момента привязка не работает, хотя у меня есть действия, которые обновляют StringProperty объекта dss, они не обновляют метку в графическом интерфейсе.

Вот полный файл, который генерирует урезанную версию сцены:

public class eol_gui extends Application {

private static eol_server dss = null;
private static Stage primaryStage;


/**
 * Application Main Function
 * @param args
 */
public static void main(String[] args) {
    launch(args);
}

/**
 * @param stage
 */
private void setPrimaryStage(Stage stage) {
    eol_gui.primaryStage = stage;
}

/**
 * @return Stage for GUI
 */
static public Stage getPrimaryStage() {
    return eol_gui.primaryStage;
}

/* (non-Javadoc)
 * @see javafx.application.Application#start(javafx.stage.Stage)
 */
@Override
public void start(Stage primaryStage) {

    setPrimaryStage(primaryStage);

    BorderPane root = new BorderPane();
    Label lbl_dssMessage = new Label("initialized");
    HBox topMenu = new HBox();
    topMenu.getChildren().add(lbl_dssMessage);

    eol_supervisor_I config1 = new eol_supervisor_I();

    // Build Scene
    root.setStyle("-fx-background-color: #FFFFFF;");
    root.setTop(topMenu);
    primaryStage.setScene(new Scene(root, 300, 50));
    primaryStage.show();

    dss = new eol_server();
    dss.getServerMessagesProperty().addListener(new ChangeListener<Object>() {
                        @Override 
                        public void changed(ObservableValue<?> o,Object oldVal,Object newVal)
                        {
                            //Option 1: lbl_dssMessage.setText(newVal.toString());
                        }
    });
    //Option 2
    lbl_dssMessage.textProperty().bind(dss.serverMessagesProperty);
}

}

Как видите, я пробовал метод привязки и прослушиватель изменений. Похоже, что привязка работала, как и прослушиватель, во всех случаях, кроме тех, которые выполняются в потоках службы сервера. Они вызывают исключение IllegalStateException из-за отсутствия в основном потоке приложения JavaFX. Как безопасно и правильно обмениваться сообщениями из сервиса в основную ветку?

Сервер определен в следующем классе, который предназначен для запуска служб независимо от основного потока JavaFX. Но я хотел бы обмениваться информацией между потоками, чтобы показать статус. Я пытаюсь избежать зависания графического интерфейса пользователя во время подключения к серверу и обмена данными.

public class eol_server {

public StringProperty serverMessagesProperty;

public eol_server() {
    /* Create Scripting Environment */

    serverMessagesProperty().set("Establishing Debug Server Environment");
    connect();

}
public boolean connect() {  
    serverMessagesProperty().set("Creating Server");
    ConnectService connectService = new ConnectService();
    connectService.start();
    return false;
}

public StringProperty serverMessagesProperty() {
    if (serverMessagesProperty == null) {
        serverMessagesProperty = new SimpleStringProperty();
    }
    return serverMessagesProperty;
}

public StringProperty getServerMessagesProperty() {
    return serverMessagesProperty;
}

private class ConnectService extends Service<Void> {

    @Override
    protected void succeeded() {

    }

    @Override
    protected void failed() {

    }

    @Override
    protected void cancelled() {

    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                serverMessagesProperty().set("Connecting....");
                Thread.sleep(5000);
                // DEMO: uncomment to provoke "Not on FX application thread"-Exception:
                // connectButton.setVisible(false);
                serverMessagesProperty().set("Waiting for server feedback");
                Thread.sleep(5000);
                return null;
            }
        };
    }
}

private class DisconnectService extends Service<Void> {

    @Override
    protected void succeeded() {

    }

    @Override
    protected void cancelled() {

    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                updateMessage("Disconnecting....");
                serverMessagesProperty().set("Disconnecting....");
                Thread.sleep(5000);
                updateMessage("Waiting for server feedback.");
                serverMessagesProperty().set("Waiting for server feedback.");
                Thread.sleep(5000);

                return null;
            }
        };
    }

}

}

заранее спасибо

JW

Нет, привязка не должна теряться. Если вы обновляете другой экземпляр eol_server или обновляете serverMessagesProperty из потока, отличного от потока приложения javafx, это может вызвать проблемы. Блокировка потока приложения JavaFX с помощью длительной операции также может привести к такой проблеме. Невозможно сказать без минимальный воспроизводимый пример.

fabian 20.06.2018 19:13

думал, что это не решит проблему - посмотрите Соглашения кода Java для именования классов

lumo 21.06.2018 09:06
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
1 167
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Кажется, у меня есть решение, основанное на том, что я прочитал о методе платформы runlater (). Также см. Обсуждение здесь

Ошибка многопоточности при привязке StringProperty

изменение моего слушателя для вызова обновления сообщения через runLater, похоже, ломает проблему многопоточности. Да, я ожидаю, что это произойдет не сразу, но будет очень близко к немедленному и достаточно хорошим. Я понимаю, что JavaFX требует, чтобы вы не связывались со значениями / узлами потоков приложения и т.д. и т.д. графа сцены, но это довольно сложная область библиотеки JavaFX.

Вот слушатель, который работал у меня

// Get new DSS session active
    dss = new eol_server();

    dss.serverMessagesProperty.addListener(new ChangeListener<Object>() {
        @Override
        public void changed (ObservableValue<?> observable, Object oldValue, Object newValue) {
            Platform.runLater(() -> lbl_dssMessage.setText(newValue.toString()));
        }
    });
}

Рад за дальнейшее обсуждение того, почему это работает, когда другие варианты не работают, также открыты для любых других более элегантных предложений.

Ответ принят как подходящий

Прочтите приведенный ниже абзац из документации Узел JavaFX.

Node objects may be constructed and modified on any thread as long they are not yet attached to a Scene in a Window that is showing. An application must attach nodes to such a Scene or modify them on the JavaFX Application Thread.

Правильный и более функциональный способ решения вашей проблемы -

dss.serverMessagesProperty.addListener((observable, oldValue, newValue) -> Platform.runLater(() -> lbl_dssMessage.setText(newValue));

Другие вопросы по теме