Многопоточный пользовательский интерфейс JavaFX - PullRequest
0 голосов
/ 13 октября 2018

У меня есть две проблемы многопоточности, которые переплетаются.

У меня есть SplitPane в настольном приложении JavaFX с использованием весенней загрузки.Слева TreeView, справа TabPane.В начале разделитель SplitPane находится на правом краю, скрывая панель TabPane.Когда пользователь выбирает элемент в дереве, две вещи должны происходить параллельно:

Сначала, в зависимости от выбора, создается около 10 вкладок.Вкладки различаются в зависимости от выбранного объекта.Каждая вкладка показывает подробные данные, связанные с выбранным объектом.Большинство вкладок содержат диаграммы, а также текст.

Во-вторых, так как настройка вкладок занимает несколько секунд - данные должны быть извлечены из БД - идея состояла в том, чтобы медленно «свернуть» разделитель TabPane влево, скрывая дерево.Это создает у пользователя впечатление, что приложение все еще работает, и делает переход более мягким.Мне не нравится ждать, ждать, .. взрыв!

Одна проблема в том, что временная шкала (см. Ниже), которую я использую, заикается, и я не могу заставить ее работать параллельно параллельно для настройки вкладок.

Создание вкладок выполняется в отдельной задаче, и каждый создатель вкладок использует Platform.runLater().Вторая проблема в том, что я не уверен, является ли это лучшим способом кодирования этого.Я имею в виду, что почти все вкладки скрыты верхней, но все вкладки создаются одна за другой в потоке приложения.

Другими словами, псевдокод будет выглядеть примерно так:

KeyValue keyValue = new KeyValue(splitPane.getDividers().get(0).positionProperty(), 0.1);
Timeline timeline = new Timeline(new KeyFrame(Duration.millis(300), keyValue));
timeline.play();

Task task = new Task<Void>() {
    @Override public Void call() {
       Platform.runLater(()-> {
           createTabA();
       }

       ..

       Platform.runLater(()-> {
           createTabZ();
       }

       return null;
    }
};
Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();

Я также изменил порядок, имея временную шкалу после запуска Thread.Это выглядит по-другому, но все же не так, как ожидалось.

Как я могу улучшить свою многопоточную логику и избавиться от бикинга?

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

Заранее спасибо!

1 Ответ

0 голосов
/ 13 октября 2018

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

Runnable с, переданные Platform.runLater, не должны содержать никаких длительных операций.

Вместо этого создайте вкладки в фоновом потоке но не прикрепляйте их к сцене из этого потока. (Создание (части) сцены в фоновом потоке не является проблемой, если вы не изменяете то, чтоприсоединен к Scene.)

Если вы можете добавить сразу все вкладки в конце задания, рассмотрите возможность использования Task<List<Tab>> и возврата вкладок.

Task<List<Tab>> task = new Task<List<Tab>>() {
    @Override public List<Tab> call() {
       List<Tab> result = new ArrayList<>(1 + 'Z' - 'A');

       for (char c = 'A'; c <= 'Z'; c++) {
           result.add(createTab(c));
       }

       return result;
    }
};
task.setOnSucceeded(evt -> tabPane.getTabs().addAll(task.getValue()));
...

В противном случае создайте Tab s в фоновом потоке, но добавьте их к TabPane в потоке приложения:

Task<Void> task = new Task<Void>() {
    @Override public Void call() {
       for (char c = 'A'; c <= 'Z'; c++) {
           final Tab tab = createTab(c);
           Platform.runLater(() -> tabPane.getTabs().add(tab));
       }

       return null;
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...