FXML: контроллер не указан, а контроллер указан в контроллере - PullRequest
0 голосов
/ 28 октября 2019

Я пытаюсь использовать несколько файлов fxml в приложении, которое я создаю, и в ходе некоторых исследований я обнаружил, что использование пользовательских контроллеров для файлов fxml - лучший подход к выполнению этого типа приложения.

Я следовал учебному руководству Oracle Docs по «Освоению FXML» и установил корень и контроллер как «this» в файле CustomController.java.

Проблема возникает, когда intellij обнаруживает, что в файле fxml для обработчика onAction не указан контроллер, а я указываю контроллер программно.

tester.java

package task01;

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

public class tester extends Application
{
    @Override
    public void start(Stage stage) throws Exception
    {
        CustomController customController = new CustomController();

        customController.getStylesheets().add("/task01/stylize.css");

        stage.setScene(new Scene(customController,1920,1080));
        stage.setTitle("Seneca ATM Program");
        stage.setWidth(1920);
        stage.setHeight(1080);
        stage.show();
    }

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

CustomContoller.java

package task01;

import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.fxml.*;
import javafx.scene.layout.Pane;
import java.io.IOException;

public class CustomController extends GridPane
{

    @FXML
    private Pane viewableContent;

    @FXML
    private Button vigilanteButton;

    public CustomController()
    {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("root.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try
        {
            fxmlLoader.load();
        } catch (IOException exception)
        {
            throw new RuntimeException(exception);
        }
    }

    @FXML
    private void vigilanteAction(ActionEvent actionEvent)
    {
        System.out.println("Hello, World");
    }
}

root.fxml

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

<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.GridPane?>

<?import task01.MainMenuController?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.Pane?>
<fx:root type="javafx.scene.layout.GridPane" xmlns:fx="http://javafx.com/fxml" alignment="CENTER">
    <ImageView fitWidth="229.67" fitHeight="149.67" GridPane.columnIndex="0" GridPane.rowIndex="0" GridPane.halignment="CENTER">
        <Image url="/task01/logo.png"/>
    </ImageView>
    <Pane fx:id="viewableContent" GridPane.columnIndex="0" GridPane.rowIndex="1" GridPane.halignment="CENTER">
        <MainMenuController/>
    </Pane>
    <Button fx:id="vigilanteButton">Vigilante</Button>
</fx:root>

MainMenuController.java

package task01;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import java.io.IOException;

public class MainMenuController extends GridPane
{
    private CustomController customController = new CustomController();

    public MainMenuController()
    {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("mainmenu.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try
        {
            fxmlLoader.load();
        } catch (IOException exception)
        {
            throw new RuntimeException(exception);
        }
    }

    @FXML
    private VBox buttonSet;
    @FXML
    private HBox buttonSetOne;
    @FXML
    private HBox buttonSetTwo;
    @FXML
    private  Button changePinButton;
    @FXML
    private Button accountInquiryButton;
    @FXML
    private Button withdrawMoneyButton;
    @FXML
    private Button depositMoneyButton;
    @FXML
    private Button balanceInquiryButton;
    @FXML
    private Button createAccountButton;
    @FXML
    private GridPane gridpane;

    @FXML
    public void createAccountAction(ActionEvent actionEvent)
    {

    }
}

mainmenu.fxml

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

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<?import javafx.geometry.Insets?>
<GridPane fx:id="gridpane" alignment="CENTER" vgap="50" hgap="50" xmlns:fx="http://javafx.com/fxml">
    <padding><Insets top="10" bottom="10" left="10" right="10"/></padding>
    <VBox fx:id="buttonSet" spacing="25" GridPane.columnIndex="0" GridPane.rowIndex="1">
        <HBox fx:id="buttonSetOne" spacing="25">
            <Button styleClass="menuButton" fx:id="createAccountButton" onAction="#createAccountAction">Create account</Button>
            <Button styleClass="menuButton" fx:id="changePinButton">Change PIN</Button>
            <Button styleClass="menuButton" fx:id="accountInquiryButton">Account Inquiry</Button>
        </HBox>
        <HBox fx:id="buttonSetTwo" spacing="25">
            <Button styleClass="menuButton" fx:id="withdrawMoneyButton">Withdraw Money</Button>
            <Button styleClass="menuButton" fx:id="depositMoneyButton">Deposit Money</Button>
            <Button styleClass="menuButton" fx:id="balanceInquiryButton">Balance Inquiry</Button>
        </HBox>
    </VBox>
</GridPane>

Ответы [ 3 ]

0 голосов
/ 28 октября 2019

Разделяй и властвуй: разбивайте сложные проблемы на более мелкие. Начните с простой настройки, подобной следующей:

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class tester extends Application
{
    @Override
    public void start(Stage stage) throws Exception
    {
        CustomController customController = new CustomController();

        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("root.fxml"));
        fxmlLoader.setController(customController);
        Parent root = (Parent)fxmlLoader.load();

        stage.setScene(new Scene(root,1920,1080));
        stage.setTitle("Seneca ATM Program");
        stage.show();
    }

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

//controller should be just that. It is not a pane 
class CustomController /* extends GridPane */
{

