Wednesday, 9 March 2016

Drag and Drop from and to a File

The usual way of loading or saving data involves clicking a menu, opening a dialog box, navigating trough directories and choosing a file or typing a name. It wouldn't be more easy to just drag a file into my application and have it's contents loaded or the other way round, drag an image and have it saved?
So I started coding, building an application, JavaFX, just to prove the concept. The application consists of just a pane with an image. Dragging a file into it is accepted if the file contains a valid image and the image is loaded and displayed. Dragging from it to a folder creates a new file saving the previously loaded image to it.
To save the image to a file two events are caught. First on drag detected a temporary file is created with the image's contents. Then on drag done either nothing needs to be done if the image was already moved by the OS or the file is deleted if the drag was canceled to avoid cluttering the temporary folder.
To load the image other two events are caught. First on drag over the file is validated, then on drag dropped the file is read into an Image and the Image is displayed.


import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * Test drag and drop in both directions from a file to an image.
 * 
 * @author António Raposo
 */
public class DragDropJavafx extends Application {

@Override
public void start(Stage primaryStage) {
ImageView image = new ImageView();
StackPane myPane = new StackPane();
myPane.getChildren().add(image);

// starting drag and drop from the pane
myPane.setOnDragDetected(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
// create a new file object representing a temporary file and
// put it in the dragboard. create the temporary file and save
// the image to it.
Dragboard db = myPane.startDragAndDrop(TransferMode.ANY);
ClipboardContent content = new ClipboardContent();
File tempFile = new File(System.getProperty("java.io.tmpdir"), "test_image.png");
BufferedImage bImage = SwingFXUtils.fromFXImage(image.getImage(), null);
try {
ImageIO.write(bImage, "png", tempFile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
content.putFiles(Arrays.asList(tempFile));
db.setContent(content);
event.consume();
}
});

// completing drag and drop from the pane
myPane.setOnDragDone(new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent event) {
// if the transfer is not accepted delete the temporary file.
if (!event.isAccepted()) {
Dragboard db = event.getDragboard();
List<File> files = db.getFiles();
if (files != null && !files.isEmpty()) {
files.get(0).delete();
}
}
event.consume();
}
});

// accepting drag and drop to the pane
myPane.setOnDragOver(new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent event) {
// the first step is when the mouse enters the target. accept
// copy or move of one file into the target
if (event.getGestureSource() != myPane && event.getDragboard().hasFiles()
&& event.getDragboard().getFiles().size() == 1) {
if (!new Image(event.getDragboard().getFiles().get(0).toURI().toString()).isError()) {
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
}
event.consume();
}
});

// accepting drag and drop to the pane
myPane.setOnDragDropped(new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent event) {
// complete the drag and drop event reading the dropped file.
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasFiles()) {
List<File> files = db.getFiles();
if (files != null && !files.isEmpty()) {
image.setImage(new Image(files.get(0).toURI().toString()));
}
}
event.setDropCompleted(success);
event.consume();
}
});

Scene myScene = new Scene(myPane);
primaryStage.setScene(myScene);
primaryStage.setWidth(400);
primaryStage.setHeight(300);
primaryStage.show();
}

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

}

No comments:

Post a Comment