Channels ▼

Eric Bruno

Dr. Dobb's Bloggers

JavaFX 8: Combining Language Features, Part 2

June 02, 2014

In my previous blog, I began the creation of a File Manager written in JavaFX 8, which is part of Java SE 8. In this installment, we'll add the ability to move files around via drag-and-drop (something JavaFX easily implements), and open files for viewing and editing using JavaFX controls. This is a work in progress, and we'll refine this over the next blog or two to make this functionality even more useful. Let's begin with moving files.

JavaFX Drag-and-Drop

Since many developers still think of Java for server-side duties only, you may not realize just how capable JavaFX is in terms of client functionality. This includes drag-and-drop, which is very easy with JavaFX. Every Node object has the ability to be dragged from one container and dropped onto another. Although a lot of the mechanics are built-in to make it easy, you can still control what actually gets transferred.

For instance, in our File Manager application, I want to control what gets transferred depending on where a file is dropped: If it's dropped on a directory then the file itself gets transferred (moved) there via the filesystem. If the file is dropped on an editor (any editor configured on the running system), then I want the file contents to be transferred.

It turns out that implementing this differentiation is a cake walk with JavaFX, and Lambdas once again eliminate much of the code needed. Additionally, since drag-and-drop in JavaFX is built upon and analogous to mouse operations, the coding model is similar to what we've seen so far. Let's look at some of the changes in the code needed to support this (you can download the updated project here).

First, instead of adding Java Strings to each HeadList — representing file and directory names — we need to change them to JavaFX Text objects, which extend Node. Here's the snippet of the method populateList() with that change:


        for (File file : files) {
            if ( ! file.isHidden() ) {
                if ( file.isFile() ) {
                    Text source = new Text(file.getName());
                    results.add(source);
                }
                else if ( file.isDirectory() ) {
                    Text target = new Text("<" + file.getName()+">");
                    results.add(target);
                }
            }
        }            

Additionally, any place in the code that grabs items from the list and expects a String needs to be changed to something like this:


    Text item = (Text)list.getSelectionModel().getSelectedItem();
    String filename = item.getText();

Overall, this is not a major change.

The drag-and-drop model in JavaFX involves handling a few steps each from the point of view of the source (the item being dragged) and the target (where the item is dragged to, or dropped on). Here are the steps to implement:

Source:
—Drag Detected: the first step when a Node is dragged via the mouse
—Drag Done: the final step when the source node has been dropped on the target

Target:
—Drag Entered: occurs when the source first enters a drop target Node
—Drag Over: occurs repeatedly while the source is dragged over the target region
—Drag Exited: occurs when the source exits a drop target
—Drag Dropped: occurs when the source Node is dropped via the mouse on the target Node

The methods to handle these steps, as DragEvent object, are implemented as EventHandlers via Node methods setOnDragDetected, setOnDragDropped, and so on. Here's the slight change required to the code snippet above to set the DragEvent event handlers for the various Text Nodes created in our File Manager application:


    if ( file.isFile() ) {
        Text source = new Text(file.getName());
        source.setOnDragDetected(de -> { onDragDetected(de,source); });
        source.setOnDragDone(de -> { onDragDone(de,source); });
        results.add(source);
    }
    else if ( file.isDirectory() ) {
        Text target = new Text("<" + file.getName()+">");
        target.setOnDragOver(de -> { onDragOver(de,target); });
        target.setOnDragEntered(de -> { onDragEntered(de,target); });
        target.setOnDragExited(de -> { onDragExited(de,target); });
        target.setOnDragDropped(de -> { onDragDropped(de,target); });
        results.add(target);
    }

The code to start the drag-and-drop process is in onDragDetected, implemented for files (and not directories) in our File Manager application. Let's examine it now:


    private void onDragDetected(MouseEvent me, Text source) {
        // start a drag-and-drop gesture
        HeaderList sourceList = getParentHeaderList(source);
        String sourcePath = 
            constructPath( sourceList ) + stripDecorators( source.getText() );
        
        Dragboard db = source.startDragAndDrop(TransferMode.ANY);

        // Put the file contents or filename into the clipboard
        ClipboardContent content = new ClipboardContent();
        String fileContents = readFile( sourcePath );
        if ( fileContents == null ) 
            fileContents = source.getText();
        
        content.putString(fileContents);
        db.setContent(content);

        me.consume();
    }

First, we get a reference to the source Node's list and construct the complete file path. Next, we get a reference to the JavaFX Dragboard object, used to manage the actual data that gets dragged. In addition to data, you can provide an image to be displayed with the mouse cursor as the drag-and-drop proceeds, and define how the data is transferred. For instance, is the data copied, moved, or is the source and target linked in some way as a result?

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video