a.disableProperty (). bind (b.visibleProperty ()) вызывает неправильный рендеринг элементов в Java FX 10 - PullRequest
0 голосов
/ 11 июня 2018

Это регрессия в Java 10, дальнейшие обновления см. В отчете об ошибках: JDK-8204949


Рассмотрим следующий код Java FX, с которого начинается binvisible: a.disableProperty().bind(b.visibleProperty())

Если приложение, использующее такой код, выполняется на Java 10 VM, то с первого раза b становится видимым, a всегда будет отображаться так, как если бы оно было отключено.

Конечно, в то время как a на самом деле не отключен (несмотря на то, что отображается с серым наложением), вы все равно можете взаимодействовать с этим элементом.Например, вы можете редактировать текст в элементах управления вводом, нажимать кнопки / ссылки и т. Д., События будут правильно распространяться и т. Д.

Если приложение работает на виртуальной машине Java 8, оно работает должным образом.

В настоящее время у меня нет EOS Java 9, поэтому я тестировал только на:

  • Windows 10 x64 Pro 1709 и 1803
  • Java 8u172 x64 (как на JDK, так и на JDKJRE явно нацелены на исполняемые файлы)
  • Java 10u1 x64 (как на JDK, так и на JRE явно нацелены на исполняемые файлы)

Пример того, как это выглядит в Java 10: Invalid render example in Java 10

Как это выглядит при первом запуске, до того как b имел шанс стать видимым: enter image description here


A SSCCE (обязателен для некоторой неясной проблемы; a будет propertyProvider, b будет invalidRenderField и invalidRenderButton):

package application;

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Accordion;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.VBox;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        System.out.println("Executing start(Stage) in " + Thread.currentThread().getName());
        try {
            TextField invalidRenderField = new TextField();
            Button invalidRenderButton = new Button("Click to reproduce");
            Label propertyProvider = new Label();
            propertyProvider.setVisible(false);
            VBox invalidRenderParent = new VBox(invalidRenderField, invalidRenderButton, propertyProvider);
            TitledPane invalidRenderPane = new TitledPane("Incorrectly rendered elements", invalidRenderParent);
            Accordion root = new Accordion(invalidRenderPane);
            root.setExpandedPane(invalidRenderPane);

            invalidRenderField.disableProperty().bind(propertyProvider.visibleProperty());
            invalidRenderButton.disableProperty().bind(propertyProvider.visibleProperty());
            invalidRenderButton.setOnAction(e -> {
                System.out.println("Executing 1st onAction(ActionEvent) in " + Thread.currentThread().getName());

                propertyProvider.setVisible(true);
                propertyProvider.setText("At this point of time you cannot modify the field or click the button");

                Task<Void> task = new Task<>() {
                    @Override
                    protected Void call() throws Exception {
                        System.out.println("Executing non-JFX code in " + Thread.currentThread().getName());
                        Thread.sleep(3_000L);
                        return null;
                    }
                };
                task.setOnSucceeded(e2 -> {
                    System.out.println("Executing onSuccess(WorkerStateEvent) in " + Thread.currentThread().getName());

                    propertyProvider.setVisible(false);

                    Label infoLabel = new Label("Either click the button below or just select the previous pane within the accordion");
                    Button closePlaceholderButton = new Button("View failure");
                    VBox placeholder = new VBox(infoLabel, closePlaceholderButton);
                    TitledPane placeholderPane = new TitledPane("Placeholder", placeholder);

                    closePlaceholderButton.setOnAction(e3 -> {
                        System.out.println("Executing 2nd onAction(ActionEvent) in " + Thread.currentThread().getName());
                        root.getPanes().remove(placeholderPane);
                        root.setExpandedPane(invalidRenderPane);
                    });

                    root.getPanes().add(1, placeholderPane);
                    root.setExpandedPane(placeholderPane);
                });
                new Thread(task, "WhateverThread").start();
            });

            Scene scene = new Scene(root, 800, 450);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.println("Executing main(String[]) in " + Thread.currentThread().getName());
        launch(args);
    }
}

SSCCE вывод после однократного нажатия «Нажмите для воспроизведения»:

Executing main(String[]) in main
Executing start(Stage) in JavaFX Application Thread
Executing 1st onAction(ActionEvent) in JavaFX Application Thread
Executing non-JFX code in WhateverThread
Executing onSuccess(WorkerStateEvent) in JavaFX Application Thread

В точности, как и ожидалось, код JavaFX выполняется в указанном потоке.


вопрос в том, делаю ли я что-то не так и / или упускаю что-то очевидное?Кажется, я не могу найти что-то «неправильное» в этом коде, он звучит нормально, но это не работает.Это ошибка (и мне нужен lrn2search)?

В общем, любые предложения по обходу приветствуются.Мне нужен этот код (или эквивалент через обходной путь) для работы на Java 10, никаких оправданий.

1 Ответ

0 голосов
/ 12 июня 2018

Во-первых, я просто хотел бы подтвердить, что я наблюдаю то же поведение, что и у вас.

  • Windows 10 x64 Home
  • Java 1.8.0_172 x64 - Работает какожидается
  • Java 10.0.1 x64 - Сбой (отображается как отключенный, но фактически не отключен)

Это ошибка, и вы должны сообщить об этом как таковой.


Возможный обходной путь

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

node.disableProperty().addListener((observable, oldValue, newValue) -> {
    if (!newValue) { // if no longer disabled
        node.applyCss();
    }
});

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

Edit

Я обнаружил, что порядок, когда вы делаете propertyProvider невидимым, влияет на обходной путьЯ предоставил.Если вы сделаете propertyProvider невидимым после , вы отобразите новый TitledPane, а затем, когда вы вернетесь к другому TitledPane, TextField и Button по-прежнему будут отключены, если они не,Пока что не нашли обходного пути.

...