Drag-and-Drop in JavaFX (Draggable Icons), Part 1

Note:  You can get the complete code for this series from my github account.

Recently, I’ve been working on developing an app in Java.  As I did research, it appears that, although JavaFX has received a lot of attention from Oracle lately (especially with the releases of Java 7 and Java 8), many in the industry think Oracle’s devotion to their UI framework to be too little, too late.

But as I considered my development process, I decided I didn’t want to outsource my UI development to another language or framework.  So I decided to stick it out with JavaFX.

It’s been a good experience overall and, admittedly, JavaFX has surprised me.  The UI seems pretty stable and there are a significant number of controls available.  The framework is still a bit rough around the edges – no support for databound controls and (until recently) no support for dialogs, but there’s a community surrounding it that supports it, the development team is pretty active, and there’s other option that have appeared to fill some of those gaps (like ControlsFX).

As a long-time C++/QT programmer and relatively new to the Java scene, I wasn’t sure how I’d like working in Java, but I admit, I’ve really grown to love it.  It’s a great language that’s easy to develop in and works well across all platforms.

That said, I wanted to present the work I’ve done developing a drag-and-drop user interface in JavaFX because creating it taught me a lot about how JavaFX works and the value of writing custom controls.

To get a view of what I’ve developed (in a very early and rough stage), take a look at this:

I’ll also state, upfront, that I took a lot of inspiration from this really great couple of posts on writing custom controls and doing drag and drop in JavaFX.  Some code is going to look similar, as a result. 🙂

Anyway, my idea was to model Blender’s Node Editor.  I’ve always appreciated the way the user is rather intuitively allowed to interconnect nodes quickly and easily.

Blender’s node editor makes shader development intuitive and simple to follow.

I wanted to create something like that for my application for a variety of reasons.  Foremost was the idea that the user interface should directly represent the model that it presents.  My usual experience in developing user interfaces is that the data was typically abstracted from the view so much so that neither really had anything to do with the other.  A node-style UI, however, seems to be precisely the opposite idea:  That the data itself (and it’s relationships to other data) are directly and intuitively represented visually.

In developing this blog series, it has proven to be a bit more lengthy than I’d originally planned – partly because I’m not just explaining how certain features or classes work.  Rather I’m presenting this as a complete (albeit generally useless) application, from beginning to end.

Thus, the series is broken up across three specific application components, each with several posts devoted to it.  They are:

  • Draggable Icons (Parts 1, 2, 3, and 4)
  • Draggable Nodes (Part 1)
  • Linking Nodes

At the end of each component’s portion, I will post the complete code to that point, as I realize following the posts can be a bit tedious.

Setting up the Development Environment

To get started, my development environment consists of the following:

  • Eclipse (Luna)
  • JavaSE1.8
  • JavaFX2.2
  • SceneBuilder 2.0

Starting with an empty workspace in Eclipse Luna, the first thing to do is to create a new JavaFX project (File>New>Project… and select the new JavaFX project wizard), give the project a name and click finish.

The next step is to create a source folder alongside the default “src” folder called “resources”.  I like to place FXML, image, and css files there.  For this project, move the “application.css” file from the src folder to the resources folder.

Creating the Custom Controls

The custom control in JavaFX is a fantastic feature I’ve learned to appreciate.

The custom control method in JavaFX is flexible as it can be manipulated using FXML, CSS, and straight Java code.  The template I will provide here provides all of the code necessary to create a custom control and place it into an application using a .fxml file and a .java class file.

First, we need to create files for two custom controls.

Create these three classes in the src folder:
(File > New > Class…)Screenshot from 2015-02-14 22:40:03

  • DragIcon.java
  • DragIconType.java
  • RootLayout.Java

Then, create two FXML documents in the resources folder:
(File > New > Other… > JavaFX > New FXML Document)

  • RootLayout.fxml
  • DragIcon.fxml

Finally, add this template code to DragIcon.java and RootLayout.java:

public class [class name] extends AnchorPane{

    public [class name]() {

        FXMLLoader fxmlLoader = new FXMLLoader(
            getClass().getResource("/[class name].fxml")
        );

        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try {
            fxmlLoader.load();

        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    @FXML
    private void initialize() {
    }
}

You will also need to replace the AnchorPane tag code in both .fxml files with this template:


<fx:root fx:id="root_pane" type="javafx.scene.layout.AnchorPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">

Finally, make sure your main class appears as follows. Note I changed the size of the window to be 640 x 480, and added the line root.setCenter(new RootLayout()); after the try / catch block.

public class Main extends Application {
    
    @Override
    public void start(Stage primaryStage) {
        BorderPane root = new BorderPane();
        
        try {
            
            Scene scene = new Scene(root,640,480);
            scene.getStylesheets().add(getClass().getResource("/application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
            
        } catch(Exception e) {
            e.printStackTrace();
        }
        
        root.setCenter(new RootLayout());
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}>/code>

Now would be a good time to test the application. You should end up with an empty window.

Drag-and-Drop in JavaFX (Draggable Icons), Part 1