JavaFX8, TextArea - dragging selected text

After hours of digging the code and browsing the web in search of a solution, I decided to post my problem here.

I am currently working using Java 8u45. I need to enable dragging selected text from TextFieldand TextArea. Although it works great for TextField, it's not for TextArea- the selection changes right before the drag and drop.

Below some working example - just select a piece of text and drag it somewhere, for example. To Notepad:

public class DnD extends Application
{
    private static final GridPane rootPane = new GridPane();
    private TextField textField;
    private TextArea textArea;

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

    @Override
    public void start( final Stage primaryStage )
    {
        primaryStage.setTitle( "Drag and Drop Application" );

        buildGui();

        installDnd();

        primaryStage.setScene( new Scene( rootPane, 400, 325 ) );
        primaryStage.show();
    }

    private void installDnd()
    {
        textField.setOnDragDetected( e -> {
            if( canDrag( textField, e ) )
            {
                Dragboard dragboard = textField.startDragAndDrop( TransferMode.COPY );
                putIntoDragboard( dragboard, textField.getSelectedText() );
                e.consume();
            }
        } );

        textArea.setOnDragDetected( e -> {
            if( canDrag( textArea, e ) )
            {
                Dragboard dragboard = textArea.startDragAndDrop( TransferMode.COPY );
                putIntoDragboard( dragboard, textArea.getSelectedText() );
                e.consume();
            }
        } );
    }

    private void putIntoDragboard( final Dragboard aDragboard, final String aText )
    {
        ClipboardContent content = new ClipboardContent();
        content.put( DataFormat.PLAIN_TEXT, aText );
        aDragboard.setContent( content );
    }

    private boolean canDrag( final HitInfo aHitInfo, final IndexRange aSelection, final String aSelectedText )
    {
        int insertionPoint = aHitInfo.getInsertionIndex();
        // Start drag only if started over selected text
        boolean dragOverText = aSelection.getStart() < insertionPoint && aSelection.getEnd() > insertionPoint;
        return dragOverText && !(aSelectedText == null || aSelectedText.length() == 0);
    }

    private boolean canDrag( final TextField aTextField, final MouseEvent aEvent )
    {
        TextFieldSkin skin = (TextFieldSkin)aTextField.getSkin();
        HitInfo insertionPointInfo = skin.getIndex( aEvent.getX(), aEvent.getY() );
        return canDrag( insertionPointInfo, aTextField.getSelection(), aTextField.getSelectedText() );
    }

    private boolean canDrag( final TextArea aTextArea, final MouseEvent aEvent )
    {
        TextAreaSkin skin = (TextAreaSkin)aTextArea.getSkin();
        HitInfo insertionPointInfo = skin.getIndex( aEvent.getX(), aEvent.getY() );
        return canDrag( insertionPointInfo, aTextArea.getSelection(), aTextArea.getSelectedText() );
    }

    private void buildGui()
    {
        textField = new TextField( "text field: sample text" );
        textArea = new TextArea( "text area: sample text" );
        rootPane.add( textField, 0, 0 );
        rootPane.add( textArea, 0, 1 );
    }
}

Is it possible to make it work without writing my own skin? It is impossible to replace TextAreaBehaviorinternally TextAreaSkin(as TextFieldBehaviorpassed to the constructor TextFieldSkin).

I would be grateful for any help in this matter.

+4

Source: https://habr.com/ru/post/1609796/


All Articles