Não é possível importar componentes personalizados com fábricas de células personalizadas

StackOverflow https://stackoverflow.com//questions/24016229

Pergunta

No JavaFX 2.2, tenho tido problemas para importar componentes customizados que possuem uma fábrica de células customizada definida no FXML.Digamos que meu componente personalizado seja o seguinte

public class CustomComponent extends VBox{

public CustomComponent() {
    try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("CustomComponent.fxml"));
        loader.setRoot(this);
        loader.setController(this);
        loader.load();
    } catch (IOException e ){
        throw new RuntimeException(e);
    }
}

}

E o FXML correspondente é

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

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.VBox?>
<?import application.*?>
<?import application.TestFactory?>


<fx:root prefHeight="358.0" prefWidth="260.0" type="VBox" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
   <children>
      <TableView prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
        <columns>
          <TableColumn prefWidth="75.0" text="C1" >
            <cellFactory>
                <TestFactory />
            </cellFactory>
          </TableColumn>
          <TableColumn prefWidth="75.0" text="C2" >
          <cellFactory>
            <TestFactory />
          </cellFactory>
          </TableColumn>
        </columns>
         <columnResizePolicy>
            <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
         </columnResizePolicy>
      </TableView>
   </children>
</fx:root>

e TestFactory é definido como

public class TestFactory<S,T> implements Callback<TableColumn<S, T>, TableCell<S, T>>{

    @Override
    public TableCell<S, T> call(TableColumn<S, T> param) {
        return new TableCell<S,T>();
    }

}

E todos esses três arquivos estão no mesmo diretório/pacote src.

Quando eu juntei esses arquivos e tentei importar o jar para o scenebuilder, ele não encontrará CustomComponent.No entanto, se eu retirar a referência ao cellFactory & TestFactory, ele será importado perfeitamente.Olhando para a análise do jar, parece lançar uma ClassNotFoundException no TestFactory.

Not a Node: application/Main.class

Not a Node: application/TestFactory.class

Exception for: application/CustomComponent.class
javafx.fxml.LoadException: 
unknown path:2

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2617)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2595)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2425)
    at com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer.instantiateWithFXMLLoader(JarExplorer.java:105)
    at com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer.exploreEntry(JarExplorer.java:146)
    at com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer.explore(JarExplorer.java:65)
    at com.oracle.javafx.scenebuilder.kit.library.user.LibraryFolderWatcher.exploreAndUpdateLibrary(LibraryFolderWatcher.java:298)
    at com.oracle.javafx.scenebuilder.kit.library.user.LibraryFolderWatcher.runDiscovery(LibraryFolderWatcher.java:122)
    at com.oracle.javafx.scenebuilder.kit.library.user.LibraryFolderWatcher.run(LibraryFolderWatcher.java:88)
    at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.RuntimeException: javafx.fxml.LoadException: 
file:/C:/Users/bthomas/AppData/Roaming/Scene%20Builder/Library/testing.jar!/application/CustomComponent.fxml

    at application.CustomComponent.<init>(CustomComponent.java:17)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
    at java.lang.Class.newInstance(Class.java:433)
    at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51)
    at javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:1010)
    at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:740)
    at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2723)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
    ... 8 more
Caused by: javafx.fxml.LoadException: 
file:/C:/Users/bthomas/AppData/Roaming/Scene%20Builder/Library/testing.jar!/application/CustomComponent.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2617)
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2864)
    at javafx.fxml.FXMLLoader.processImport(FXMLLoader.java:2708)
    at javafx.fxml.FXMLLoader.processProcessingInstruction(FXMLLoader.java:2677)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2517)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
    at application.CustomComponent.<init>(CustomComponent.java:15)
    ... 18 more
Caused by: java.lang.ClassNotFoundException: application.TestFactory
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2932)
    at javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2921)
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2862)
    ... 24 more

Presumo que seja algum problema de caminho de classe com o construtor de cena, mas estou perdido.Alguém já encontrou esse problema antes ou sabe de uma solução?

Foi útil?

Solução

Parece que o problema está no ambiente de carregamento da classe scenebuilder.Também é um bug/problema conhecido com o scenebuilder.

Uma solução alternativa é propagar o carregador de classe para o carregador FXML.

try {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("CustomComponent.fxml"));
    loader.setRoot(this);
    loader.setController(this);
    loader.setClassLoader(getClass().getClassLoader());
    loader.load();
} catch (IOException e ){
    throw new RuntimeException(e);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top