JavaFX – drag and drop works differently in Java 11 than in Java 8
I wrote a program that uses the drag and drop function in JavaFX It works perfectly in JavaFX 8
In JavaFX 11, the drag and drop function fails: I don't get a different mouse cursor, I don't get a ghost image of the row I'm dragging, and there's a problem - they don't trigger the mouse release, and then trigger the drop every time I click on the table
This is the smallest runnable example that demonstrates the problems I face Running on the Java 8 JVM, it can run as needed It does not exist on the Java 11 JVM I'm on Ubuntu 18.04
I changed my code well to suit Java 11, but I don't know what I did wrong
Java version 11
java version "11.0.1" 2018-10-16 LTS Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS) Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS,mixed mode)
Java version 8
openjdk version "1.8.0_181" OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-1ubuntu0.18.04.1-b13) OpenJDK 64-Bit Server VM (build 25.181-b13,mixed mode)
DND11. java
import javafx.application.Application; import javafx.collections.FXCollections; import javafx.scene.Scene; import javafx.scene.control.SelectionMode; import javafx.scene.control.TableColumn; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.input.ClipboardContent; import javafx.scene.input.DataFormat; import javafx.scene.input.Dragboard; import javafx.scene.input.TransferMode; import javafx.stage.Stage; public class DND11 extends Application { public TableView<Person> getTable () { DataFormat DRAGGED_PERSON = new DataFormat ( "application/example-person" ); TableColumn <Person,String> firstNameColumn = new TableColumn <> ( "First Name" ); TableColumn <Person,String> LastNameColumn = new TableColumn <> ( "Last Name" ); firstNameColumn.setCellValueFactory( new PropertyValueFactory <Person,String>( "firstName" ) ); LastNameColumn.setCellValueFactory( new PropertyValueFactory <Person,String>( "lastName" ) ); TableView <Person> tableView = new TableView <> (); tableView.getColumns().addAll( firstNameColumn,LastNameColumn ); tableView.setColumnResizePolicy( TableView.CONSTRAINED_RESIZE_POLICY ); tableView.setEditable( false ); tableView.setItems( FXCollections.observableArrayList( Person.generatePersons ( 10 ) ) ); tableView.getSelectionModel().setSelectionMode( SelectionMode.MULTIPLE ); tableView.setRowFactory( tv -> { TableRow <Person> row = new TableRow <>(); row.setOnDragDetected( event -> { if ( !row.isEmpty() ) { Dragboard db = row.startDragAndDrop( TransferMode.COPY ); ClipboardContent cc = new ClipboardContent(); cc.put( DRAGGED_PERSON,row.getItem() ); tableView.getItems().remove( row.getItem() ); db.setContent( cc ); } }); row.setOnDragOver( event -> { Dragboard db = event.getDragboard(); event.acceptTransferModes( TransferMode.COPY ); }); row.setOnDragDropped( event -> { Dragboard db = event.getDragboard(); Person person = (Person)event.getDragboard().getContent( DRAGGED_PERSON ); if ( person != null ) { tableView.getItems().remove( person ); int dropIndex = row.getIndex(); tableView.getItems().add( dropIndex,person ); } event.setDropCompleted( true ); event.consume(); }); return row; }); return tableView; } @Override public void start ( Stage stage ) throws Exception { stage.setScene( new Scene( getTable(),800,400 ) ); stage.show(); } public static void main ( String[] args ) { launch( args ); } }
Person. java
import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Random; public class Person implements Serializable { private static final long serialVersionUID = 1L; private String firstName,lastName; public Person ( String firstName,String lastName ) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public static List <Person> generatePersons ( int number ) { List<Person> retMe = new ArrayList<Person> ( number ); for ( int k = 0; k < number; k++ ) { retMe.add ( new Person ( randomFirstName(),randomLastName() ) ); } return retMe; } private static Random rand = new Random(); private static String randomFirstName() { return firstNames [ Math.abs( rand.nextInt() ) % firstNames.length ]; } private static String randomLastName() { return lastNames [ Math.abs( rand.nextInt() ) % lastNames.length ]; } private static String[] firstNames = new String[] { "ANTON","ANTONE","ANTONIA","NTONIO","ANTONY","ANTWAN","ARCHIE","ARDEN","ARIEL","ARLEN","ARMAND","ARMANDO","ARNOLD","ARNOLDO","ARNULF","ARON","ARRON","ART","ARTHUR","ARTURO","DARRICK","DARRIN","DARRON","DARRYL","DARWIN","DARYL","DAVE","DAVID","DAVIS","DEAN",}; private static String[] lastNames = new String[] { "SMITH","JOHNSON","WILLIAMS","BROWN","JONES","MILLER","GARCIA","RODRIGUEZ","WILSON","MARTINEZ","ANDERSON","TAYLOR","THOMAS","HERNANDEZ","MOORE","MARTIN","JACKSON" }; }
Solution
Although drop and drop in JavaFX has a common API for all platforms (of course, as the rest of the API), its internal implementation depends on the platform and is completely different on windows, MAC or Linux
However, this should not be a problem when migrating from JavaFX 8 to JavaFX 11
The example released by OP works the same way as JavaFX 8 and 11 on windows and MAC. If this is not the case on Linux, it may be related to the changes made in the latest version of JavaFX for Linux
According to the releases note, in the important changes section, we can see:
Although this change is basically a two-line difference in JavaFX code and has not changed from the implementation details of DND, the GTK 3 implementation may have changed from GTK 2, and these changes have not been taken into account
It is reported that dialogs, windows or Wayland crashes have similar problems related to GTK
resolvent
So far, the only known solution to all these problems is to run the application using GTK 2, which can be set using the system property: JDK gtk. version.
Therefore, you can add this option on the command line:
java -Djdk.gtk.version=2 ...
Run the application
As stated in the comments, this seems to solve the drag and drop problem
Reporting issues
Of course, this confirms that this is a problem, so it should be submitted in the openjfx problem tracker to provide sample code and system details (operating system version, java version, JavaFX version...)