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 TextField
and 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();
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 TextAreaBehavior
internally TextAreaSkin
(as TextFieldBehavior
passed to the constructor TextFieldSkin
).
I would be grateful for any help in this matter.