简体   繁体   English

使用没有 FXML 的 JavaFX 控制器

[英]Using JavaFX controller without FXML

Is there a possibility to use a controller with a JavaFX GUI without using FXML.是否有可能在不使用 FXML 的情况下使用带有 JavaFX GUI 的控制器。

I noticed that the FXML file contains an fx-controller attribute to bind the controller but i don't find it an easy way to work with it.我注意到 FXML 文件包含一个fx-controller属性来绑定控制器,但我认为它不是一种简单的方法来使用它。

Any ideas about have an MVC arch with JavaFX without using the FXML file or JavaFX Scene Builder ?关于在不使用 FXML 文件或 JavaFX Scene Builder 的情况下使用 JavaFX 建立 MVC 架构的任何想法?

Your question isn't particularly clear to me: you just create the classes and basically tie everything together with listeners.您的问题对我来说不是特别清楚:您只需创建类并基本上将所有内容与听众联系在一起。 I don't know if this helps, but here is a simple example that just has a couple of text fields and a label displaying their sum.我不知道这是否有帮助,但这里有一个简单的例子,它只有几个文本字段和一个显示它们总和的标签。 This is what I regard as "classical MVC": the view observes the model and updates the UI elements if the model changes.这就是我认为的“经典 MVC”:如果模型发生变化,视图会观察模型并更新 UI 元素。 It registers handlers with the UI elements and delegates to the controller if events happen: the controller in turn processes the input (if necessary) and updates the model.它向 UI 元素注册处理程序,并在事件发生时委托给控制器:控制器依次处理输入(如有必要)并更新模型。

Model:型号:

package mvcexample;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.beans.property.SimpleIntegerProperty;

public class AdditionModel {
    private final IntegerProperty x = new SimpleIntegerProperty();
    private final IntegerProperty y = new SimpleIntegerProperty();
    private final ReadOnlyIntegerWrapper sum = new ReadOnlyIntegerWrapper();

    public AdditionModel() {
        sum.bind(x.add(y));
    }

    public final IntegerProperty xProperty() {
        return this.x;
    }

    public final int getX() {
        return this.xProperty().get();
    }

    public final void setX(final int x) {
        this.xProperty().set(x);
    }

    public final IntegerProperty yProperty() {
        return this.y;
    }

    public final int getY() {
        return this.yProperty().get();
    }

    public final void setY(final int y) {
        this.yProperty().set(y);
    }

    public final javafx.beans.property.ReadOnlyIntegerProperty sumProperty() {
        return this.sum.getReadOnlyProperty();
    }

    public final int getSum() {
        return this.sumProperty().get();
    }



}

Controller:控制器:

package mvcexample;

public class AdditionController {

    private final AdditionModel model ;

    public AdditionController(AdditionModel model) {
        this.model = model ;
    }

    public void updateX(String x) {
        model.setX(convertStringToInt(x));
    }

    public void updateY(String y) {
        model.setY(convertStringToInt(y));
    }

    private int convertStringToInt(String s) {
        if (s == null || s.isEmpty()) {
            return 0 ;
        }
        if ("-".equals(s)) {
            return 0 ;
        }
        return Integer.parseInt(s);
    }
}

View:查看:

package mvcexample;

import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextFormatter.Change;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;

public class AdditionView {
    private GridPane view ;
    private TextField xField;
    private TextField yField;
    private Label sumLabel;

    private AdditionController controller ;
    private AdditionModel model ;

    public AdditionView(AdditionController controller, AdditionModel model) {

        this.controller = controller ;
        this.model = model ;

        createAndConfigurePane();

        createAndLayoutControls();

        updateControllerFromListeners();

        observeModelAndUpdateControls();

    }

    public Parent asParent() {
        return view ;
    }

    private void observeModelAndUpdateControls() {
        model.xProperty().addListener((obs, oldX, newX) -> 
                updateIfNeeded(newX, xField));

        model.yProperty().addListener((obs, oldY, newY) -> 
                updateIfNeeded(newY, yField));

        sumLabel.textProperty().bind(model.sumProperty().asString());
    }

    private void updateIfNeeded(Number value, TextField field) {
        String s = value.toString() ;
        if (! field.getText().equals(s)) {
            field.setText(s);
        }
    }

