Search code examples
androidjavafxjavafxports

Textfield copy action on long hold (copy popup)


I have Textfield and I want to copy content of it on my android device.

If I run it as a windows desktop application I can select the text right click I got the popup menu with possible actions.

Is there anyway to get this popup menu also on Android?


Solution

  • The push and hold event can be easily simulated in JavaFX, as in this question.

    Once you get the initial event, all you need to do is call the ContextMenu from the TextField. Since TextField.getContextMenu() won't return the default one, you can either provide your own or try to get the default one.

    Getting the default one is a little bit more tricky, since it is part of the TextFieldBehavior class. It contains this method public void contextMenuRequested(ContextMenuEvent e);, so all you need to do is provide a ContextMenuEvent, and fire the event from the TextField.

    This is a quick implementation:

    public class BasicView extends View {
    
        public BasicView(String name) {
            super(name);
    
            TextField textField = new TextField();
    
            addPressAndHoldHandler(textField, Duration.seconds(1), event -> {
                Bounds bounds = textField.localToScreen(textField.getBoundsInLocal());
                textField.fireEvent(new ContextMenuEvent(ContextMenuEvent.CONTEXT_MENU_REQUESTED, 
                        0, 0, bounds.getMinX() + 10, bounds.getMaxY() + 10, false, null));
            });
    
            setCenter(new VBox(15.0, new Label("Push and hold for ContextMenu"), textField));
        }
    
        private void addPressAndHoldHandler(Node node, Duration holdTime, EventHandler<MouseEvent> handler) {
            class Wrapper<T> { 
                T content; 
            }
    
            Wrapper<MouseEvent> eventWrapper = new Wrapper<>();
    
            PauseTransition holdTimer = new PauseTransition(holdTime);
            holdTimer.setOnFinished(event -> handler.handle(eventWrapper.content));
    
            node.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
                eventWrapper.content = event;
                holdTimer.playFromStart();
            });
            node.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> holdTimer.stop());
            node.addEventHandler(MouseEvent.DRAG_DETECTED, event -> holdTimer.stop());
        }
    
        @Override
        protected void updateAppBar(AppBar appBar) {
            appBar.setTitleText("Push and Hold");
        }
    
    }
    

    On Desktop this is what you'll get:

    The good news is you don't need to modify the ContextMenu for Android, JavaFX has a custom one:

    Note the different menu items will change automatically based on the context, as in the Desktop popup.