Как подключить несколько контроллеров к одной модели? Простое оконное приложение в JavaFX - PullRequest
0 голосов
/ 07 января 2019

Я видел кучу сообщений, связанных с моей проблемой, но мне кажется, что ничего не работает Я пишу простое оконное приложение на Java FX и FXML. У меня есть Main класс, который имеет поле с именами дней. У меня также есть два класса контроллеров - Контроллер (что походит на более важный контроллер) и ShowDays . Каждый контроллер имеет свой собственный FXML, и он отвечает за переключение сцен и работу с пользователем (и с моделью = 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 голосов
/ 07 января 2019

Вы должны использовать Идеи из ответа @James_D здесь . Ваша проблема в том, как передать модель от одного Controller к другому. В этом примере модель представляет собой List<String>. Модель передается в исходное Controller с именем FXMLDocumentController. С этого момента модель передается между FXMLDocumentController и ShowDayscontroller. Метод showDaysInWindow показывает информацию о текущей модели в узле Text. addDay добавляет день из массива days, если в модели отсутствует день. removeDay удаляет день из модели.

Главная

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

}

FXMLDocumentController

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>

ShowDaysController

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

}

ShowDays 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>
...