    private void updateControllerFromListeners() {
        xField.textProperty().addListener((obs, oldText, newText) -> controller.updateX(newText));
        yField.textProperty().addListener((obs, oldText, newText) -> controller.updateY(newText));
    }

    private void createAndLayoutControls() {
        xField = new TextField();
        configTextFieldForInts(xField);

        yField = new TextField();
        configTextFieldForInts(yField);

        sumLabel = new Label();

        view.addRow(0, new Label("X:"), xField);
        view.addRow(1, new Label("Y:"), yField);
        view.addRow(2, new Label("Sum:"), sumLabel);
    }

    private void createAndConfigurePane() {
        view = new GridPane();

        ColumnConstraints leftCol = new ColumnConstraints();
        leftCol.setHalignment(HPos.RIGHT);
        leftCol.setHgrow(Priority.NEVER);

        ColumnConstraints rightCol = new ColumnConstraints();
        rightCol.setHgrow(Priority.SOMETIMES);

        view.getColumnConstraints().addAll(leftCol, rightCol);

        view.setAlignment(Pos.CENTER);
        view.setHgap(5);
        view.setVgap(10);
    }

    private void configTextFieldForInts(TextField field) {
        field.setTextFormatter(new TextFormatter<Integer>((Change c) -> {
            if (c.getControlNewText().matches("-?\\d*")) {
                return c ;
            }
            return null ;
        }));
    }
}

Application class:应用类:

package mvcexample;

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

public class MVCExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        AdditionModel model = new AdditionModel();
        AdditionController controller = new AdditionController(model);
        AdditionView view = new AdditionView(controller, model);

        Scene scene = new Scene(view.asParent(), 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

I use JavaFX extensively and do not use FXML or scenebuilder.我广泛使用 JavaFX,不使用 FXML 或场景构建器。 So I can vouch that it can be done.所以我可以保证它可以做到。

Below is the auto generated code made by my IDE to get an JavaFX main class.下面是我的 IDE 为获取 JavaFX 主类而自动生成的代码。 This will be the root of your application.这将是您的应用程序的根。 You will then add to it to create your application.然后,您将添加到它以创建您的应用程序。

public class NewFXMain extends Application {

@Override
public void start(Stage primaryStage) {
    Button btn = new Button();
    btn.setText("Say 'Hello World'");
    btn.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {
            System.out.println("Hello World!");
        }
    });

    StackPane root = new StackPane();
    root.getChildren().add(btn);

    Scene scene = new Scene(root, 300, 250);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}

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

}

For the rest of us... Here is a VERY simple example showing how to create a JavaFX form without the use of any FXML files.对于我们其他人......这是一个非常简单的示例,展示了如何在不使用任何 FXML 文件的情况下创建 JavaFX 表单。 This example can be used within an app that is already running, so I've skipped the Main class and all that ... it's just meant to show the simplicity of JavaFX.这个例子可以在已经运行的应用程序中使用,所以我跳过了 Main 类和所有这些......它只是为了展示 JavaFX 的简单性。

In a nutshell, you simply create your scene based on a container such as an AnchorPane, then you create your Stage and assign the Scene to the stage ... add your controls then show the stage简而言之,您只需根据 AnchorPane 等容器创建场景,然后创建舞台并将场景分配给舞台……添加控件然后显示舞台

package javafx;

import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class SimpleFX {

    private AnchorPane anchorPane;

    private TextArea textArea () {
        TextArea textArea = new TextArea();
        textArea.setLayoutX(20);
        textArea.setLayoutY(20);
        textArea.setMaxWidth(450);
        textArea.setMinHeight(380);
        return textArea;
    }

    private TextField textField () {
        TextField textField = new TextField();
        textField.setLayoutX(20);
        textField.setLayoutY(410);
        textField.setMinWidth(450);
        textField.setMinHeight(25);
        return textField;
    }

    private Button button() {
        Button button = new Button("Button");
        button.setLayoutX(240);
        button.setLayoutY(450);
        return button;
    }


    private void addControls    () {
        anchorPane.getChildren().add(0,textArea());
        anchorPane.getChildren().add(1,textField());
        anchorPane.getChildren().add(2,button());
    }

    public void startForm () {
        anchorPane = new AnchorPane();
        Scene scene = new Scene(anchorPane, 500, 500);
        Stage stage = new Stage();
        stage.setScene(scene);
        addControls();
        stage.show();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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