Можете ли вы пройти через переменную Insets в FXML? - PullRequest
0 голосов
/ 04 октября 2019

Я делаю некоторую работу, которая требует, чтобы у меня были разные значения для элементов на основе скалярного значения. У меня есть работа, чтобы придумать скалярное значение в классе с именем Sizer с помощью метода getScalar (), который возвращает значение типа double. Ниже частичный 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 и т. Д., Он будет работать во время выполнения, и у меня появится диалоговое окно. Настройка prefWidth с использованием SCALAR, кажется, работает нормально, но когда я добавляю ссылку на значения 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)

MyПонимание

Вы можете создавать эти определенные объекты через блоки определения и затем ссылаться на них в других атрибутах посредством привязки выражений и разрешения переменных, но почему-то я не могу сделать это с помощью Insets. Единственное, что я обнаружил, это то, что у prefWidth есть установщик, принимающий удвоение, тогда как у 'left' или других позиций со вставками есть геттеры. Я подумал, что, возможно, у него могут быть проблемы с привязкой к объекту, который, похоже, не имеет установщика.

Любая помощь будет принята с благодарностью, так как я не настолько осведомлен о 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
}

1 Ответ

2 голосов
/ 07 октября 2019

Синтаксис ${} используется для создания привязки выражения , которая, в свою очередь, используется для привязки 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 также поддерживает scripting :

Тег <fx:script> позволяет вызывающей стороне импортировать код сценария в код JavaScript или встраивать его в FXMLфайл. Можно использовать любой язык сценариев JVM, включая JavaScript, Groovy и Clojure. Код сценария часто используется для определения обработчиков событий непосредственно в разметке или в связанном исходном файле, поскольку обработчики событий часто могут быть написаны более кратко на более свободно типизированных языках сценариев, чем на статически типизированном языке, таком как Java.

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


Не имеет отношения к вашей проблеме, но вы, похоже, используете классы AWT для того, чтобы получитьразмеры экрана. JavaFX предоставляет собственный API для этого: javafx.stage.Screen. Вы можете использовать:

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

Чтобы получить размеры основного экрана. Чтобы получить размеры всего экрана, а не только визуальной области, используйте getBounds() вместо getVisualBounds().

...