JavaFx 处理程序覆盖

JavaFx handler override

我有一个从 fxml 构建器构建的 fxml 文件,我在 Java.

中通过加载器使用它
URL resource = getClass().getClassLoader().getResource("fxmlFile.fxml");

FXMLLoader loader = new FXMLLoader(resource, resourceBundle);
Pane rootPane = (Pane) loader.load(); 

这个 fxml 文件将点击事件映射到我的 class;

<Group id="Group" layoutX="0.0" layoutY="0.0" onMouseReleased="#handleThis" scaleX="1.0" scaleY="1.0">
...
<Group/>

所以我在 class 中实现了我的处理程序,我们称它为 MyClass;

public class MyClass {
public void createScene() throws IOException
{
    URL resource = getClass().getClassLoader().getResource("fxmlFile.fxml");

    FXMLLoader loader = new FXMLLoader(resource, resourceBundle);
    Pane rootPane = (Pane) loader.load(); 
    ...
}

@FXML
public void handleThis(ActionEvent event) {
    System.out.println("from MyClass");
}
        ...
}

现在我将 MyClass 扩展为 MyExtendedClass 并覆盖 handleThis 方法;

public class MyExtendedClass extends MyClass {
    @Override
    public void handleThis(ActionEvent event) {
           System.out.println("from MyExtendedClass");
    }
}

我的问题是,我无法在我的扩展 class 中处理 handle 方法。它不会覆盖它。我怎样才能让它打印 "from MyExtendedClass" 而不是 "from MyClass"?

当在 MyExtendedClass 实例上调用 createScene() 时,FXMLLoader 解析 FXML 文件,读取 fx:controller="MyClass" 属性并实例化一个 new 对象输入 MyClass。这就是为什么始终调用基方法的原因。 FXMLLoader 不知道 MyExtendedClass。

有一种 - 骇人听闻的 - 方法可以实现你想要的(即在 MyClass 中进行加载并仍然在 FXML 中定义控制器):

public class MyClass
{
    public void createScene()
    {
        try
        {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(getClass().getResource("FXML.fxml"));
            // set a controller factory that returns this instance as controller
            // (works in this case, but not recommended)
            loader.setControllerFactory(controllerType -> this);
            pane = (Pane) loader.load();
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }
}

实例化控制器并将其传递给 FXMLLoader 会更清晰。
为此,必须从 FXML 文件中删除 fx:controller="" 属性。

public class Main extends Application
{
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        MyClass controller = new MyExtendedClass();

        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("FXML.fxml"));
        loader.setController(controller);
        Pane pane = (Pane) loader.load();

        primaryStage.setScene(new Scene(pane));
        primaryStage.show();
    }

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

或者使用fx:controller="MyClass"在FXML文件中定义基本类型,让控制器工厂决定实际实现。

public class Main extends Application
{
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("FXML.fxml"));
        loader.setControllerFactory(controllerType -> {
            if (MyClass.class.equals(controllerType))
                return new MyExtendedClass();
            else
                return null; // return some other controller
        });
        Pane pane = (Pane) loader.load();

        MyClass controller = (MyClass) loader.getController();

        primaryStage.setScene(new Scene(pane));
        primaryStage.show();
    }

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