JavaFX FXML在将fxml作为组件嵌入到另一个fxml中时,“Controller is not defined on root component”无法正确识别我的控制器方法。

3

我正在创建一个富UI应用程序,使用FXML在每个部分中都有单独的控制器。我决定遵循这篇教程并将我的FXML用作组件。因此,我使用类作为控制器和组件。一切似乎都正常,但当我尝试将方法放入我的类/控制器时,我遇到了问题。我编辑了我的FXML,所以不直接将控制器放入其中,而是使用类本身。这就是问题所在的地方。

<fx:root fx:id="profilePane" onMouseClicked="#select" onMouseEntered="#hoverOver" onMouseExited="#hoverOut" type="javafx.scene.layout.Pane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">...etc

每个方法都提示“在根组件上未定义Controller”的错误。我知道我从fxml中删除了那个部分。但是,我按照教程进行操作该怎么办?这是我正在使用的组件类。
imports etc..
public class FxmlProfilePanel extends Pane implements Initializable{

    @FXML
    private ToggleButton toggleButton;

    @FXML
    private Pane profilePane;

    private FadeTransition fadeTransition=new FadeTransition(Duration.millis(500),toggleButton);


    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO


        System.out.println("Is fx thread?:"+Platform.isFxApplicationThread());
    }   

    public FxmlProfilePanel(){
        FXMLLoader fxmlLoader=new FXMLLoader(getClass().getResource("/bitcompile/ecps/fxml/FxmlProfilePanel.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);
        try {
            fxmlLoader.load();
        } catch (IOException ex) {
            Logger.getLogger(FxmlProfilePanel.class.getName()).log(Level.SEVERE, null, ex);
        }
    }


    public void hoverOver(MouseEvent event){
        Platform.runLater(() -> {
            if(!toggleButton.isSelected()){
            toggleButton.setText("Select profile");
            fadeTransition.setFromValue(0);
            fadeTransition.setToValue(1.0);
            fadeTransition.play();

            }else{
            toggleButton.setText("Deselect profile");
            fadeTransition.setFromValue(0);
            fadeTransition.setToValue(1.0);
            fadeTransition.play();
            }
        });
    }

      public void hoverOut(MouseEvent event){
        Platform.runLater(() -> {
            if(toggleButton.isSelected())
            fadeTransition.setFromValue(1.0);
            fadeTransition.setToValue(0);
            fadeTransition.play();
        });
    }

    public void selected(MouseEvent event){
        if(!toggleButton.isSelected()){
          toggleButton.setSelected(true);
          toggleButton.setText("Profile Selected");

        }else{
            toggleButton.setSelected(false);
            toggleButton.setText("Select profile");
        }
    }
}

问题是:当我将fxml/controller作为组件嵌入到另一个fxml中,而这个fxml又嵌套在另一个fxml中时,如何从我的组件类中连接我的方法?(我知道如何遵循普通的fxml样式并使用单独的控制器等来完成所有这些操作,但不是这种方式)我选择了错误的方式吗?应该考虑另一种方法吗?感谢任何见解。
完整的fxml代码:
<fx:root fx:id="profilePane" onMouseClicked="#select" onMouseEntered="#hoverOver" onMouseExited="#hoverOut" type="javafx.scene.layout.Pane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children><AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="384.0" prefWidth="270.0" style="-fx-border-color: #40464A;">
<children>
<StackPane prefHeight="430.0" prefWidth="270.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Pane prefWidth="270.0">
<children><ImageView fitHeight="288.0" fitWidth="270.0" layoutY="49.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../resources/images/category/TechnologyTemp.png" />
</image>
<StackPane.margin>
<Insets top="45.0" />
</StackPane.margin>
<viewport>
<Rectangle2D />
</viewport></ImageView>
</children>
</Pane><BorderPane layoutX="79.0" layoutY="100.0" prefHeight="258.0" prefWidth="270.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<top>
<Pane prefHeight="49.0" prefWidth="268.0" style="-fx-background-color: white;">
<children><VBox prefHeight="143.0" prefWidth="270.0" BorderPane.alignment="CENTER">
<children><Label text="Adobe">
<font>
<Font name="System Bold" size="15.0" />
</font>
<padding>
<Insets left="10.0" top="5.0" />
</padding>
</Label><Label text="Adobe Systems,inc">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="3.0" left="10.0" />
</padding>
</Label>
<Pane layoutX="-1.0" opacity="0.82" prefHeight="82.0" prefWidth="220.0">
<children><TextArea cache="true" editable="false" focusTraversable="false" mouseTransparent="true" pickOnBounds="false" prefHeight="82.0" prefWidth="268.0" style="-fx-background-radius: 0;" text="Oracle continually applies good corporate governance principles. The composition and activities of the company's Board of Directors, the approach to public disclosure" wrapText="true">
<VBox.margin>
<Insets top="53.0" />
</VBox.margin></TextArea>
</children>
</Pane>
</children></VBox>
</children>
</Pane>
</top>
<bottom>
<Pane prefHeight="45.0" prefWidth="270.0" style="-fx-background-color: white;">
<children><VBox prefHeight="55.0" prefWidth="270.0" BorderPane.alignment="CENTER">
<children><Label text="Technology">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets left="10.0" top="4.0" />
</padding>
</Label><Label text="Software services &amp; provider">
<padding>
<Insets left="10.0" />
</padding>
<font>
<Font size="13.0" />
</font></Label>
</children></VBox>
</children>
</Pane>
</bottom></BorderPane>
</children>
</StackPane><Pane prefHeight="382.0" prefWidth="270.0">
<children><ToggleButton fx:id="toggleButton" layoutX="1.0" layoutY="191.0" mnemonicParsing="false" prefHeight="30.0" prefWidth="268.0" style="-fx-background-radius: 0; -fx-background-color: #57A1DE;" text="Select profile" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font></ToggleButton>
</children></Pane>
</children></AnchorPane>
</children>
</fx:root>

“<fx:root ...>”是你的FXML文件的根元素吗?我认为这是唯一有效的位置。 - James_D
@James_D 是的,那是根元素,然后子元素在其下面。到目前为止,整个UI都是解耦的。这个组件应该独立工作,没有任何依赖关系,因此我将其制作为组件。但是无论我尝试什么,都无法使这些方法起作用。 - Tomas Bisciak
那么错误在哪里?它们是Java代码中的编译错误吗? - James_D
每个方法都被标记为红色,当我悬停在上面时,错误提示说“Controller未定义在根组件上”。但是我的类中确实存在每个方法,而且fx:root是一个根元素。除了我的问题,我还会发布整个fxml文件。 - Tomas Bisciak
所以这只是IDE报告的错误,而且如果我理解正确的话,它在FXML文件中。你有没有尝试看看它是否仍然可以工作,因为FXML没有被编译? - James_D
是的,那是正确的。不,我还没有尝试过,我认为这是一个警示信号,所以没有继续,但我会尝试并很快报告结果。 - Tomas Bisciak
4个回答

4

它与以下内容配合使用效果很好:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class LoadOwnFXML extends Application {

    @Override
    public void start(Stage primaryStage) {


            Scene scene = new Scene(new ProfilPane());
            primaryStage.setTitle("Hello World!");
            primaryStage.setScene(scene);
            primaryStage.show();
    }

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

}

还有ProfilePane类

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.AnchorPane;

public class ProfilPane extends AnchorPane {

    public ProfilPane() {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("my.fxml"));
            loader.setRoot(this);
            loader.setController(this);
            loader.load();
        } catch (IOException ex) {
            Logger.getLogger(ProfilPane.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @FXML
    public void select() {
        System.out.println("selected");
    }

    @FXML
    public void hoverOver() {
        System.out.println("hovered");
    }

    @FXML
    public void hoverOut() {
        System.out.println("hovered out");
    }
}
< p >FXML文件

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<fx:root fx:id="profilePane" onMouseClicked="#select" onMouseEntered="#hoverOver" onMouseExited="#hoverOut" type="javafx.scene.layout.Pane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children><AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="384.0" prefWidth="270.0" style="-fx-border-color: #40464A;">
<children>
<StackPane prefHeight="430.0" prefWidth="270.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Pane prefWidth="270.0">
<children><ImageView fitHeight="288.0" fitWidth="270.0" layoutY="49.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../resources/images/category/TechnologyTemp.png" />
</image>
<StackPane.margin>
<Insets top="45.0" />
</StackPane.margin>
<viewport>
<Rectangle2D />
</viewport></ImageView>
</children>
</Pane><BorderPane layoutX="79.0" layoutY="100.0" prefHeight="258.0" prefWidth="270.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<top>
<Pane prefHeight="49.0" prefWidth="268.0" style="-fx-background-color: white;">
<children><VBox prefHeight="143.0" prefWidth="270.0" BorderPane.alignment="CENTER">
<children><Label text="Adobe">
<font>
<Font name="System Bold" size="15.0" />
</font>
<padding>
<Insets left="10.0" top="5.0" />
</padding>
</Label><Label text="Adobe Systems,inc">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="3.0" left="10.0" />
</padding>
</Label>
<Pane layoutX="-1.0" opacity="0.82" prefHeight="82.0" prefWidth="220.0">
<children><TextArea cache="true" editable="false" focusTraversable="false" mouseTransparent="true" pickOnBounds="false" prefHeight="82.0" prefWidth="268.0" style="-fx-background-radius: 0;" text="Oracle continually applies good corporate governance principles. The composition and activities of the company's Board of Directors, the approach to public disclosure" wrapText="true">
<VBox.margin>
<Insets top="53.0" />
</VBox.margin></TextArea>
</children>
</Pane>
</children></VBox>
</children>
</Pane>
</top>
<bottom>
<Pane prefHeight="45.0" prefWidth="270.0" style="-fx-background-color: white;">
<children><VBox prefHeight="55.0" prefWidth="270.0" BorderPane.alignment="CENTER">
<children><Label text="Technology">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets left="10.0" top="4.0" />
</padding>
</Label><Label text="Software services &amp; provider">
<padding>
<Insets left="10.0" />
</padding>
<font>
<Font size="13.0" />
</font></Label>
</children></VBox>
</children>
</Pane>
</bottom></BorderPane>
</children>
</StackPane><Pane prefHeight="382.0" prefWidth="270.0">
<children><ToggleButton fx:id="toggleButton" layoutX="1.0" layoutY="191.0" mnemonicParsing="false" prefHeight="30.0" prefWidth="268.0" style="-fx-background-radius: 0; -fx-background-color: #57A1DE;" text="Select profile" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font></ToggleButton>
</children></Pane>
</children></AnchorPane>
</children>
</fx:root>

你看到了哪些错误?也许你需要一些导入吗?请发布你得到的错误,这样我就可以看看如何解决它。 - Patrick

2
尝试从<fx:root ...>元素中删除fx:id属性以及Java代码中的相应profilePane字段。由于在Java代码中根元素仅为this,因此这些都是冗余的。我怀疑这只会混淆您的IDE。
与您的问题无关,但您需要在initialize()方法中初始化FadeTransition,因为在调用该方法之前,toggleButton将不会被初始化。而且,没有必要进行Platform.runLater(...)调用;事件处理程序将在FX应用程序线程上调用。

0
对我有效的方法(使用NetBeans 8.1和jdk8u74)是在我的.fxml文件的根元素中添加fx:controller属性。例如,如果根元素为GridPane,控制器类为fxmltableview包中的FXMLTableViewController:
<GridPane xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fxmltableview.FXMLTableViewController">

0
在FXML文档的最上层父级中添加fx:controller="packagename.FXMLDocumentController"类。例如,在我的情况下,我将其添加到顶部的VBox中,并将所有组件作为VBox的子级,这就是为什么现在一切都正常工作的原因。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接