Maxoudela
Maxoudela

Reputation: 2211

TextArea loose focus when using scrollBar

When you create a TextArea, you can listen to its "focusedProperty".

But if the user touch the inner scrollBar of the TextArea (if it's too small), the focus of the TextArea is lost (since the scrollBar has the focus).

But as far as I am concerned, the TextArea is still having the focus because the scrollBar are part or the TextArea and there's even no way of accessing them.

How can I hack the textArea so that I would detect when the user is using the scrollBar? I want to hack/create a focusedProperty that will return true when the user is typing text or using the scrollBar.

Upvotes: 1

Views: 336

Answers (2)

Tomas Mikula
Tomas Mikula

Reputation: 6537

Here is a variation on @James_D's answer, in case you need to be able to obtain the focus binding from his answer without having a reference to the scene, e.g. if you need to set up the bindings before the text area is added to the scene, are implementing a library, or just want to have your code less entangled.

This solution uses the EasyBind library for convenient selection of nested property (selecting focusOwnerProperty from the sceneProperty).

public static Binding<Boolean> containsFocus(Node node) {
    return EasyBind.monadic(node.sceneProperty())
            .flatMap(Scene::focusOwnerProperty)
            .map(owner -> {
                for (Node n = owner; n != null; n = n.getParent()) {
                    if (n == node) return true ;
                }
                return false ;
            })
            .orElse(false); // when node.getScene() is null
}

Upvotes: 1

James_D
James_D

Reputation: 209225

Observe the Scene's focusOwner property, and create a BooleanBinding that is true if it is a descendant of the text area and false otherwise:

import java.util.stream.IntStream;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TextAreaFocusTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        TextArea textArea = new TextArea();
        IntStream.rangeClosed(1, 200).forEach(i -> textArea.appendText(" "));
        IntStream.rangeClosed(1, 80).forEach(i -> textArea.appendText("\nLine "+i));
        Label label = new Label();
        TextField textField = new TextField();
        VBox root = new VBox(10, textArea, textField, label);
        Scene scene = new Scene(root, 400, 400);

        BooleanBinding focus = Bindings.createBooleanBinding(() -> {
            for (Node n = scene.getFocusOwner(); n!= null ; n=n.getParent()) {
                if (n == textArea) return true ;
            }
            return false ;
        }, scene.focusOwnerProperty());

        label.textProperty().bind(Bindings.when(focus).then("Focused").otherwise("Not Focused"));

        primaryStage.setScene(scene);
        primaryStage.show();        
    }

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

Upvotes: 1

Related Questions