JavaFX - 将一行从表格视图拖到文本区域中

JavaFX - drag a row from a tableview into a textarea

考虑 JavaFX 应用程序中的表视图。表格视图包含有关人员的数据:

id    firstname    lastname

1     John         Doe

tableview 的每一行都可以用来实例化一个 Person 对象:

new Person(Integer id, String firstname, String lastname).

这是我想要做的:

我想 select 表格视图中的其中一个人物,然后用鼠标将其拖到文本区域中。在文本区域内,我想打印字符串:

1 John Doe.

我知道我必须实现三个功能才能实现此目的:onDragDetected(), onDragOver() and onDragDropped()

我想从以下开始:

public void onDragDetected(DragEvent dragevent) {
    Person person = tvPersonData.getSelectionModel().getSelectedItem();
}

这行得通。但我必须以某种方式让我的 Person 进入 DragBoard 对象 (dragevent.getDragboard())。我想我知道。然后也许我的其他功能可以使用我的拖板中的任何内容。

有人可以帮我吗?

为了在DragAndDrop手势中使用自定义对象,您需要为对象定义自定义DataFormat

DataFormat personDataFormat = new DataFormat("com.package.Person");

您显然需要将 com.package.Person 替换为您为其创建的 class 的完整路径。

另请注意,为了将 class 用作 DataFormat,class 必须是 Serializable。这是通过在 Person 对象中实现 Serializable 接口来实现的:

class Person implements Serializable {}

另一件事要记住,JavaFX 属性不是 Serializable,所以如果您在 Person 对象中使用 StringProperty,这将不起作用;您需要创建一个包装器 class 来保存您需要的数据。


一旦您的 DataFormatPerson 实现了 Serializable,您就可以将 Person 对象复制到剪贴板,就像任何其他内容一样;你只需要为它指定 DataFormat:

ClipboardContent content = new ClipboardContent();
content.put(personDataFormat, tableView.getSelectionModel().getSelectedItem());

落入 TextArea 将是相似的。您将定义 DataFormat,然后根据需要添加要处理的代码:

Person droppedPerson = (Person) db.getContent(personDataFormat);
textArea.appendText(droppedPerson.getName() + "\n");

完整示例应用如下:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.Serializable;
import java.util.Arrays;

public class DragObject extends Application {

    private final TableView<Person> tableView = new TableView<>();
    private final TextArea textArea = new TextArea();

    public static void main(String[] args) {

        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        // **********************************************************************************************
        // Create a basic layout
        // **********************************************************************************************
        VBox root = new VBox(5);
        root.setAlignment(Pos.TOP_CENTER);
        root.setPadding(new Insets(10));

        // **********************************************************************************************
        // Configure a regular TableView
        // **********************************************************************************************
        configureTableView();

        tableView.setItems(sampleData());
        tableView.setPrefHeight(200);
        root.getChildren().add(tableView);

        root.getChildren().add(textArea);

        // **********************************************************************************************
        // This method will configure our drag-and-drop functionality
        // **********************************************************************************************
        initDragAndDrop();

        // **********************************************************************************************
        // Set the Scene for the stage
        // **********************************************************************************************
        primaryStage.setScene(new Scene(root));

        // **********************************************************************************************
        // Configure the Stage
        // **********************************************************************************************
        primaryStage.setTitle("Test Application");
        primaryStage.show();
    }

    private void configureTableView() {

        // **********************************************************************************************
        // Just a standard sample TableView
        // **********************************************************************************************

        TableColumn<Person, String> colName = new TableColumn<>("Name");
        TableColumn<Person, String> colEmail = new TableColumn<>("Email");

        colName.setCellValueFactory(new PropertyValueFactory<>("name"));
        colEmail.setCellValueFactory(new PropertyValueFactory<>("email"));

        tableView.getColumns().addAll(colName, colEmail);

    }

    private void initDragAndDrop() {

        DataFormat personDataFormat = new DataFormat("Person");

        // **********************************************************************************************
        // Add drag and drop to the TableView
        // **********************************************************************************************
        tableView.setOnDragDetected(event -> {
            // **********************************************************************************************
            // Drag was detected, allow any type of transfer
            // **********************************************************************************************
            Dragboard db = tableView.startDragAndDrop(TransferMode.ANY);

            // **********************************************************************************************
            // Add the selected Person to the clipboard, using our custom DataFormat
            // **********************************************************************************************
            ClipboardContent content = new ClipboardContent();
            content.put(personDataFormat, tableView.getSelectionModel().getSelectedItem());
            db.setContent(content);
        });

        // **********************************************************************************************
        // Add drag and drop to the TextArea
        // **********************************************************************************************
        textArea.setOnDragOver(event -> {

            // **********************************************************************************************
            // Person was dragged over the TextArea; accept it only if dragged from a node other than itself.
            // In this case, this condition isn't necessary, but still good practice
            // **********************************************************************************************
            if (event.getGestureSource() != textArea
                && event.getDragboard().hasContent(personDataFormat)) {

                // **********************************************************************************************
                // For this example, we'll allow ANY transfer type again
                // **********************************************************************************************
                event.acceptTransferModes(TransferMode.ANY);

            }

            // **********************************************************************************************
            // Consume the event. We'll handle placing content into the TextArea next
            // **********************************************************************************************
            event.consume();
        });

        // **********************************************************************************************
        // Add handler to the TextArea to accept a Person object that's been dropped and add the person's
        // name to the TextArea
        // **********************************************************************************************
        textArea.setOnDragDropped(event -> {

            // **********************************************************************************************
            // First, ensure the object being dropped was a Person object
            // **********************************************************************************************
            Dragboard db = event.getDragboard();
            boolean success = false;
            if (db.hasContent(personDataFormat)) {

                // **********************************************************************************************
                // Get a reference to the Person being dropped. Note that you need to 
                // cast the object to a Person so Java knows what object type you're 
                // working with.
                // **********************************************************************************************
                Person droppedPerson = (Person) db.getContent(personDataFormat);
                textArea.appendText(droppedPerson.getName() + "\n");

                success = true;
            }

            // **********************************************************************************************
            // Complete the event
            // **********************************************************************************************
            event.setDropCompleted(success);

            event.consume();
        });

    }

    private ObservableList<Person> sampleData() {
        // **********************************************************************************************
        // Just some sample Persons for our TableView
        // **********************************************************************************************
        return FXCollections.observableList(Arrays.asList(
                new Person("John Williams", "jwilliams@et.com"),
                new Person("Howard Shore", "hshore@shire.com"),
                new Person("Danny Elfman", "delfman@scissorpalace.org")));

    }
}

RESULT: