2016-12-22 4 views
0

Ich habe zwei FXML Dokumente jeweils eine Ansicht darstellt, nennen wir sie View1 und View2, und ich habe jedes in einer separaten Tab platziert, (Tab1 und Tab2) innerhalb eines TabPane.JavaFX: Rufen Sie einen Knoten

Jetzt im Controller1 von View1 Ich habe ein Ereignis, das die selectedItem meine TabPaneTab1-Tab2 wechseln. Meine Frage ist, wie kann ich auf meine TabPane von Controller1

Im Allgemeinen zugreifen. Wie erhalten wir einen bestimmten Node in Javafx.

bearbeiten Ansicht1

<VBox fx:controller="controllers.Controller1"> 
    <Button onAction="#openView2"/> 
</VBox> 

Controller1

public class Controller1{ 
    public void openView2(){ 
     //What should I do here 
    } 
} 

Mainview

<TabPane fx:id="tabPane" fx:controller="controllers.MainController"/> 

MainController

public class MainController implements Initializable { 

@FXML 
public TabPane tabPane; 

@Override 
public void initialize(URL arg0, ResourceBundle arg1) { 
    try { 
     tabPane.getTabs().add(createView1Tab()); 
     tabPane.getTabs().add(createView2Tab()); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
} 

protected Tab createView1Tab() throws IOException { 
    Tab tab = new Tab(); 
    tab.setContent(FXMLLoader.load(getClass().getResource("/views/View1.fxml"))); 
    return tab; 
} 

protected Tab createView2Tab() throws IOException { 
    Tab tab = new Tab(); 
    tab.setContent(FXMLLoader.load(getClass().getResource("/views/View2.fxml"))); 
    return tab; 
} 
} 
+0

Im Allgemeinen sollten Sie nicht auf Steuerelemente aus einer Ansicht im Controller für eine andere Ansicht zugreifen. Ändern Sie stattdessen beobachtbare Daten und beobachten Sie diese Daten dort, wo Sie sie benötigen. Wenn Sie Ihre Frage mit einem [MCVE] bearbeiten können, der das Problem demonstriert, wäre es einfacher, hier eine tatsächliche Antwort zu geben. –

+0

Danke für die Bearbeitung, aber können Sie es lesen und die Tippfehler korrigieren? Sollte 'openView1()' 'openView2()' nicht sein?Und ich nehme an, 'mainController' in MainView soll' MainController' sein? –

Antwort

2

Sie sollten ein "Ansichtsmodell" erstellen, das den aktuellen Status der Ansicht kapselt und es mit jedem der Controller teilt. Beobachten Sie es dann von Ihrem Hauptcontroller und reagieren Sie entsprechend.

Zum Beispiel:

public class ApplicationState { 

    private final StringProperty currentViewName = new SimpleStringProperty(); 

    public StringProperty currentViewNameProperty() { 
     return currentViewName ; 
    } 

    public final String getCurrentViewName() { 
     return currentViewNameProperty().get(); 
    } 

    public final void setCurrentViewName(String viewName) { 
     currentViewNameProperty().set(viewName); 
    } 
} 

Jetzt können Sie tun (man beachte ich auch Ihren redundanten ich wiederholenden Code hier entfernt):

public class MainController implements Initializable { 

    @FXML 
    public TabPane tabPane; 

    private final ApplicationState appState = new ApplicationState(); 
    private final Map<String, Tab> views = new HashMap<>(); 

    @Override 
    public void initialize(URL arg0, ResourceBundle arg1) { 
     try { 
      tabPane.getTabs().add(createViewTab("View1", new Controller1(appState))); 
      tabPane.getTabs().add(createViewTab("View2", new Controller2(appState))); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     appState.currentViewNameProperty().addListener((obs, oldView, newView) -> 
      tabPane.getSelectionModel().select(views.get(newView))); 
     appState.setCurrentViewName("View1"); 
    } 

    protected Tab createViewTab(String viewName, Object controller) throws IOException { 
     Tab tab = new Tab(); 
     FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/"+viewName+".fxml")); 
     loader.setController(controller); 
     tab.setContent(loader.load()); 
     views.put(viewName, tab); 
     return tab; 
    } 


} 

Jetzt Ihre Controller müssen nur tun:

public class Controller1{ 

    private final ApplicationState appState ; 

    public Controller1(ApplicationState appState) { 
     this.appState = appState ; 
    } 

    public void openView2(){ 
     appState.setCurrentViewName("View2"); 
    } 
} 

Beachten Sie, dass, da die Controller keine Arg-Konstruktoren haben, ich sie in Code mitfestlegen. Dies bedeutet, dass Sie das Attribut fx:controller aus den fxml-Dateien für view1 und view2 entfernen müssen, z. Ihre View1.fxml wird:

<VBox xmlns="..."> <!-- no fx:controller here --> 
    <Button onAction="#openView2"/> 
</VBox> 

Der Vorteil dieser Konstruktion ist, dass, wenn Ihr Chef in 8 Monaten in Ihr Büro geht und sagt: „Der Kunde nicht die Tabfeld mag, ersetzen Sie es mit etwas, das nur zeigt ein Bildschirm nach dem anderen ", es ist sehr einfach, solche Änderungen vorzunehmen, da alles ordnungsgemäß entkoppelt ist. (Sie müssten nur die Hauptansicht und den Controller ändern, die anderen Ansichten oder Controller würden sich überhaupt nicht ändern.) Wenn Sie den Registerkartenbereich für alle anderen Controller geöffnet haben, müssen Sie alle Bereiche finden, auf die Sie zugegriffen haben es Änderungen zu machen.

+0

JavaFX könnte in einigen Aspekten fehlen, aber IMHO das Beste, was es hat ist, dass es Sie irgendwie zwingt, ein MVC-Modell zu verwenden. – m0skit0

+0

Sehr beeindruckend –

+0

@ m0skit0 Ja (mindestens eines von MVC/MVP/MVVM/etc). Das Großbilddesign ist sehr gut, auch wenn einige der Details einige Feinabstimmungen erfordern könnten. Das ist wahrscheinlich ein gutes Zeichen, auf lange Sicht. –

Verwandte Themen