Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dragging and dropping list view items between different javafx windows

Tags:

javafx-8

I've been wondering how you would be able to drag and drop list view items between 2 java fx windows.

The code that I used was

tilePane.setOnDragDropped((event) -> {
        Dragboard db = event.getDragboard();
        boolean success = false;
        if (db.hasString()) {
            TilePane pane = (TilePane) event.getGestureTarget();
            if (pane.getChildren().size() >= 10) {
                //error
            } else {
                ListView<Item> list = (ListView<Item>) event
                        .getGestureSource();
                addShopItem(pane, list.getSelectionModel()
                        .getSelectedItem());
                success = true;
            }
        }
        event.setDropCompleted(success);
        event.consume();
    });

Both the list view and tile pane used to be in one window but I've decided to make seperate them into different javafx windows so it would allow for more flexibility. One window has the list view and the other has the tilepane.

I would like to drag the list view item to the tilepane(other window) but this code no longer works because getGestureTarget() is null for different applications.

Thanks

like image 708
TopRS Avatar asked Dec 25 '22 05:12

TopRS


1 Answers

It does look like the gesture source and target both get set to null when the drag leaves the JavaFX application (e.g. moving it between two windows).

For the gesture source, you may need to manage that yourself by creating a property and setting its value in the onDragDetected handler.

The gesture target is surely just the tile pane to which you attached the onDragDropped listener. So I don't see that you need to access that from the event; though you could use the same technique.

Example:

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class DnDListViews extends Application {

    private int counter = 0 ;

    private final ObjectProperty<ListCell<String>> dragSource = new SimpleObjectProperty<>();

    @Override
    public void start(Stage primaryStage) {
        populateStage(primaryStage);
        primaryStage.show();

        Stage anotherStage = new Stage();
        populateStage(anotherStage);
        anotherStage.setX(primaryStage.getX() + 300);
        anotherStage.show();
    }

    private void populateStage(Stage stage) {
        ListView<String> listView = new ListView<>();
        for (int i=0; i<5; i++ ) {
            listView.getItems().add("Item "+(++counter));
        }

        listView.setCellFactory(lv -> {
           ListCell<String> cell = new ListCell<String>(){
               @Override
               public void updateItem(String item , boolean empty) {
                   super.updateItem(item, empty);
                   setText(item);
               }
           };

           cell.setOnDragDetected(event -> {
               if (! cell.isEmpty()) {
                   Dragboard db = cell.startDragAndDrop(TransferMode.MOVE);
                   ClipboardContent cc = new ClipboardContent();
                   cc.putString(cell.getItem());
                   db.setContent(cc);
                   dragSource.set(cell);
               }
           });

           cell.setOnDragOver(event -> {
               Dragboard db = event.getDragboard();
               if (db.hasString()) {
                   event.acceptTransferModes(TransferMode.MOVE);
               }
           });

           cell.setOnDragDone(event -> listView.getItems().remove(cell.getItem()));

           cell.setOnDragDropped(event -> {
               Dragboard db = event.getDragboard();
               if (db.hasString() && dragSource.get() != null) {
                   // in this example you could just do
                   // listView.getItems().add(db.getString());
                   // but more generally:

                   ListCell<String> dragSourceCell = dragSource.get();
                   listView.getItems().add(dragSourceCell.getItem());
                   event.setDropCompleted(true);
                   dragSource.set(null);
               } else {
                   event.setDropCompleted(false);
               }
           });

           return cell ;
        });

        BorderPane root = new BorderPane(listView);
        Scene scene = new Scene(root, 250, 450);
        stage.setScene(scene);

    }

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

If the dragboard supported attaching arbitrary object references for drag and drop within the same JVM (see JIRA request, and vote if so inclined) then this would be quite a bit easier...

like image 91
James_D Avatar answered Apr 24 '23 19:04

James_D