我正在做一些工作,要求我根据标量值对元素具有不同的值。我的工作是在名为Sizer的类中提出标量值,并使用一种名为getScalar()的方法来返回双精度值。下面是我现在拥有的部分FXML。

<VBox id="mainWindow" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller">
   <fx:define>
      <Sizer fx:id="SCALAR" fx:factory="getScalar"/>
   </fx:define>
   <children>
     <HBox alignment="CENTER_LEFT">
        <children>
           <Label fx:id="titleLabel" text="Label" HBox.hgrow="ALWAYS" />
           <HBox fx:id="titleBar" HBox.hgrow="ALWAYS" />
        </children>
        <padding>
           <!-- This part DOESN'T work at runtime -->
           <Insets left="${SCALAR * 10.0}" right="${SCALAR * 10.0}" top="${SCALAR * 5.0}" />
        </padding>
     </HBox>
     <!-- This part DOES work at runtime -->
     <Separator prefWidth="${SCALAR * 200.0}" />
  </children>
</Vbox>


在这段代码中,如果我取出Insets引用并仅将这些值设置为10.0、5.0等,则它在运行时有效并且出现我的对话框。使用SCALAR的'prefWidth'设置似乎工作正常,但是当我添加对Insets值的引用时,它会抛出错误并指向带有Insets的行。

javafx.fxml.LoadException: Cannot bind to untyped object.

at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2621)
at javafx.fxml.FXMLLoader.access$100(FXMLLoader.java:105)
at javafx.fxml.FXMLLoader$Element.processPropertyAttribute(FXMLLoader.java:306)
at javafx.fxml.FXMLLoader$Element.processInstancePropertyAttributes(FXMLLoader.java:242)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:757)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)


我的理解

您可以通过定义块创建这些定义的对象,然后通过表达式绑定和变量解析在其他属性中引用它们,但是以某种方式,我无法使用Insets进行此操作。我发现的唯一一件事是,“ prefWidth”具有一个双精度的二传手,而“ Insets”的“ left”或其他位置则具有getter。我以为可能绑定到似乎没有设置器的对象时可能会遇到问题。

因为我对FXML的了解不多,所以可以提供任何帮助,并且我来自JavaFX界,这比这容易得多。

编辑
以下是Sizer类的内容

public static Toolkit getToolKit() {
    return Toolkit.getDefaultToolkit();
}
public static Dimension getScreenSize() {
    return getToolKit().getScreenSize();
}
public static int getPercentOfHeight(double percent) {
    return (int)(getScreenSize().getHeight() * percent / 100.0);
}
public static int getPercentOfWidth(double percent) {
    return (int)(getScreenSize().getWidth() * percent / 100.0);
}
public static double getScaleFactor() {
    if ((int) getScreenSize().getHeight() > 1800) return 2.0;    //4K
    else if ((int)getScreenSize().getHeight() > 1260) return 1.33; //1440p
    else if ((int)getScreenSize().getHeight() > 900) return 1.0;     //1080p
    else return 0.667;                                   //720p
}

最佳答案

${}语法用于创建expression binding,而该scripting又用于将Property绑定到生成的ObservableValue。代码的问题是Insets不会将其状态显示为Property实例。最重要的是,Insets类是不可变的,这意味着状态是通过构造函数之一设置的,并且两个构造函数都仅接受double参数。您不能传递表达式绑定的结果,因为double并且FXMLLoader不会在创建Insets实例时“巧妙地”提取当前值。

据我了解,您想将Insets的每一边乘以一个double值,这只需要发生一次(即,您不需要随着时间的推移更新值)。在这种情况下,一种解决方案是将Insets子类化,并为标量参数的每个构造函数“添加参数”。

package com.example;

import javafx.beans.NamedArg;
import javafx.geometry.Insets;

public class ScaledInsets extends Insets {

    public ScaledInsets(@NamedArg(value = "scale", defaultValue = "1") double scale,
                        @NamedArg("top") double top, @NamedArg("right") right,
                        @NamedArg("bottom") double bottom, @NamedArg("left") double left) {
        super(scale * top, scale * right, scale * bottom, scale * left);
    }

    public ScaledInsets(@NamedArg(value = "scale", defaultValue = "1") double scale,
                        @NamedArg("topRightBottomLeft") double topRightBottomLeft) {
        super(scale * topRightBottomLeft);
    }

}


这将使您可以在FXML文件中使用以下内容:

<?xml version="1.0" encoding="UTF-8"?>

<?import com.example.ScaledInsets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.StackPane?>

<StackPane xmlns="http://javafx.com/javafx/" xmlns:fx="http://javafx.com/fxml">
    <fx:define>
        <Sizer fx:id="SCALAR" fx:factory="getScaleFactor"/>
    </fx:define>
    <padding>
        <ScaledInsets scale="$SCALAR" top="5" left="10" right="10"/>
    </padding>
    <Label text="Hello, World!"/>
</StackPane>




请注意,FXML还支持<fx:script>


  javafx.stage.Screen标记允许调用者将脚本代码导入FXML文件或将脚本嵌入FXML文件中。可以使用任何JVM脚本语言,包括JavaScript,Groovy和Clojure等。脚本代码通常用于直接在标记或关联的源文件中定义事件处理程序,因为与使用静态类型的语言(例如Java)相比,事件处理程序通常可以使用更为宽松的脚本语言来更简洁地编写。


我以前从未在FXML中使用脚本,并且现在不知道如何在示例中使用它。可以说,您可以弄乱它,但是我不知道脚本编写是否是可行的解决方案。



与您的问题无关,但是您似乎正在使用AWT类来获取屏幕尺寸。 JavaFX为此提供了自己的API:。您可以使用:

Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();


获取主屏幕的尺寸。要获取整个屏幕的尺寸,而不仅仅是视觉区域,请使用getBounds()而不是getVisualBounds()

关于java - 您可以将变量传递给FXML中的Insets吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58239870/

10-11 10:43