2016-12-22 4 views
0

У меня есть два FXML документов каждый из них представляет собой вид, давайте назовем их View1 и View2, и я поместил каждый в отдельном Tab, (Tab1 и Tab2) внутри TabPane.JavaFX: Получение узла

Сейчас в Controller1 из View1 у меня есть событие, которое будет переключать selectedItem из моих TabPane с Tab1 в Tab2. Мой вопрос в том, как я могу получить доступ к моим TabPane от Controller1

В целом. Как мы получаем Node в Javafx.

Редактировать View1

<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

В общем, вы просто не должны обращаться к элементам управления с одного вида в контроллере для другого вида. Вместо этого измените некоторые наблюдаемые данные и понаблюдайте за теми данными, где вам нужно. Если вы можете [изменить] свой вопрос с помощью [MCVE], демонстрирующего проблему, было бы легче дать реальный ответ здесь. –

+0

Спасибо за редактирование, но можете ли вы проверить его и исправить опечатки? Не следует ли 'openView1()' быть 'openView2()'?И я предполагаю, что 'mainController' в MainView должен быть' MainController'? –

ответ

2

Вы должны создать «модель представления», которая инкапсулирует текущее состояние представления и делится им с каждым из контроллеров. Затем наблюдайте его от вашего основного контроллера и отвечайте соответствующим образом.

Например:

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

Теперь вы можете сделать (обратите внимание, я также удалил свой избыточный повторяющийся код здесь):

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


} 

Теперь ваши контроллеры просто сделать:

public class Controller1{ 

    private final ApplicationState appState ; 

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

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

Обратите внимание, что поскольку контроллеры не имеют конструкторов no-arg, я устанавливаю их в код с помощью loader.setController(...). Это означает, что вам нужно удалить атрибут fx:controller из файлов fxml для view1 и view2, например. ваш View1.fxml становится:

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

Преимущество этой конструкции состоит в том, что, когда ваш босс заходит в ваш офис в 8 месяцев, и говорит, что «клиент не любит вкладку панели, заменить его чем-то, что только показывает по одному экрану за раз », очень легко сделать такие изменения, поскольку все правильно развязано. (Вам просто нужно было бы изменить основной вид и его контроллер, ни один из других видов или контроллеров не изменился бы вообще.) Если вы открыли панель вкладок всем другим контроллерам, вам нужно было бы найти все места, к которым вы обращались он должен вносить такие изменения.

+0

В некоторых аспектах JavaFX может отсутствовать, но имхо лучше всего это то, что он каким-то образом заставляет вас использовать модель MVC. – m0skit0

+0

Очень впечатляет –

+0

@ m0skit0 Да (по крайней мере один из MVC/MVP/MVVM/etc). Дизайн большой картинки очень хорош, даже если некоторые детали могут использовать некоторую настройку. Вероятно, это хороший знак, в долгосрочной перспективе. –

Смежные вопросы