Search code examples
javascrolljavafxtouchfocus

JavaFX TextField focusProperty lost on touchScrollEvent


I am showing a Keyboard if the user clicks into a my extended TextField with the code shown below. When scrolling with a mouse you don't loose the focus to the TextField, but when scrolling by touch the focus is lost - and keyboard dispears of course. Is there a way to get the same behavior on touchScroll as on mouseScroll? I don't want the keyboard to disapear if the user is scrolling with touch!

focusedProperty().addListener(new ChangeListener<Boolean>() {

        @Override
        public void changed(final ObservableValue<? extends Boolean> observable, final Boolean oldValue,
                final Boolean newValue) {

                KeyboardUtils.INSTANCE.setVisible(newValue);
        }
    });

Solution

  • This is pretty basic sir, when you are scrolling with a Touchscroll you definitely Touch a scrollable Pane area, and that Pane requestFocus()by the touch, so your TextField will loose its focus.

    so to solve it you send focus back to your TextField if you detect a touch either by using the Scrolling listener of that Pane or Node or go for setOnTouchStationary() or setOnTouchReleased(), to help tweak the visibility of your keyboard instead of lying on focus of your TextField.

    EDIT

    Try this

    Node lastFocusedNode =null; // lastly known node to have focus
    //now every node or child in your ScrollPane or Scrollable parent 
    //that you care about will have a focusable listener-including
    // your textfield
    textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
    @Override
    public void changed(
            ObservableValue<? extends Boolean> observable,
                    Boolean oldValue, Boolean newValue) {
                    if(!newValue){//if they loose focus
                        lastFocusedNode = textField;
                        //if they loose focus attach them to lastFocusedNode
                    }
                }
            });
     //the above saves you iterations
    

    then when your ScrollPane/scrollable Node Receives focus you set them to the lastFocusedNode since its just going to allow scrolling.

    sp.focusedProperty().addListener(new InvalidationListener() {               
                @Override
                public void invalidated(Observable observable) {
                    if (lastFocusedNode != null) {
                        lastFocusedNode.requestFocus();
                    }
                }
            });
    

    the above assumes your ScrollPane will just not do anything consuming aside from scrolling..

    if you ScrollPane/scrollable parent is not going with that assumption then you go with this approach-detect when the user scrolls after touching your content area of your Scrollable Node-this works only if user attempts to scroll after touching.

    //approach loaded
    final InvalidationListener lis = new InvalidationListener() {               
    @Override
    public void invalidated(Observable observable) {
        //here it is changing
        if(sp.isFocused())
            lastFocusedNode.requestFocus();//take the focus away
        }
    };
    

    using the above invalidation listener you set it on the hvalueProperty() and vvalueProperty() or your ScrollPane - which Scrollable parent are you using?

    sp.hvalueProperty().addListener(lis);
    sp.vvalueProperty().addListener(lis);
    

    then you are done. any of the above solution will cause No problemo

    EDIT 2

    from what i know TouchEvent is for Touch enabled computers, so maybe go with MouseEvent and you can detect Pane.setOnMousePressed(); etc etcc

    Hope it helps