【问题标题】:Scene Builder - Jar Import Issue场景生成器 - Jar 导入问题
【发布时间】:2018-11-06 20:13:38
【问题描述】:

我已经问了很多关于 Scene Builder 的问题,以至于我开始觉得我可能会对某些人产生轻微的烦恼。但现在另一个问题暴露了出来。我之前发布了this 关于将嵌套自定义节点导入场景生成器的问题。我的穿着闪亮盔甲的骑士过来帮我解决了这个问题。现在我有一个新问题。症状完全相同,但原因似乎不同。同样,我不知道如何对这个问题进行错误测试(如果有人教我怎么做,我会很高兴。不幸的是,我不完全理解最后一个答案的错误测试方法。)但它似乎无处不在。

所以问题是,就像以前一样,当我尝试导入包含自定义节点的 jar 文件时,最外层容器内的其他嵌套节点不会被导入到 Scene Builder 中。上次解决这个问题是通过添加

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

在加载 fxml 之前到我的 java 控制器代码,但这一次并没有解决它。 Here 是所有源代码。老实说,这个问题可能是我忽略的一些非常愚蠢的问题,如果是这种情况,我很抱歉。

感谢大家的帮助!

编辑:我应该说所有的罐子都可以自己运行。它们根本不能很好地与 Scene Builder 配合使用。

编辑 2: 正如 cmets 中所指出的,我应该尝试让问题更容易理解,对此感到抱歉。所以这里是结构。最外层的组件就是我所说的 NumberSlider。这包含另外两个自定义组件 NumberField 和 InfoIcon(见下图)。内部组件是进口的,外部不是。 NumberSlider 的结构基本上是一个滑块,它的 valueProperty 绑定到 NumberField 的 valueProperty。 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 的其余部分只是其各种属性的 getter 和 setter。我不相信更改监听器有问题,因为它们在我的 IDE 运行时都可以正常工作。

编辑 3:请参阅下面的答案以获得很好的解释。我只想在我的源代码中添加,NumberSlider 的所有属性都需要 getter 和 setter,即使是从 NumberField 继承的那些。否则它将无法与 Scene Builder 很好地配合。

【问题讨论】:

  • 现在没有显示哪个组件?如果您发布一些代码(不是全部)会更好。不要指望人们会潜入您的存储库。
  • @JoséPereda 当然你是对的。我添加了一个编辑,更详细地解释了(可能)有问题的区域。抱歉,我的问题很草率。

标签: javafx jar custom-controls scenebuilder


【解决方案1】:

有一个简单的修复方法可以让您的嵌套控件正常工作并被 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 默认值

那么,当您从 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);

通过此更改,构建您的控件和 jar,然后尝试再次导入它,现在您将在 Scene Builder 中看到这三个控件。

另请注意,控件的预览将反映这些新的默认值。

【讨论】:

  • 哦,好吧。这很有意义。再一次感谢你。我觉得在 Scene Builder 方面我还有很多东西要学。不幸的是,这不是很宽容。
  • 请注意,它并非始终关于 Scene Builder...您的控件通常必须更加健壮,因为 SB 只是另一个尝试使用它们的 JavaFX 应用程序...
  • 嗯好吧,我之前只为自己写过代码。我想像这样集成 Scene Builder 需要更多的思考。顺便说一句,你给出了非常好的答案。
猜你喜欢
  • 2014-07-23
  • 2016-08-24
  • 2015-06-10
  • 1970-01-01
  • 2017-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
相关资源
最近更新 更多