JavaFX: настраиваемая оболочка таблицы с настраиваемым заголовком таблицы

#java #javafx #tableview #javafx-8

#java #javafx #просмотр таблицы #javafx-8

Вопрос:

Я работаю над CustomTableViewSkin, где я передаю некоторые аргументы конфигурации для настройки моего скина в зависимости от переданного параметра. Одна из возможностей конфигурации связана с TableHeaderRow тем, который инициализируется в методе инициализации ableHeaderRow , который вызывается в конструкторе. Поскольку я вынужден вызывать суперконструктор, мои параметры конфигурации еще не инициализированы, и даже если я @Override createTableHeaderRow() , это действительно не работает так, как мне нужно.

Я нашел решение или, лучше сказать, обходной путь, но я не уверен, насколько безопасно его использовать.

Вот простой код, который показывает, что я имею в виду.

 public class MyTableSkin<T> extends TableViewSkin<T> {

    private Set<Param> params;

    public MyTableSkin(TableView<T> tableView, Set<Param> params) {
        super(tableView);
        this.params = params;
    }

    @Override
    protected TableHeaderRow createTableHeaderRow() {
        // NPE at params since this method is called in super constructor there params are not initialized.
        if (params.contains(Param.TABLE_HEADER)) {
            return new MyTableHeaderRow(this);
        }
        return super.createTableHeaderRow();
    }

    private static class MyTableHeaderRow extends TableHeaderRow {

        public MyTableHeaderRow(TableViewSkinBase skin) {
            super(skin);
        }
    }

    public enum Param {
        TABLE_HEADER
    }
}
  

После небольшого эксперимента я нашел этот способ:

 public class MyTableSkin<T> extends TableViewSkin<T> {

    private Set<Param> params;

    public MyTableSkin(TableView<T> tableView, Set<Param> params) {
        super(tableView);
        this.params = params;
        getChildren().clear(); // if I didn't do this an exception is thrown
        // calling init again to "reinitialize" the skin.
        super.init(tableView); // how safe is this? :)
    }

    @Override
    protected TableHeaderRow createTableHeaderRow() {
        // Now it enters the if after the second init call, after params are initialized.
        if (params != null amp;amp; params.contains(Param.TABLE_HEADER)) {
            return new MyTableHeaderRow(this);
        }
        return super.createTableHeaderRow();
    }

    private static class MyTableHeaderRow extends TableHeaderRow {

        public MyTableHeaderRow(TableViewSkinBase skin) {
            super(skin);
        }
    }

    public enum Param {
        TABLE_HEADER
    }
}
  

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

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

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

Комментарии:

1. совсем не безопасно … не вызывайте методы инициализации более одного раза, вы вызываете проблемы 😉 Вместо этого задайте параметры для таблицы — скиннируемый доступен «очень рано», поскольку он установлен в конструкторе SkinBase

2. Я думал, что это не так: D Но поскольку у меня не было никакой замены, и это был единственный «рабочий», который я использовал. Тем не менее, я переписываю его, чтобы иметь это в skinnable и я попробую.

3. Это работает нормально, если вы хотите, вы можете опубликовать свое предложение в качестве ответа, чтобы я мог вознаградить его 😉