如何将多个控制器连接到一个模型? JavaFX中的简单窗口应用程序

时间:2019-01-07 17:04:09

标签: javafx model-view-controller fxml

我看过很多与我的问题有关的帖子,但似乎对我没有任何帮助。我正在用Java FX和FXML编写简单的窗口应用程序。我有一个 Main 类,该类具有带有天名称的字段。我也有两个控制器类- Controller (就像更重要的控制器一样)和 ShowDays 。每个控制器都有自己的FXML,它们负责切换场景并与用户(以及使用Model = Main )一起工作。在 Controller 类中,用户可以在我们的日期名称中添加新的一天或删除最后一天。在 ShowDays 类中,用户可以在天的窗口名称上打印。所有这些都通过单击按钮来连接。

我知道我可以更轻松地组织程序,并且可以在 Controller 类中打印日期名称,并删除所有 ShowDays 类,但这只是我想要的项目的一部分创建,而我只想了解真正的程序员是如何完成这种事情的。

这是我的代码:

public class Main extends Application {

private ArrayList<String> daysNames;

public Main() {
    daysNames = new ArrayList<>();
}

public void addDay() {
    String[] days = {"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
    System.out.println("I'm adding day!" + daysNames.size());

    if (getDaysNames().size() < 7)
        getDaysNames().add(days[getDaysNames().size()]);
    else
        System.out.println("Can't add more days!");
}

public void removeDay() {
    if (!getDaysNames().isEmpty())
        getDaysNames().remove(getDaysNames().get(getDaysNames().size()-1));
}

@Override
public void start(Stage primaryStage) throws Exception{
    Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(root, 300, 275));
    primaryStage.show();
}
//setters,getters...
}

控制器类:

public class Controller implements Initializable {
private Main myMain;
@FXML
private ShowDays showDays;

public Controller() {
    myMain=new Main();
    showDays = new ShowDays(myMain);
}

public Controller(Main main) {
    this.myMain = main;
    showDays = new ShowDays(myMain);
}

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}

public void addDay() {
    myMain.addDay();
}

public void removeDay() {
    myMain.removeDay();
}

public void GOTOshowDays(ActionEvent event) throws IOException {
    Parent showDaysParent = FXMLLoader.load(getClass().getResource("ShowDays.fxml"));
    Scene showDaysScene = new Scene(showDaysParent);
    Stage window = (Stage) ((Node)event.getSource()).getScene().getWindow();

    window.setScene(showDaysScene);
    window.show();
}
}

ShowDays 类:

public class ShowDays implements Initializable {
@FXML
private Text text;
private Main myMain;

public ShowDays() {
    myMain = new Main();
}

public ShowDays(Main main) {
    myMain = main;
}

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}

public void BackToController(ActionEvent event) throws IOException {
    Parent controllerParent = FXMLLoader.load(getClass().getResource("sample.fxml"));
    Scene controllerScene = new Scene(controllerParent);
    Stage window = (Stage) ((Node)event.getSource()).getScene().getWindow();

    window.setScene(controllerScene);
    window.show();
}

public void showDaysInWindow(ActionEvent event) throws IOException {
    String allText = "";
    for (String day : myMain.getDaysNames())
        allText += day + " ";
    text.setText(allText);
}
}  

和FXML文件: sample.fxml

<HBox prefHeight="100.0" prefWidth="483.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
    <children>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
     <children>
        <Button layoutX="-8.0" layoutY="48.0" mnemonicParsing="false" onAction="#GOTOshowDays" text="GOTO show days" />
     </children>
  </AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
  <Button mnemonicParsing="false" onAction="#addDay" text="add day" />
  <Button mnemonicParsing="false" onAction="#removeDay" text="remove day" />

ShowDays.fxml

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.ShowDays">
   <center>
      <Text fx:id="text" strokeType="OUTSIDE" strokeWidth="0.0" BorderPane.alignment="CENTER" />
   </center>
   <top>
      <Button mnemonicParsing="false" onAction="#showDaysInWindow" text="Show days" BorderPane.alignment="CENTER" />
   </top>
   <bottom>
      <Button mnemonicParsing="false" onAction="#BackToController" text="Go back" BorderPane.alignment="CENTER" />
   </bottom>
</BorderPane>

我不确定 ShowDays 用户操作是否按预期方式工作(全部有关...),但是 Controller 可以。问题是,当我在 Controller 场景中添加几天,然后将场景切换到 ShowDays 场景时,好像我丢失了 Main 实例。 ..当我只有一个控制器类时,我的代码可以应付所有时间在 Main 的同一实例上工作,并且添加/删除工作日的工作符合预期,但是我无法应付将多个控制器连接到模型和他们彼此之间……我花了很多时间尝试解决此问题,但我不太了解我在互联网上找到的所有提示,所以我问你。

