在JavaFX11中,拖放操作功能失效:我没有得到不同的鼠标光标,我没有得到我正在拖动的行的鬼图像,而且滴有问题 – 它们不会触发鼠标释放,然后每次我点击表格时触发掉落.
这是最小的可运行示例,它演示了我面临的问题.在Java 8 JVM上运行它可以根据需要运行.在Java 11 JVM上它没有.我在Ubuntu 18.04上.
我很好地改变我的代码以适应Java 11,但我不知道我做错了什么.
Java 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 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" }; }
解决方法
但是,从JavaFX 8迁移到JavaFX 11时,这不应该是一个问题.
OP发布的示例在Windows和Mac上与JavaFX 8和11的工作方式相同,如果在Linux上不是这种情况,则可能与最新版本的JavaFX for Linux中所做的更改有关.
根据releases note,在重要变更部分,我们可以看到:
Switch default GTK version to 3
JavaFX will now use GTK 3 by default on Linux platforms where the gtk3 library is present. Prior to JavaFX 11,the GTK 2 library was the default. This matches the default for AWT in JDK 11. See JDK-8198654 for more information.
虽然这个change基本上是JavaFX代码中的两行差异,并且没有从DND的实现细节改变,但GTK 3实现可能已经从GTK 2改变了,并且这些改变没有被考虑在内.
据报道,dialogs,windows或Wayland crashes与GTK有关的类似问题.
到目前为止,所有这些问题的唯一已知解决方法是使用GTK 2运行应用程序,可以使用系统属性设置:jdk.gtk.version.
因此可以在命令行上添加此选项:
java -Djdk.gtk.version=2 ...
运行应用程序.
报告问题
当然,这确认这是一个问题,因此它应该在OpenJFX问题tracker提交,提供重现它的示例代码,系统细节(操作系统版本,Java版本,JavaFX版本……).