JavaFX:检索节点 [英] JavaFX: Retrieve a Node

查看:145
本文介绍了JavaFX:检索节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个 FXML 文件,每个文件代表一个视图,我们称之为 View1 View2 ,我已将每一个放在一个单独的标签中,( Tab1 Tab2 )在 TabPane 中。



现在在 Controller1 of View1 我有一个事件会切换 selectedItem 我的 TabPane Tab1 Tab2 。我的问题是如何从 Controller1



<访问我的 TabPane 一般而言。我们如何在 Javafx 中检索某个节点



编辑
View1

 < VBox fx:控制器= controllers.Controller1 > 
< Button onAction =#openView2/>
< / VBox>

Controller1

  public class Controller1 {
public void openView2(){
//我该怎么办
}
}

MainView

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

MainController

  public class MainController实现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自动生成的catch块
e.printStackTrace();
}
}

protected Tab createView1Tab()抛出IOException {
Tab tab = new Tab();
tab.setContent(FXMLLoader.load(getClass()。getResource(/ views / View1.fxml)));
返回标签;
}

protected Tab createView2Tab()抛出IOException {
Tab tab = new Tab();
tab.setContent(FXMLLoader.load(getClass()。getResource(/ views / View2.fxml)));
返回标签;
}
}


解决方案

你应创建一个视图模型,它封装视图的当前状态,并与每个控制器共享。然后从主控制器中观察并做出相应的响应。



例如:

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

现在你可以做(​​注意我也删除了多余的)这里重复的代码):

 公共类MainController实现Initializable {

@FXML
public TabPane tabPane;

private final ApplicationState appState = new ApplicationState();
私人最终地图< String,Tab> views = new HashMap<>();

@Override
public void initialize(URL arg0,ResourceBundle arg1){
try {
tabPane.getTabs()。add(createViewTab(View1,new控制器1(APPSTATE)));
tabPane.getTabs()。add(createViewTab(View2,new Controller2(appState)));
} catch(IOException e){
// TODO自动生成的catch块
e.printStackTrace();
}
appState.currentViewNameProperty()。addListener((obs,oldView,newView) - >
tabPane.getSelectionModel()。select(views.get(newView)));
appState.setCurrentViewName(View1);
}

protected Tab createViewTab(String viewName,Object controller)抛出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);
返回标签;
}


}

现在你的控制器只需要这样做:

  public class Controller1 {

private final ApplicationState appState;

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

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

请注意,由于控制器没有 - arg构造函数,我在代码中用 loader.setController(...)设置它们。这意味着您必须从view1和view2的fxml文件中删除 fx:controller 属性,例如你的View1.fxml变为:

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

这种设计的优势在于,当你的老板在8个月内走进办公室并说客户不喜欢选项卡窗格,将其替换为一次只显示一个屏幕的内容,因为所有内容都正确分离,所以很容易进行更改。 (您只需要更改主视图及其控制器,其他任何视图或控制器都不会发生任何变化。)如果将选项卡窗格暴露给所有其他控制器,则必须找到您访问过的所有位置它可以做出类似的改变。


I have two FXML documents each one represents a view, let's call them View1 and View2, and I have placed each one in a separate Tab, (Tab1 and Tab2) inside a TabPane.

Now in the Controller1 of View1 I have an event that will switch the selectedItem of my TabPane from Tab1 to Tab2. My question is how can I access my TabPane from Controller1

In general. How do we retrieve a certain Node in Javafx.

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

解决方案

You should create a "view model" which encapsulates the current state of the view, and share it with each of the controllers. Then observe it from your main controller and respond accordingly.

For example:

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

Now you can do (note I also removed your redundant repetitive code here):

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


}

Now your controllers just have to do:

public class Controller1{

    private final ApplicationState appState ;

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

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

Note that since the controllers don't have no-arg constructors, I am setting them in code with loader.setController(...). This means you have to remove the fx:controller attribute from the fxml files for view1 and view2, e.g. your View1.fxml becomes:

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

The advantage of this design is that when your boss walks into your office in 8 months and says "The customer doesn't like the tab pane, replace it with something that only shows one screen at a time", it's very easy to make changes like that as everything is properly decoupled. (You would only have to change the main view and its controller, none of the other views or controllers would change at all.) If you exposed the tab pane to all the other controllers, you would have to find all the places you had accessed it to make changes like that.

这篇关于JavaFX:检索节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