提问者:小点点

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


我看到了很多与我的问题有关的帖子,但似乎没有什么对我有效。我正在用JavaFX和FXML编写简单的窗口应用程序。我有一个Main类,它有带日期名称的字段。我还有两个控制器类——controller(它就像更重要的控制器一样)和ShowDays。每个控制器都有自己的FXML,它们负责切换场景和与用户(以及Model=Main)合作。在Controller类中,用户可以将新的一天添加到我们的日期名称中,也可以删除最后一天。在ShowDays类中,用户可以在窗口上打印日期名称。这一切都与点击按钮有关。

我知道我可以更轻松地组织我的程序,我可以在控制器类中打印天数名称并删除所有 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();
}
}

表演日类:

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" />

显示日期.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>

我不确定ShowDay用户操作是否按预期工作(都是关于这个的…),但控制器可以。问题是,当我在控制器场景中添加几天,然后将场景切换到显示场景时,我似乎丢失了我的主实例…当我有一个控制器类时,我的代码处理所有时间在同一个Main实例上工作,添加/删除天数按预期工作,但我无法处理连接多个控制器来建模和相互连接…我花了这么多时间试图解决这个问题,我真的不明白我在互联网上找到的所有提示,所以我问你。


共1个答案

匿名用户

你应该在这里使用@James_D的创意回答。您的问题是如何将模型从一个控制器传递到下一个控制器。在本例中,模型是一个<code>列表

主要的

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);
    }

}

FXML文档控制器

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);
    }

}

FXMLDocument

<?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控制器

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);
    }

}

显示FXML

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication320.ShowDaysController">
    <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>