1

Add Note: While I didn't find a clean solution to my stated problem, the root issue turned out to be that I was attempting to solve the "wrong problem". This is due to the timing of when initialize() is being called on the different JavaFX objects, and got ugly quickly (i.e., what happens if/when GridPane accesses Tab before the appropriate value(s) are set on Tab?). The real solution was to step back, reassess the implementation, and use setUserData() on GridPane from Tab, after Tab's values were correctly populated. Still a bit of a kludge, but much cleaner and reliable than what I was originally attempting, which was requiring the solution asked for below.

I am adding a GridPane to a Tab, and I need to access Tab.getText(). In the GridPane's initialize(), I can get the Parent using GridPane.getParent(). But, Parent doesn't implement getText(), and I cannot do ( Tab )Parent, nor use instanceof.

I've found mechanisms for gaining access to GridPane's controller, but I really don't want to do that unless necessary (i.e., I'd like for the GridPane instance to do "the right thing" without having external prodding).

I know the code snippet below doesn't compile/run, but is there a clean way to accomplish the idea behind the code?

@FXML private GridPane gridPane;

@FXML
public void initialize() {
    Parent parent = gridPane.getParent();

    if (parent instanceof Tab) {
        String foo = (( Tab )parent).getText();
    }
}
SoCal
  • 801
  • 1
  • 10
  • 23
  • Possible duplicate of [JavaFX get access to a Tab or TabPane from a TabContent(Node)](http://stackoverflow.com/questions/33186784/javafx-get-access-to-a-tab-or-tabpane-from-a-tabcontentnode) – Elltz Sep 16 '16 at 05:24

3 Answers3

0

There's no particularly clean way to do this. Once the tab has been placed in a scene, etc, you can iterate up the node hierarchy until you find a tab pane, then iterate through the tab pane's list of tabs and see if the content matches the node. E.g.:

import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.stage.Stage;

public class TabPaneTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        TabPane pane = new TabPane();
        Tab tab = new Tab("Test tab");
        Label label = new Label("Test Label");
        tab.setContent(label);
        pane.getTabs().addAll(tab);


        primaryStage.setScene(new Scene(pane));
        primaryStage.show();

        for (Node n = label ; n != null ; n = n.getParent()) {
            if (n instanceof TabPane) {
                System.out.println("Found Tab Pane...");
                for (Tab t : ((TabPane)n).getTabs()) {
                    if (t.getContent() == label) {
                        System.out.println("Tab containing label: "+t.getText());
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

You probably want to find a better way to do this though. E.g. can you just inject the tab directly instead of (or as well as) injecting the grid pane. It seems that whatever you need to do should be handled at a level which "knows about" the tab anyway. At worst, you could set the user data of the grid pane to the text of the tab. But this feels like an x-y problem: you shouldn't need to do this at all.

Community
  • 1
  • 1
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Yes, this got ugly fairly quickly, and I determined I was barking up the wrong tree (although it still interests me). Bottom line is that there was a series of initializers involved, so the "parent" wasn't even populated, as the node was not being added to the parent until after it was created (i.e., after the child's initialize() had terminated, and too late to try to do what I was attempting). Since all of the UI components are built against a common data model, I'm managing the desired behavior by firing an event on the data model once the mods to the model are actually completed. – SoCal Sep 12 '16 at 21:45
0

Easiest way I've found to do this is just to create a subclass of Gridpane and feed it the Tab it's being added to when you construct it.

Sam Claus
  • 1,807
  • 23
  • 39
  • This would work if I has hand-rolling the GridPane. But, I'm attempting to go the FXML-route, and the issue ended up being a timing-of-initialize() thing (see comment above). – SoCal Sep 12 '16 at 21:54
0

It's been a while since I asked this, and I have since modified the implementation and this is no longer an issue.

The solution was to forgo declaring the controller in the FXML, and associating the controller to the FXMLLoader instance programmatically. This allows information to be passed to the GridPane's controller (either via constructor or other public methods) prior to the GridPane being loaded/instantiated.

Doing it this way, the required information is already resident in the controller and can be accessed during initialization.

Live and learn...

SoCal
  • 801
  • 1
  • 10
  • 23