I have spent alot of time working on implementing more functionality of our JavaFX PDF Viewer. I recently added a drag and drop functionality to the viewer which enables the user to drag and drop a PDF file into the viewer to be decoded and displayed. This is very easy to implement in JavaFX so here is a short tutorial for you to follow.
In this article, we will create a simple scene, and add the DnD function which will only accept image files (jpeg, jpg ,png) . This file will them be displayed when dropped unto the application.
Drag and drop support requires several items.
1. Component that will accept the draggable objects.
In this example we will use a StackPane to accept the DnD function. Once the image has been dropped onto the StackPane the we will use an ImageView to display the image
The code for displaying the image will be
Image img = new Image("path_to_image");
ImageView imageView = new ImageView();
imageView.setImage(img);
2. Handling the DnD Events
There are different DnD events we can add to the StackPane. In this example we will add three events to the StackPane.
The first we will add is the setOnDragOver
stackPane.setOnDragOver(new EventHandler() {
@Override
public void handle(final DragEvent event) {
//Do something when an Object is dragged over the StackPane
}
});
We will add an event which will detect when a an object is dropped onto the StackPane. This will be the setOnDragDropped
contentPane.setOnDragDropped(new EventHandler() {
@Override
public void handle(final DragEvent event) {
//Do something when an object is dropped onto the StackPane
}
});
The last we will add is the setOnDragExited
contentPane.setOnDragExited(new EventHandler() {
@Override
public void handle(final DragEvent event) {
//Do something when an object exits the StackPane
}
});
3. Filter to control which types of file are supported
Since we only want our program to accept only images, we will want to accept specific file types (i.e. png, jpeg). In this case, when an object is dragged over the StackPane we will check if it is an image file, if not,we tell our program not to accept it. We will store any item which is being dragged to the StackPane in a DragBoard, we will then check if the object stored in the DragBoard is an image file type.
final Dragboard db = e.getDragboard();
final boolean isAccepted = db.getFiles().get(0).getName().toLowerCase().endsWith(".png")
|| db.getFiles().get(0).getName().toLowerCase().endsWith(".jpeg")
|| db.getFiles().get(0).getName().toLowerCase().endsWith(".jpg");
if (db.hasFiles() && isAccepted) {
//display the image file
} else {
e.consume();
}
Now we put this all together in a code example
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class DragAndDropExample extends Application {
ImageView imageView;
StackPane contentPane;
BorderPane layout;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Drag and Drop");
layout = new BorderPane();
contentPane = new StackPane();
Scene scene = new Scene(layout, 800, 800, Color.WHITE);
contentPane.setOnDragOver(new EventHandler() {
@Override
public void handle(final DragEvent event) {
mouseDragOver(event);
}
});
contentPane.setOnDragDropped(new EventHandler() {
@Override
public void handle(final DragEvent event) {
mouseDragDropped(event);
}
});
contentPane.setOnDragExited(new EventHandler() {
@Override
public void handle(final DragEvent event) {
contentPane.setStyle("-fx-border-color: #C6C6C6;");
}
});
layout.setCenter(contentPane);
primaryStage.setScene(scene);
primaryStage.show();
}
void addImage(Image i, StackPane pane){
imageView = new ImageView();
imageView.setImage(i);
pane.getChildren().add(imageView);
}
private void mouseDragDropped(final DragEvent e) {
final Dragboard db = e.getDragboard();
boolean success = false;
if (db.hasFiles()) {
success = true;
// Only get the first file from the list
final File file = db.getFiles().get(0);
Platform.runLater(new Runnable() {
@Override
public void run() {
System.out.println(file.getAbsolutePath());
try {
if(!contentPane.getChildren().isEmpty()){
contentPane.getChildren().remove(0);
}
Image img = new Image(new FileInputStream(file.getAbsolutePath()));
addImage(img, contentPane);
} catch (FileNotFoundException ex) {
Logger.getLogger(DragAndDropExample.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
e.setDropCompleted(success);
e.consume();
}
private void mouseDragOver(final DragEvent e) {
final Dragboard db = e.getDragboard();
final boolean isAccepted = db.getFiles().get(0).getName().toLowerCase().endsWith(".png")
|| db.getFiles().get(0).getName().toLowerCase().endsWith(".jpeg")
|| db.getFiles().get(0).getName().toLowerCase().endsWith(".jpg");
if (db.hasFiles()) {
if (isAccepted) {
contentPane.setStyle("-fx-border-color: red;"
+ "-fx-border-width: 5;"
+ "-fx-background-color: #C6C6C6;"
+ "-fx-border-style: solid;");
e.acceptTransferModes(TransferMode.COPY);
}
} else {
e.consume();
}
}
}
Now lets run the Application.
This image shows when we drag a non image file to the application | |
This image shows when we drag an image file to the application | |
This image shows when we drop the image file unto the application |
Hopefully you have found this quick guide useful.
Our software libraries allow you to
Convert PDF files to HTML |
Use PDF Forms in a web browser |
Convert PDF Documents to an image |
Work with PDF Documents in Java |
Read and write HEIC and other Image formats in Java |
Hi there Ernest.
Thanks for creating this tutorial! I was wondering, can’t you migrate to Java 8?. JavaFX8 with lambdas are a god send for event handling. Also for tutorials like this one. Methinks that for desktop applications like the PDF Reader you’re doing, there’s more agency to use the prefered JVM version, right?
Yes you’re definitely right Loïc. Lambda’s are really great for event handling. Make you write clean and short readable code. I did not use them specifically because not everyone reading this article might have migrated to Java8 yet. You can also check my article on Lambda Expression
thank you very much!!!!!Really helpful!!
Good post, but the drag event handlers should rather be in the form:
contentPane.setOnDragX(new EventHandler() {
@Override
public void handle(final DragEvent event) {
//call to method to handle mouseDragX event or codes to handle event
}
});
Thank you very much.