JavaFX Scene Builder——在父节点之间拖放

JavaFX Scene Builder -- Drag-And-Drop Between Parent Nodes

我正在使用 FXML 和 Scene Builder 来开发一个非常简单的界面。下面,第一张图片代表布局层次结构。按下按钮时,第二个图像显示一个文本区域。

动作事件方法实例化一个新的文本区域并将其分配给第一个流程窗格(从左到右)。我的目标是将每个文本区域拖放到任何其他流程窗格中。

我的第一次尝试是使用事件处理程序来检测 MOUSE_PRESSED:textArea.addEventHandler(MouseEvent.DRAG_DETECTED, e-> handle(e));

当我开始设置 handle 方法时,事情变得很混乱。例如,我是否应该包括其他各种 MouseEvent,例如 MOUSE_EXITED_TARGET、MOUSE_ENTERED_TARGET? MOUSE_RELEASED 句柄是如何组成的?

我开始查看 Dragboard 和 Clipboard,但也没有找到太多运气。剪贴板似乎只能处理字符串值,或者以一种迂回的方式处理图像。我确信我的困境有一个简单的答案,因为它清楚地表明我正在探索未知领域。

我通读了几个 "textbook" 资源,但它们都解决了在运行时构造的对象的移动问题,并且大多数都符合看似通用或简单的示例。

注意 我为这些图像道歉,我意识到它不是很清楚。整个网格窗格分布有 5 个流程窗格。我会尽快编辑更新。

所以我了解到您正在尝试将 TextAreas 拖放到不同的 FlowPanes。您可以使用 DragEvents 而不是 MouseEvents 来实现此目的。这是一个例子:

考虑像您这样的简单布局,仅考虑 TextArea 和两个 FlowPanes,我们将有以下字段:

@FXML
private TextArea textArea;

@FXML
private FlowPane flowPane1;

@FXML
private FlowPane flowPane2;

开始时,textArea 位于 flowPane1 上,在 GridLayout 的左侧。

我们想将“textArea”拖放到右侧 flowPane。所以首先,我们必须告诉 textArea 它应该是可拖动的。在这种情况下,移动。您可以用不同的方式实现它,但在这里我将向您展示如何将现有的 TextArea 移动到另一个 FlowPane。另一种方法是重新创建一个上面有文字的方法。

textArea.setOnDragDetected((MouseEvent event) -> {
    //We want the textArea to be dragged. Could also be copied.
    Dragboard db = textArea.startDragAndDrop(TransferMode.MOVE);

    // Put a string on a dragboard as an identifier
    ClipboardContent content = new ClipboardContent();
    content.putString(textArea.getId());
    db.setContent(content);

    //Consume the event
    event.consume();
});

然后,我们希望 flowPane2textArea 被拖到时接受它。所以首先,我们告诉它在被拖过来时接受 textArea。

flowPane2.addEventHandler(DragEvent.DRAG_OVER, (DragEvent event) -> {
    if (event.getGestureSource() != flowPane2
            && event.getDragboard().hasString()) {
        event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
    }
    event.consume();
});

在我们允许它被拖动之后,我们确实希望它能真正做一些事情并在被放下时接受它。所以我们添加另一个处理程序来接受丢弃的 textArea.

flowPane2.addEventHandler(DragEvent.DRAG_DROPPED, (DragEvent event) -> {
    //Get the dragboard back
    Dragboard db = event.getDragboard();
    boolean success = false;
    //Could have some more thorough checks of course.
    if (db.hasString()) {
        //Get the textarea and place it into flowPane2 instead
        flowPane2.getChildren().add(textArea);
        success = true;
    }
    //Complete and consume the event.
    event.setDropCompleted(success);
    event.consume();
});

结果,textArea可以从flowPane1移动到flowPane2。反之亦然,但这会让你继续前进!