JavaFX java.lang.IllegalArgumentException: невозможно установить в поле javafx.scene.control.Label sample.Controller.location значение java.net.URL - PullRequest
4 голосов
/ 22 мая 2019

У моего приложения JavaFX есть Метка с идентификатором fx: location. Это определено в файле FXML. Когда я пытаюсь запустить приложение, я получаю следующую ошибку:

java.lang.IllegalArgumentException: невозможно установить для поля javafx.scene.control.Label sample.Controller.location значение java.net.URL

Я использую JDK 12 с JavaFX 11.0.2.

Я видел здесь другие ответы на SO, которые говорят, что это вызвано конфликтующим типом для location Label. Например, он может быть объявлен как метка в файле FXML, но в коде Java это нечто другое (в данном случае, java.net.URL). Однако, как видно из приведенного ниже кода, я нигде не использую класс URL.

Изменение fx: id на что-то другое (например, loc) устраняет ошибку, поэтому location должно быть "волшебным" именем.

Что вызывает это?

sample.fxml

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

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.Pane?>

<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
   <children>
      <Label fx:id="location" layoutX="133.0" layoutY="146.0" text="Output" />
   </children>
</Pane>

Main.java

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application
{

    @Override
    public void start(Stage primaryStage) throws Exception
    {
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 400, 275));
        primaryStage.show();
    }


    public static void main(String[] args)
    {
        launch(args);
    }
}

Controller.java

package sample;

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class Controller
{
    @FXML
    Label location;

}

module-info.java

module MyTest
{
    requires javafx.controls;
    requires javafx.fxml;
    opens sample;
}

1 Ответ

5 голосов
/ 22 мая 2019

Это относительно легко узнать, осмотрев FXMLLoader:

/**
 * A key for location URL in namespace map.
 * @see #getNamespace()
 * @since JavaFX 2.2
 */
public static final String LOCATION_KEY = "location";
/**
 * A key for ResourceBundle in namespace map.
 * @see #getNamespace()
 * @since JavaFX 2.2
 */
public static final String RESOURCES_KEY = "resources";

private URL location;
private ResourceBundle resources;

private <T> T loadImpl(InputStream inputStream,
                       Class<?> callerClass) throws IOException {
    ...
    namespace.put(LOCATION_KEY, location);
    namespace.put(RESOURCES_KEY, resources);
    ...
}

В основном это означает, что location (например, resources, controller и Controller) является зарезервированным ключевым словом .

Эти ключевые слова добавляются в namespace (наблюдаемая карта: ObservableMap<String, Object> namespace), а location - это URL-адрес файла FXML, что-то вроде:

namespace.put("location", "file:/path/to/your/FXML/file");

Позже различные теги fx:id вашего файла FXML оцениваются и добавляются в одно и то же пространство имен:

private void processValue() throws LoadException {
    ...
    if (fx_id != null) {
        namespace.put(fx_id, value);
        injectFields(fx_id, value);
    }
    ...
}

В этом случае, если ваш fx:id равен "location", вы будете делать что-то вроде:

namespace.put("location", Label@12dafafa);

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

Позже, когда FXMLLoader пытается внедрить это местоположение:

injectFields(LOCATION_KEY, location);

исключение происходит, поскольку Label, полученное картой от ключа "location", может быть установлено в поле URL:

Can not set javafx.scene.control.Label field org.openjfx.FXMLController.location to java.net.URL

Хотя это не задокументировано, это означает, что вы не можете использовать "location" (или "resources", "controller") в качестве значения для тега fx:id, поскольку он будет конфликтовать с этими ключевыми словами.

...