1 个答案:

答案 0 :(得分:0)

您应该使用@James_D答案here中的“想法”。您的问题是如何将模型从一个chars传递到下一个。在此示例中,模型是Controller。该模型将传递到名为List<String>的初始Controller。从这一点开始,模型在FXMLDocumentControllerFXMLDocumentController之间传递。 ShowDayscontroller方法在showDaysInWindow节点中显示当前模型信息。如果模型缺少一天,则Text从数组addDay中添加一天。 days从模型中删除了一天。

  

主要

removeDay
  

FXMLDocumentController

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 *
 * @author blj0011
 */
public class JavaFXApplication320 extends Application
{

    @Override
    public void start(Stage stage)
    {
        try {
            String[] days = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
            List<String> daysNames = new ArrayList();
            for (int i = 0; i < days.length; i++) {
                daysNames.add(days[i]);
            }

            //Load the FXML. Pass the model to initModel
            FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
            loader.load();
            FXMLDocumentController fXMLDocumentController = loader.getController();
            fXMLDocumentController.initModel(daysNames);
            Scene scene = new Scene(loader.getRoot());

            stage.setScene(scene);
            stage.show();
        }
        catch (IOException ex) {
            ex.printStackTrace();
        }
    }

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

}
  

FXMLDocument

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;

/**
 *
 * @author blj0011
 */
public class FXMLDocumentController implements Initializable
{

    List<String> model;

    @FXML
    private void goToShowDays(ActionEvent event)
    {
        try {
            FXMLLoader showDaysLoader = new FXMLLoader(getClass().getResource("ShowDays.fxml"));
            showDaysLoader.load();
            ShowDaysController showDaysController = showDaysLoader.getController();
            showDaysController.initModel(this.model);

            Stage stage = (Stage) ((Button) event.getSource()).getScene().getWindow();
            stage.setScene(new Scene(showDaysLoader.getRoot()));
        }
        catch (IOException ex) {
            ex.printStackTrace();
        }

    }

    @FXML
    private void addDay(ActionEvent event)
    {
        String[] days = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
        List<String> tempDays = new ArrayList(Arrays.asList(days));

        if (!this.model.containsAll(tempDays)) {
            tempDays.removeAll(this.model);
            if (tempDays.size() > 0) {
                this.model.add(tempDays.get(0));
            }
        }
    }

    @FXML
    private void removeDay(ActionEvent event)
    {
        if (this.model.size() > 0) {
             Random random = new Random();
             this.model.remove(random.nextInt(this.model.size()));
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle rb)
    {
        // TODO
    }

    public void initModel(List<String> model)
    {
        // ensure model is only set once:
        if (this.model != null) {
            throw new IllegalStateException("Model can only be initialized once");
        }

        this.model = model;
        this.model.forEach(System.out::println);
    }

}
  

ShowDaysController

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

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



<HBox prefHeight="100.0" prefWidth="483.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication320.FXMLDocumentController">
    <children>
        <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
            <children>
                <Button layoutX="-8.0" layoutY="48.0" mnemonicParsing="false" onAction="#goToShowDays" text="GOTO show days" />
            </children>
        </AnchorPane>
        <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
        <Button mnemonicParsing="false" onAction="#addDay" text="add day" />
        <Button mnemonicParsing="false" onAction="#removeDay" text="remove day" />
    </children>
</HBox>
  

ShowDays FXML

import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**
 * FXML Controller class
 *
 * @author blj0011
 */
public class ShowDaysController implements Initializable
{

    @FXML
    Text text;

    List<String> model;

    @FXML
    private void showDaysInWindow(ActionEvent event)
    {
        text.setText(String.join(" ", this.model));
    }

    @FXML
    private void backToController(ActionEvent event)
    {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
            loader.load();
            FXMLDocumentController fXMLDocumentController = loader.getController();
            fXMLDocumentController.initModel(this.model);

            Stage stage = (Stage) ((Button) event.getSource()).getScene().getWindow();
            stage.setScene(new Scene(loader.getRoot()));
        }
        catch (IOException ex) {
            ex.printStackTrace();
        }
    }

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

    public void initModel(List<String> model)
    {
        // ensure model is only set once:
        if (this.model != null) {
            throw new IllegalStateException("Model can only be initialized once");
        }

        this.model = model;
        this.model.forEach(System.out::println);
    }

}