禁止将项目放入同一个 TableView

Prohibit dropping items into the same TableView

我遇到了另一个 JavaFX 问题。为了让问题的故事尽可能简短:

我有两个 TableView,我想在各自的 TableView 中拖放项目。我现在遇到的问题是我可以将项目放在我从中获取它的同一个 TableView 中。事实并非如此,我想阻止这种情况。

有没有办法限制目标 table,如果可以,我该怎么办?

非常感谢您的帮助!

实现了 setOnDragOver 方法:

selectedParticipantsTable.setOnDragOver(new EventHandler<DragEvent>() {
        @Override
        public void handle(DragEvent event) {
            // data is dragged over the target 
            Dragboard db = event.getDragboard();

                if (db.hasContent(participantsDataFormat)){    

                    if(selectedParticipantsTableData.contains(db.getContent(participantsDataFormat)) != true){
                        event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
                    }
                    else
                    {
                        event.acceptTransferModes(TransferMode.NONE);
                    }
                }
            event.consume();
        }
    });

好的,我想我说得更进一步了。我创建了一个自己的 DataFormat 以将项目放入 DragBoard 的剪贴板中。现在的问题是 MetaData class 中的 SimpleStringProperties 不可序列化,我不知道如何正确执行此操作,因为当我将项目拖到另一个 TableView 上时,我总是得到一个 EOFExceptio。

有什么建议吗?

只能将可序列化对象放到拖板上的限制真是令人头疼。即使您使模型 class 可序列化(这很困难,因为 JavaFX 属性不可序列化,但并非不可能),它可能不会执行您想要的操作,因为您将在拖动时获得对象的副本而不是对原始对象的引用。

我唯一的解决方法基本上是将拖动的对象存储在一个实例变量中(如果放置代码与拖动代码在不同的 class 中,那么您需要更复杂的东西)。

这是一个 SSCCE,使用 Oracle 教程中的常用联系人 table:

import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class TwoTablesDragging extends Application {

    private static final String DRAGGING_PERSON_KEY = "dragging-person";
    private Person currentDraggedPerson ;

    @Override
    public void start(Stage primaryStage) {
        TableView<Person> contacts = createPersonTable();
        TableView<Person> selectedContacts = createPersonTable();
        contacts.getItems().addAll(
                new Person("Jacob", "Smith", "jacob.smith@example.com"),
                new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
                new Person("Ethan", "Williams", "ethan.williams@example.com"),
                new Person("Emma", "Jones", "emma.jones@example.com"),
                new Person("Michael", "Brown", "michael.brown@example.com")
        );
        HBox root = new HBox(10, contacts, selectedContacts);
        root.setPadding(new Insets(10));
        primaryStage.setScene(new Scene(root, 800, 600));
        primaryStage.show();
    }

    private void setUpDragAndDrop(TableView<Person> table) {

        // note: It's generally better to set drag detected on the table rows, using
        // a rowFactory, so you don't rely on selection. This is just a "quick and dirty"
        // approach for a demo
        table.setOnDragDetected(e -> {
            Dragboard db = table.startDragAndDrop(TransferMode.COPY_OR_MOVE);
            ClipboardContent content = new ClipboardContent();
            content.putString(DRAGGING_PERSON_KEY);
            db.setContent(content);
            currentDraggedPerson = table.getSelectionModel().getSelectedItem();
        });

        table.setOnDragOver(e -> {
            Dragboard db = e.getDragboard();
            if (DRAGGING_PERSON_KEY.equals(db.getString()) &&
                    ! table.getItems().contains(currentDraggedPerson)) {
                e.acceptTransferModes(TransferMode.MOVE);
            }
        });

        table.setOnDragDropped(e -> {
            Dragboard db = e.getDragboard();
            if (DRAGGING_PERSON_KEY.equals(db.getString())) {
                table.getItems().add(currentDraggedPerson);
                e.setDropCompleted(true);
            } else {
                e.setDropCompleted(false);
            }
        });

        table.setOnDragDone(e -> {
            if (e.getTransferMode() == TransferMode.MOVE) {
                table.getItems().remove(currentDraggedPerson);
                currentDraggedPerson = null ;
            }
        });
    }

    private TableView<Person> createPersonTable() {
        TableView<Person> table = new TableView<>();
        table.getColumns().add(column("First Name", Person::firstNameProperty, 100));
        table.getColumns().add(column("Last Name", Person::lastNameProperty, 100));
        table.getColumns().add(column("Email", Person::emailProperty, 175));
        setUpDragAndDrop(table);
        return table ;
    }

    private <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> prop, double width) {
        TableColumn<S,T> col = new TableColumn<>(title);
        col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
        col.setPrefWidth(width);
        return col ;
    }

    public static class Person {
        private StringProperty firstName = new SimpleStringProperty();
        private StringProperty lastName = new SimpleStringProperty();
        private StringProperty email = new SimpleStringProperty();

        public Person(String firstName, String lastName, String email) {
            setFirstName(firstName);
            setLastName(lastName);
            setEmail(email);
        }

        public final StringProperty firstNameProperty() {
            return this.firstName;
        }

        public final java.lang.String getFirstName() {
            return this.firstNameProperty().get();
        }

        public final void setFirstName(final java.lang.String firstName) {
            this.firstNameProperty().set(firstName);
        }

        public final StringProperty lastNameProperty() {
            return this.lastName;
        }

        public final java.lang.String getLastName() {
            return this.lastNameProperty().get();
        }

        public final void setLastName(final java.lang.String lastName) {
            this.lastNameProperty().set(lastName);
        }

        public final StringProperty emailProperty() {
            return this.email;
        }

        public final java.lang.String getEmail() {
            return this.emailProperty().get();
        }

        public final void setEmail(final java.lang.String email) {
            this.emailProperty().set(email);
        }


    }

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