Scene Builder - проблема импорта банок - PullRequest
0 голосов
/ 28 мая 2018

Я задал так много вопросов о Scene Builder, что начинаю чувствовать, что я могу слегка раздражать некоторых людей.Но теперь появилась другая проблема.Ранее я опубликовал этот вопрос об импорте вложенных пользовательских узлов в Scene Builder.Мой рыцарь в сияющих доспехах помог мне решить эту проблему.Теперь у меня появилась новая проблема.Симптомы точно такие же, но причина, кажется, другая.Опять же, я не знаю, как тестировать эту проблему (я был бы очень рад, если бы кто-то научил меня, как. Я, к сожалению, не совсем понимаю методы тестирования ошибок в последнем ответе), но, похоже, это произошло из ниоткуда.

Таким образом, проблема, как и прежде, заключается в том, что при попытке импортировать файл JAR, содержащий пользовательский узел с другими вложенными узлами внутри самого внешнего контейнера, не импортируется в Scene Builder.В прошлый раз это было решено добавлением

fxmlLoader.setClassLoader(getClass().getClassLoader());

в мой код контроллера Java перед загрузкой fxml, но на этот раз это не исправлено. Здесь - это весь исходный код.Чтобы быть честным с вами, проблема, вероятно, довольно глупа, что я упустил из виду, и если это так, я заранее извиняюсь.

Спасибо за помощь!

РЕДАКТИРОВАТЬ: Должен сказать, что все банки работают нормально.Они просто не очень хорошо играют в Scene Builder.

РЕДАКТИРОВАТЬ 2: Как указано в комментариях, я должен попытаться сделать проблему немного более доступной, извините за это.Итак, вот структура.Внешний компонент - это то, что я называю NumberSlider.Он содержит два других пользовательских компонента - NumberField и InfoIcon (см. Изображение ниже).Внутренние компоненты импортируются нормально, а внешние нет.Структура NumberSlider - это, по сути, слайдер, у которого значение valueProperty привязано к valueProperty объекта NumberField.NumberField - это, по сути, TextField, который позволяет пользователю вводить текст для изменения его valueProperty, а если valueProperty изменяет текст, изменяется в соответствии с этим.Я считаю, что проблема заключается в создании переменной ползунка, поскольку этот компонент не импортирует должным образом.Это конструктор.

//Properties
private final BooleanProperty logarithmic;
private final BooleanProperty ticks;

//Variables
@SuppressWarnings("unused")
private boolean lock = false;

//Structural Elements
@FXML private Label label;
@FXML private Slider slider;
@FXML public NumberField field;
@FXML private InfoIcon info;

public NumberSlider(@NamedArg("logarithmic") boolean logarithmic, @NamedArg("ticks") boolean ticks, 
            @NamedArg("intSlider") boolean intSlider, @NamedArg("value") double value, 
            @NamedArg("min") double min, @NamedArg("max") double max) {
    this.logarithmic = new SimpleBooleanProperty(this, "logarithmic", logarithmic);
    this.ticks = new SimpleBooleanProperty(this, "ticks", ticks);

    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("NumberSlider.fxml"));
    fxmlLoader.setRoot(this);
    fxmlLoader.setController(this);
    fxmlLoader.setClassLoader(getClass().getClassLoader());

    try {
        fxmlLoader.load();
    } catch (IOException exception) {
        throw new RuntimeException(exception);
    }

    field.reconfigureLogic(value, min, max, intSlider);

    //An awfully long code block that basically binds the two properties with change listeners in different ways depending on the input arguments.
}    

Остальная часть NumberSlider - это только методы получения и установки для его различных свойств.Я не верю, что есть проблема со списками изменений, так как все они работают нормально при работе из моей IDE.

РЕДАКТИРОВАТЬ 3: См. Ответ ниже для хорошего объяснения.Я просто хочу добавить, что в моем исходном коде NumberSlider нужны геттеры и сеттеры для всех его свойств, даже тех, которые унаследованы от NumberField.В противном случае он не будет хорошо работать с Scene Builder.

1 Ответ

0 голосов
/ 29 мая 2018

Существует простое решение, чтобы ваш вложенный элемент управления работал и был импортирован Scene Builder.

Проблема связана с непустым конструктором, который вы использовали для элементов управления.

ХотяNumberField работает (как его можно импортировать) с этим конструктором:

public NumberField(@NamedArg("intField") boolean intField, @NamedArg("value") double value, @NamedArg("min") double min, 
        @NamedArg("max") double max);

Внешний элемент управления NumberSlider, который использует элемент управления NumberField, и имеет этот конструктор:

public NumberSlider(@NamedArg("logarithmic") boolean logarithmic, @NamedArg("ticks") boolean ticks, 
            @NamedArg("intSlider") boolean intSlider, @NamedArg("value") double value, 
            @NamedArg("min") double min, @NamedArg("max") double max);

не удается импортировать.

В этот раз это не проблема загрузчика классов, а проблема, связанная с аргументами и соответствующими значениями по умолчанию.

@ NamedArg defaultзначения

Итак, каковы значения по умолчанию для этих аргументов при создании и экземпляра элемента управления из Scene Builder?

  • Для логических значений: false
  • Для целых чисел: 0
  • Для двойных чисел: 0.0

Это означаетчто при создании элемента управления вы вызываете:

final NumberSlider slider = new NumberSlider(false, false, false, 0, 0, 0);

И если вы попробуете это в своем проекте, он потерпит неудачу !!

Caused by: java.lang.IllegalArgumentException: MajorTickUnit cannot be less than or equal to 0.
at javafx.scene.control.Slider.setMajorTickUnit(Slider.java:397)
at com.mycompany.numberslider.NumberSlider.<init>(NumberSlider.java:118)
at com.mycompany.numberslider.NumberSliderApp.start(NumberSliderApp.java:20)

Из-за этого исключения произойдет сбой элемента управлениячтобы быть импортированным из Scene Builder.

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

  • Измените код, чтобы разрешить эти значения по умолчанию
  • Измените значения по умолчанию для namedArgs

Я объясню, как сделать последнее, которое будет моим предпочтительным.

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

@ NamedArg defaultValue () метод

Если вы проверите аннотацию NamedArg:

@Retention(RUNTIME)
@Target(PARAMETER)
public @interface NamedArg {
    /**
     * The name of the annotated argument.
     * @return the name of the annotated argument
     */
    public String value();

    /**
     * The default value of the annotated argument.
     * @return the default value of the annotated argument
     */
    public String defaultValue() default "";
}

, есть два метода, и обычно мы используем только один: value().

Но мы могли бы использоватьи измените значение "" по умолчанию, например:

public NumberSlider(@NamedArg(value="logarithmic", defaultValue="false") boolean logarithmic, 
            @NamedArg(value="ticks", defaultValue="false") boolean ticks, 
            @NamedArg(value="intSlider", defaultValue="false") boolean intSlider, 
            @NamedArg(value="value", defaultValue="50") double value, 
            @NamedArg(value="min", defaultValue="0") double min, 
            @NamedArg(value="max", defaultValue="100") double max);

С этим изменением соберите элементы управления и банку и попробуйте импортировать их снова, теперь вы увидите три элемента управления с помощью Scene Builder.

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

Importing nested controls

...