简体   繁体   中英

What is wrong with this JavaFX/FXML custom component?

I am learning to write FXML custom components for use with JavaFX 8 and Scene Builder.

I wrote the FXML file shown below but Scene Builder will not open it, giving me the message "Open operation has failed" due to the exception:

java.io.IOException: javafx.fxml.LoadException: mycustomcomponent.TicoTeco is not a valid type.
/C:/Users/xxxxx/Documents/NetBeansProjects/MyCustomComponent/src/mycustomcomponent/TicoTeco.fxml:9
    at com.oracle.javafx.scenebuilder.kit.fxom.FXOMLoader.load(FXOMLoader.java:92)
    at com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.(FXOMDocument.java:80)
    at com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.(FXOMDocument.java:95)
...

Why am I getting this exception?

Here's the FXML file:

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<fx:root type="mycustomcomponent.TicoTeco" prefHeight="93.0" prefWidth="304.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <BorderPane layoutX="61.0" prefHeight="115.0" prefWidth="200.0">
         <left>
            <Button fx:id="tico" mnemonicParsing="false" text="Tico" BorderPane.alignment="CENTER" />
         </left>
         <right>
            <Button fx:id="teco" mnemonicParsing="false" text="Teco" BorderPane.alignment="CENTER" />
         </right>
      </BorderPane>
   </children>
</fx:root>

And here are the Java files for TicoTeco.java and Main.java:

package mycustomcomponent;

import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;

public class TicoTeco extends AnchorPane {

    @FXML
    Button tico;

    @FXML
    Button teco;

    public TicoTeco() throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(TicoTeco.class.getResource("TicoTeco.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);
        fxmlLoader.load();
    }

    @FXML
    public void initialize() {
        final EventHandler<ActionEvent> onAction = 
                event -> System.out.println("Hi, I'm " + (event.getSource() == tico? "Tico" : "Teco") + "!");
        tico.setOnAction(onAction);
        teco.setOnAction(onAction);
    }
}
package mycustomcomponent;

import java.io.IOException;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws IOException {
        Scene scene = new Scene(new TicoTeco());

        primaryStage.setTitle("Here are Tico and Teco!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

It's a bit tricky. So your fxml have a little mistake:

Your custom class is extending AnchorPane , so this should be the root in your fxml:

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<fx:root type="AnchorPane" prefHeight="93.0" prefWidth="304.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <BorderPane layoutX="61.0" prefHeight="115.0" prefWidth="200.0">
         <left>
            <Button fx:id="tico" mnemonicParsing="false" text="Tico" BorderPane.alignment="CENTER" />
         </left>
         <right>
            <Button fx:id="teco" mnemonicParsing="false" text="Teco" BorderPane.alignment="CENTER" />
         </right>
      </BorderPane>
   </children>
</fx:root>

After that, you have to make a jar of it, because you have a fxml and a java class. This is the tricky part in Netbeans, so follow up:

First: Create an own Library Project for the component that looks like this with your copied source files:

在此输入图像描述

Second: Delete the copied Main (where the main method is in) file

Third: Do a "Clean and Build" at the project. The generated .jar file will be in the subfolder "dist" in your Project directory.

Fourth: Open Scene Builder and import your CustomComponent .jar file like this:

在此输入图像描述

在此输入图像描述

Now you are able to use the component as you want. But be aware of changes to the component are not dynamicaly refresh the imported jar, you have to do the whole thing again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM