Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In JavaFX how do I determine if the node gaining focus is a child node of myself?

Tags:

javafx

I'm working with a TableView in JavaFX. What I'd like to do is keep track of edits made to the table. When the user navigates away from the table, I want to check if there have been any edits, and if so, prompt the user to ask if they want to save their changes.

I have the TableView working, and I can track edits, and I can determine when the TableView loses focus (using a focusedProperty change listener).

However, the problem is that when a cell is clicked to edit, the focusedProperty change listener for the table fires (the editing cell gains focus, the table itself loses it). What I really want is a way to tell if, when focus changes, is it changing to a child node of the table (such as a column or cell) or something outside of the table (selecting a different tab on the parent GUI). But I don't want to have to add listeners to every other possible node one could click.

If I knew how to get the currently-focused item (haven't seen how to do that), I could call getParent() recursively and check if the TableView is in that list, and if so, I'd know it's a child. But I haven't seen a generic way to just get the currently focused node within an app.

There's no good generic way to iterate through children of the table, because getChildrenUnmodifiable() returns me Node() types (I suppose I could cast each to determine if they each had more children), or I'd have to go to TableColumns then cells from there (and check graphic for each cell).

I'd probably go with iterating through children recursively, casting as needed, and checking isFocused() at this point, barring a better solution. But I'm hoping someone here might have a better solution to this problem, and preferably a more generic solution.

like image 495
user1676075 Avatar asked Dec 16 '22 08:12

user1676075


2 Answers

You can get the currently focused node through the scene's getFocusOwner() or focusOwnerProperty(). As you say, traversing from the focused node up to the TableView is better.

    public void createTable() {
        TableView tableView = new TableView();
        tableView.focusedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
            if (oldValue && !newValue) {
                if (!isParent(tableView, tableView.getScene().getFocusOwner())) {
                    System.out.println("Saving changes.");
                }
            }
        });
    }

    public boolean isParent(Parent parent, Node child) {
        if (child == null) {
            return false;
        }
        Parent curr = child.getParent();
        while (curr != null) {
            if (curr == parent) {
                return true;
            }
            curr = curr.getParent();
        }
        return false;
    }
like image 135
Dean Wookey Avatar answered Feb 08 '23 23:02

Dean Wookey


I went with the search from a Node, casting to children and checking if the focused node was a child. It's not elegant - it certainly feels like there should be a better way. But here's the method I used to do so:

private boolean isChildFocused(javafx.scene.Parent parent)
{
    for (Node node : parent.getChildrenUnmodifiable())
    {
        if (node.isFocused())
        {
            return true;
        }
        else if (node instanceof javafx.scene.Parent)
        {
            if (isChildFocused((javafx.scene.Parent)node))
            {
                return true;
            }
        }
    }
    return false;
}

It seems to work fine (at least using a TableView as the root level parent), calling this when the focusedProperty() of the parent changes to false (via property change listener).

like image 33
user1676075 Avatar answered Feb 09 '23 00:02

user1676075