2012-08-28 11 views
25

Goodevening jeder,Mehrere FXML mit Controllern, zu teilen Objekt

Ich habe ein paar Beiträge zu diesem Thema bereits gefunden, aber ich kann immer noch nicht geschafft, ein Objekt aus Controller1 zu Controller2 passieren. Gibt es irgendwo ein vollständiges Tutorial oder ein Beispielprojekt, das das tut?

Ich habe so weit gekommen, bis ich stecken geblieben:

Land Klasse

public class Country { 
private SimpleStringProperty country = new SimpleStringProperty(""); 

//Constructor 
public Country() { 
} 

//GETTERS 
public String getCountry() { 
    return country.get(); 
} 

//SETTERS 
public void setCountry(String value) { 
    country.set(value); 
} 

@Override 
public String toString() { 
    return getCountry(); 
} 
} 

Wenn das Programm startet, wird die Haupt FXML geladen (Sample.fxml). Dies enthält ein Rahmenfenster mit einer Menüleiste im oberen Bereich und einem Inhaltsbereich in der Mitte. Bei der Initialisierung erzeuge ich ein neues Country-Objekt und speichere es in einer globalen Variablen. Ich habe eine Methode, die eine andere FXML in den Inhaltsbereich geladen wird, wenn ein Menüpunkt angeklickt wird:

SampleController.java

public class SampleController implements Initializable { 

@FXML 
private Pane pContent; 

private Country c; 

@FXML 
private void handleButtonAction(ActionEvent event) throws IOException { 
    System.out.println(c); //this prints Belgium, which is correct 

    URL url = getClass().getResource("Sub1.fxml"); 

    FXMLLoader fxmlloader = new FXMLLoader(); 
    fxmlloader.setLocation(url); 
    fxmlloader.setBuilderFactory(new JavaFXBuilderFactory()); 

    pContent.getChildren().clear(); 
    pContent.getChildren().add((Node) fxmlloader.load(url.openStream())); 
} 

@Override 
public void initialize(URL url, ResourceBundle rb) { 
    c = new Country(); 
    c.setCountry("Belgium"); 
} 

public Country getCountryFromSampleController(){ 
    return c; 
} 
} 

Nun wünsche ich das Land Objekt zu erfassen, wenn die Sub1.fxml geladen wird , was bedeutet, ich brauche das Land Objekt auf initialize() zu holen:

Sub1Controller.java

public class Sub1Controller implements Initializable { 

/** 
* Initializes the controller class. 
*/ 
@Override 
public void initialize(URL url, ResourceBundle rb) { 
    SampleController sp = new SampleController(); //I don't know how to fetch the original SampleController object 
    System.out.println(sp.getCountryFromSampleController()); 
    //this prints null, which is ofcourse logical because I make a new SampleController object.   
}  
} 

Die Frage, die ich habe, wie kann ich das 'original' SampleController-Objekt, so dass ich die getCountryFromRoot() -Methode abrufen können, um das Land-Objekt mit dem Wert Belgien? Ich habe stundenlang nach diesem Thema gesucht und jeden Post zu StackOverflow darüber gelesen, aber es scheint, dass ich den fehlenden Link nicht finde ... jede Hilfe (vorzugsweise mit diesem Code) wird geschätzt!

Sorry für den langen Post, habe ich versucht, so vollständig wie möglich sein, sonst werde ich nie verstehen ...

Antwort

41

FXML ist eine einfache Form von MVC pattern. FXML-Datei ist eine Ansicht, Controller ist offensichtlich, was ist verpasst? Das Modell - ein Ort, an dem Sie alle Daten in Bezug auf Ihre aktuelle Ansicht speichern und mit denen Sie Länderdaten zwischen Controllern teilen können.


1. eine der möglichen Vorgehensmodell einzuführen, ist "Kontext". Werfen wir einen Fall betrachten, dann haben Sie nur ein Modell für das gesamte Projekt, so dass Sie einen globalen Kontext in Form von Singleton

public class Context { 
    private final static Context instance = new Context(); 

    public static Context getInstance() { 
     return instance; 
    } 

    private Country country = new Country(); 

    public Country currentCountry() { 
     return country; 
    } 
} 

Ihre SampleController nächsten Änderungen haben haben:

@Override 
public void initialize(URL url, ResourceBundle rb) { 
    Context.getInstance().currentCountry().setCountry("Belgium"); 
} 

Und SubController1 kann es die gleiche Weise zugreifen:

@Override 
public void initialize(URL url, ResourceBundle rb) { 
    System.out.println(Context.getInstance().currentCountry().getCountry()); 
} 

2. Eine andere Möglichkeit besteht darin, den Kontext an SubController1 weiterzuleiten, dann lädt man es mit xml. Es wird besser funktionieren, wenn Sie kein globales Anwendungsmodell haben möchten.So ähnlich Context-Klasse erstellen, aber ohne Instanzfelder, und:

public class Sub1Controller implements Initializable { 
    private Context context; 
    public void setContext(Context context) { 
     this.context = context; 
     // initialize country dependent data here rather then in initialize() 
    } 
} 

Rahmen Kontext in SampleController:

Context currentContext = new Context(); 

@Override 
public void initialize(URL url, ResourceBundle rb) { 
    currentContext.currentCountry().setCountry("Belgium"); 
} 

@FXML 
private void handleButtonAction(ActionEvent event) throws IOException { 
    URL url = getClass().getResource("Sub1.fxml"); 

    FXMLLoader fxmlloader = new FXMLLoader(); 
    fxmlloader.setLocation(url); 
    fxmlloader.setBuilderFactory(new JavaFXBuilderFactory()); 

    pContent.getChildren().clear(); 
    pContent.getChildren().add((Node) fxmlloader.load(url.openStream())); 
      // here we go 
    ((Sub1Controller)fxmlloader.getController()).setContext(currentContext); 
} 
+0

Dank millionenfach Sergey macht es endlich Sinn. Dies ist das erste Mal, dass ich eine große Anwendung erstellen muss, aber ich kämpfe immer noch daran, wie man es "baut". Ich habe auch eine andere Sicherheitsfrage, die ich fragen möchte, aber ich bin mir nicht sicher, ob dies die richtige Seite ist, um es zu fragen (es ist nicht Code bezogen) – Perneel

+0

Hey Sergey, tut mir leid, dieses alte Thema zu bringen. Dies funktioniert immer noch als ein Zauber, aber was ich mich wundere ... Gibt es eine Möglichkeit, die Breite und Höhe aus dem Node - Objekt '(Node) fxmloader.load (url.openStream())' so zu maximieren, dass es an die width & Höhe des Pane (pContent)? – Perneel

+0

sollte es automatisch funktionieren, wenn nicht, besser bieten Sie Ihren Code in einer separaten Frage –