JavaFX делает что-то после активации прослушивателя свойств

У меня есть этот код, который сохраняет размер ширины TableView's TableColumn в качестве предпочтения:

column.widthProperty().addListener((obs, oldWidth, newWidth) -> {
            setTablePreference().saveColumnWidthSetting(newWidth.doubleValue(), column.getId().concat(columnWidthSettingsCommons.toString()));
        });

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

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

Я думал об использовании отдельного потока, но он создает сотни потоков, а это далеко не то, чего я пытаюсь достичь (это производительность):

column.widthProperty().addListener((obs, oldWidth, newWidth) -> {
            new Thread(new Task<>() {
                @Override
                protected Object call() {
                    setTablePreference().saveColumnWidthSetting(newWidth.doubleValue(), column.getId().concat(columnWidthSettingsCommons.toString()));
                    return null;
                }
            }).start();
        });

Итак, мой вопрос: есть ли способ запустить код после того, как прослушиватель перестал прослушивать новые значения?

Также рассмотрите java.util.prefs.Preferences , рассмотренную здесь.

trashgod 26.05.2024 23:18

Создайте Минимальный воспроизводимый пример.

SedJ601 26.05.2024 23:29

Вы можете использовать PauseTransition, чтобы сохранить изменения только в том случае, если после некоторой паузы дальнейших изменений не произошло. Но, как описано в ответе ниже, это просто не способ сохранить изменения предпочтений; вообще нет необходимости сохранять их только потому, что пользователь их изменил.

James_D 27.05.2024 00:03

В настройках «Обычное завершение работы виртуальной машины Java не приведет к потере ожидающих обновлений…»

trashgod 27.05.2024 00:18

@trashgod не может использовать эту библиотеку, как я могу гарантировать, что пользователь, входящий в систему с другого компьютера, будет иметь там свои настройки? Мне пришлось разработать собственное решение для этого

FARS 27.05.2024 05:21

@ SedJ601 SedJ601 Я не понимаю, насколько полезным может быть больше MRE, чем указано. Не могли бы вы пояснить свой комментарий?

FARS 27.05.2024 05:22

@James_D очень хорошее предложение с PauseTransition, возможно, это то, что я искал. Что касается сохранения ширины столбца, на самом деле это очень актуально с точки зрения качества обслуживания клиентов. Простой сценарий: у кого-то есть старый 13-дюймовый ноутбук, поэтому доступная площадь экрана становится потенциальной проблемой. Каждый раз, когда пользователь загружает tableView, ему всегда приходится увеличивать/уменьшать ширину таблицы, чтобы сделать информацию более «читабельной» (что потенциально может привести к тому, что пользователь просто откажется от платформы). Было бы здорово сделать это один раз, не так ли?!

FARS 27.05.2024 05:29

@James_D эта функция будет доступна в следующей версии (доступной к концу следующей недели), приглашаю вас ее проверить! jdeploy.com/gh/FelipeAumannRS/Nume

FARS 27.05.2024 05:31

@FARS, похоже, ты прав.

SedJ601 27.05.2024 06:33

Ты не понял меня. Вопрос не в том, нужно ли сохранять ширину столбца. Вопрос в том, нужно ли сохранять его каждый раз, когда пользователь меняет его. Почему бы просто не сохранить его, когда пользователь закроет окно (или каким-то образом скроет таблицу)?

James_D 27.05.2024 13:09

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

James_D 27.05.2024 13:29
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
11
79
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Основное решение состоит в том, чтобы иметь в вашем приложении точки, которые сохраняют настройки (например, закрытие приложения) и позволяют запрашивать последние значения ширины столбцов. На самом деле это обычный поток управления, а не тот стиль внедрения управления/зависимостей, который вы используете. Вы все равно можете отделить настройки от TableView.

Схематично:

public class MyPrefsWriter {
    public final Map<String, Producer<String>> props = new LinkedHashMap<>():
    public void savePrefs() {
        props.forEach((k, v) -> savePreference(k, v.get());
    }
}

public class MyPrefsReader { ... }

// Init:
MyPrefsWriter myPrefs = new MyPrefsWriter();


// GUI constructions:
myPrefs.props.put("columnXWidth", () -> columnX.width.toString());
...

// On exit:
myPrefs.savePrefs();

Что касается TableView, вы можете получить всю ширину в одном фрагменте кода, это может быть лучше и компактнее (saveTableViewToPrefs, loadTableViewFromPrefs).

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

FARS 27.05.2024 05:36

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

FARS 27.05.2024 05:38

@FARS Общий совет в этом ответе — сохранять настройки в определенных точках потока вашего приложения. Одним из таких моментов (приведенных в качестве примера в этом ответе) является закрытие приложения. В вашем случае другим моментом будет закрытие «модуля». Что касается упомянутого вами недостатка, предпочтения обычно не считаются важными данными. Но если вы хотите обеспечить сохранение предпочтений пользователя практически в реальном времени, то подход с задержкой, описанный James_D, вероятно, подойдет вам лучше всего.

Slaw 27.05.2024 07:36

@Slaw Я согласен, я уже разрабатываю реализацию на основе его подхода.

FARS 27.05.2024 14:32
Ответ принят как подходящий

Следуя предложению @James_D, я разработал реализацию с использованием PauseTransition:

final PauseTransition columnWidthPropertyPauseTransition = new PauseTransition(Duration.seconds(0.5));
        column.widthProperty().addListener((obs, oldWidth, newWidth) -> {
            adjustNodePosition(tableView);

            if (columnWidthPropertyPauseTransition.getStatus() != Animation.Status.RUNNING)
                columnWidthPropertyPauseTransition.play();
            columnWidthPropertyPauseTransition.setOnFinished(e -> setTablePreference().saveColumnWidthSetting(newWidth.doubleValue(), column.getId().concat(columnWidthSettingsCommons.toString())));
        });

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