    @FXML
    private Pane viewableContent;

    @FXML
    private Button vigilanteButton;

    @FXML
    private void vigilanteAction(ActionEvent actionEvent)
    {
        System.out.println("Hello, World");
    }
}

root.fxml:

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

<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.GridPane?>
<!--  ?import task01.MainMenuController?-->
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.Pane?>

<GridPane xmlns:fx="http://javafx.com/fxml" alignment="CENTER">
    <ImageView fitWidth="229.67" fitHeight="149.67" GridPane.columnIndex="0" GridPane.rowIndex="0"
     GridPane.halignment="CENTER">
        <Image url="task01/logo.png"/>  <!-- todo: set correct path -->
    </ImageView>
    <Button fx:id="vigilanteButton" onAction="#vigilanteAction">Vigilante</Button>
</GridPane>

Надеюсь, это поможет вам структурировать ваше приложение.

0 голосов
/ 28 октября 2019

IDE не может узнать о том, как вы настраиваете контроллер где-то в своем Java-коде. По этой причине функции автозаполнения и т.п. отключены. Тот факт, что среда IDE отображает подобные «проблемы», в этом случае вызывает сожаление, но они могут указывать на проблему, которая может быть распознана только во время выполнения.

В вашем случае, если у вас нет опечаток вВаш fxml, можно игнорировать эти предупреждения.

Конечно, вы можете просто временно добавить атрибут fx:controller при редактировании fxml и удалить его, когда закончите.

Другой способдля решения этой проблемы было бы указать атрибут fx:controller в fxml и задать свойство controllerFactory вместо свойства controller для загрузчика. Мне не очень нравится такой подход:

<GridPane fx:id="gridpane" alignment="CENTER" vgap="50" hgap="50" xmlns:fx="http://javafx.com/fxml" fx:controller="task01.MainMenuController">
    ...
public MainMenuController() {
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("mainmenu.fxml"));
    fxmlLoader.setRoot(this);

    fxmlLoader.setControllerFactory(clazz -> {
        if (!clazz.isInstance(this)) {
            throw new IllegalArgumentException(String.format("class of controller (%s) not assignable to class specified in fxml (%s)", this.getClass().getName(), clazz.getName()));
        }
        return this;
    });

    try {
        fxmlLoader.load();
    } catch (IOException exception) {
        throw new RuntimeException(exception);
    }
}

Если вы не хотите проверять совместимость назначений между типом контроллера, указанным в fxml, и типом контроллера, который вы указали,controllerFactory можно было бы упростить до clazz -> this.

Если вы хотите использовать этот подход для нескольких классов, я настоятельно рекомендую создать класс для фабрики контроллеров, чтобы избежать повторений, предполагая, что вы хотите выполнить проверку .. .

0 голосов
/ 28 октября 2019

В этом и заключается проблема: вы можете привязать файл FXML к контроллеру с контроллера, но когда вы это сделаете, IDE не узнает об этом, пока он не заработает. Вот почему IDE доставляет вам неприятности. Если вы хотите установить обработчик onAction, вам придется сделать это из контроллера. Вы должны создать такой метод и добавить слушателя onAction к кнопке:

@FXML
public void initialize() {
    createAccountButton.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {
            // TODO Auto-generated method stub
            createAccountAction(event);
        }
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...