Java Swing Drag and Drop Example
This example will help us to know about how to enable drag feature for different components and how to customize drag and drop feature for custom flavors.
1. Introduction
In case we wish to transfer data from one UI component (Where applicable) to another, one way to carry it out is cut+ paste or copy+ paste. In this case data first gets stored in the clipboard and then from the clipboard it gets transferred over to the other program.
Drag and drop facility is the other way to carry out transfer of information between two UI components (Where applicable). In this case clipboard is not used. In java swing based applications we can implement drag and drop feature to be used.
Drag and drop can be done within different UI components of the same application as well as it can happen between two different applications.
2. Technologies Used
- Java (jdk 1.6.x or higher will be fine)
- Eclipse ( Galileo or higher version is required)
3. Overview
The default drag and drop feature for different such UI components are described in the below table for more information.
3.1 Default Drag and drop support for different components
Component | Drag Support | Drop Support |
JColorChooser | Yes | Yes |
JEditorPane | Yes | Yes |
JFileChooser | Yes | No |
JFormattedTextField | Yes | Yes |
JLabel | Click to see | Click to see |
JList | Yes | No |
JPasswordField | No | Yes |
JTable | Yes | No |
JTextArea | Yes | Yes |
JTextField | Yes | Yes |
JTextPane | Yes | Yes |
JTree | Yes | No |
In order to implement Default drag support, the property dragEnabled
is required to be set to true
for the component wherever applicable. Otherwise default drag behavior won’t become active.
Unlike drag support, Default drop support is by default active and works as mentioned in the table above.
For cursor shapes please click on this link.
Data item Data Transfer Handler is the basic support required to transfer the data in and out of the component. That is how ‘Drag and Drop’ works.
In order to perform custom drag and drop, the derived classes of TransferHandler
class and implementation of Transferable
is required to be implemented in the code.
The drag and drop feature is described in the block as described below.
4. Description of the drag and drop feature in the example
4.1 Features of the Example
In the example shared below, we have one JTree
control. This control is populated with hierarchy of 3 levels. In the outer level, all drives of the system in which program is running will show. In the second level all directories inside the drives will appear. Lastly in the third level, all .txt
files will be visible. This JTree
component is added as a left component of a split panel.
As a right component of the split panel, one JTextArea
component is added in the center location and one JTextField
component is added in the top location.
One JList
component is added to the right of the JTextArea
.
If we choose a text file from JTree
and drag that to the JTextArea
, the program will try to open the file. The size and other validations will be done and after that the content will appear on the JTextArea
portion. For large files it might take a few seconds to generate output. This demonstrates the customized drag and drop feature.
If we choose any item from the JList
component and drag that over to the JTextBox
, the text will appear on the JTextBox
component. This will demonstrate the default drag and drop feature.
4.2 Description of the implementation.
Since default implementation of Transferable
interface to transfer file type object doesn’t exist, we need to have customized implementation of Transferable
interface. In the example from line# 1 – 49 the class definition is described. This class FileTransferable
contains 2 attributes, list of File
objects and array of DataFlavor
objects. File list is initialized by the File
object parameter passed on at the time of object creation and the DataFlavor
array is initialized by DataFlavor.javaFileListFlavor
value.
FileTransferable.java
package com.javacodegeeks.example.swing.dnd; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; public class FileTransferable implements Transferable { final private List files; final private DataFlavor[] flavors; /** * A drag-and-drop object for transfering a file. * @param file file to transfer -- this file should already exist, * otherwise it may not be accepted by drag targets. */ public FileTransferable(Collection files) { this.files = Collections.unmodifiableList( new ArrayList(files)); this.flavors = new DataFlavor[] { DataFlavor.javaFileListFlavor }; } public DataFlavor[] getTransferDataFlavors() { // TODO Auto-generated method stub return this.flavors; } public boolean isDataFlavorSupported(DataFlavor flavor) { // TODO Auto-generated method stub return DataFlavor.javaFileListFlavor.equals(flavor); } public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { // TODO Auto-generated method stub if (isDataFlavorSupported(flavor)) return this.files; else return null; } }
In order to support customized FileTransferable
implementation, customization of FileTransferHandler
class is also required. In the example from line# 1 – 36 the class definition of the class FileTransferHandler
which is derived from TransferHandler
is described. The class
FileTransferHandler
overrides methods viz. getSourceAction
and createTransferable
of the parent class. The method createTransferable
creates a file object using the lastSelectedPathComponent
attribute of the JTree
. This File object is added to a list and a FileTransferable
object is returned passing ‘File’ list as argument.
FileTransferHandler .java
package com.javacodegeeks.example.swing.dnd; import java.awt.datatransfer.Transferable; import java.io.File; import java.util.ArrayList; import javax.swing.JComponent; import javax.swing.JTree; import javax.swing.TransferHandler; import javax.swing.tree.DefaultMutableTreeNode; public class FileTransferHandler extends TransferHandler { /** * */ private static final long serialVersionUID = 4278824893466339483L; public int getSourceActions(JComponent Source){ return COPY_OR_MOVE; } protected Transferable createTransferable(JComponent source){ JTree tree = (JTree)source; DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent(); if(node == null) return null; File file = new File(node.getUserObject().toString()); ArrayList fileList = new ArrayList(); fileList.add(file); return new FileTransferable(fileList); } }
In order to customize drop operation, dropTarget
attribute of the target component must be populated with a customized DropTarget
object. In this case, from line# 60 – 99, for JTextArea
component, while setting the dropTarget
attribute, the drop method of DropTarget
object is overridden. This drop method accepts DropTargetDropEvent
type object. First of all, event object, acceptDrop
is set as COPY
. Then for that event object , getTransferData
method of FileTransferable
object is invoked with javaFileListFlavor
so that transferred File
type list is returned. Once the list is received, file is read and content is displayed.
SwingDnDExampleFrame.java
package com.javacodegeeks.example.swing.dnd; import java.awt.BorderLayout; import java.awt.datatransfer.DataFlavor; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDropEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; public class SwingDnDExampleFrame extends JFrame { /** * */ private static final long serialVersionUID = -224525322599947463L; public SwingDnDExampleFrame(){ JSplitPane splitPane = new JSplitPane(); splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT); splitPane.setDividerLocation(200); JTree driveTree = new JTree(getTreeStructure()); final JEditorPane content = new JEditorPane(); JScrollPane treeContent = new JScrollPane(driveTree); JScrollPane scrollContent = new JScrollPane(content); driveTree.setDragEnabled(true); driveTree.setTransferHandler(new FileTransferHandler()); JPanel panel = new JPanel(new BorderLayout()); JTextField fileName = new JTextField(); JList list = new JList(new String[]{"Asia","Europe","America","Africa"}); list.setDragEnabled(true); panel.add(fileName,BorderLayout.NORTH); panel.add(scrollContent, BorderLayout.CENTER); panel.add(list, BorderLayout.EAST); splitPane.setLeftComponent(treeContent); splitPane.setRightComponent(panel); content.setDropTarget(new DropTarget() { /** * */ private static final long serialVersionUID = -6418118605479053389L; @SuppressWarnings("unchecked") public synchronized void drop(DropTargetDropEvent evt) { try { evt.acceptDrop(DnDConstants.ACTION_COPY); List droppedFiles = (List) evt .getTransferable().getTransferData( DataFlavor.javaFileListFlavor); if(droppedFiles.size() > 1){ JOptionPane.showMessageDialog(content, "Sorry...can't handle more than one files together."); } else{ File droppedFile = droppedFiles.get(0); if(droppedFile.getName().endsWith(".txt")){ char[] contentBytes = readFile(droppedFile); if(contentBytes == null){ JOptionPane.showMessageDialog(content, "Sorry...file size is too long."); } else if(contentBytes.length == 0){ JOptionPane.showMessageDialog(content, "Sorry...file is empty."); } else{ content.setText(new String(contentBytes)); } } else{ JOptionPane.showMessageDialog(content, "Sorry...not a text file."); } } } catch (Exception ex) { ex.printStackTrace(); } } }); add(splitPane); pack(); } private char[] readFile(File inputFile){ BufferedReader inputReader = null; char[] content = null; long availableHeap = Runtime.getRuntime().freeMemory(); long fileSize = inputFile.length(); try { if(fileSize <= availableHeap){ content = new char[(int)inputFile.length()]; inputReader = new BufferedReader(new FileReader(inputFile)); inputReader.read(content); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return content; } private File[] getAllDrives(){ return File.listRoots(); } private ArrayList getAllDirectories(File file){ ArrayList directories = new ArrayList(); File[] allSub = file.listFiles(); if(allSub != null){ for(File sub: allSub){ if(sub.isDirectory()){ directories.add(sub); } } } return directories; } private ArrayList getAllTXTs(File directory){ ArrayList pdfs = new ArrayList(); File[] allSub = directory.listFiles(); if(allSub != null){ for(File sub: allSub){ if(sub.isFile() && sub.getName().endsWith(".txt")){ pdfs.add(sub); } } } return pdfs; } private DefaultMutableTreeNode getTreeStructure(){ File[] roots = getAllDrives(); DefaultMutableTreeNode allDrives = new DefaultMutableTreeNode("All Drives"); for(File root: roots){ DefaultMutableTreeNode drive = new DefaultMutableTreeNode(root); ArrayList folderNodes = getAllDirectories(root); for(File folderNode : folderNodes){ DefaultMutableTreeNode childDrive =new DefaultMutableTreeNode(folderNode.getName()); ArrayList txts = getAllTXTs(folderNode); for(File txt : txts){ childDrive.add(new DefaultMutableTreeNode(txt)); } drive.add(childDrive); } allDrives.add(drive); } return allDrives; } }
In order to enable drag operation, in lines 1 and 6 dragEnabled
attribute is set to true for JList
and JTree
components.
SwingDnDExampleFrame.java
driveTree.setDragEnabled(true); driveTree.setTransferHandler(new FileTransferHandler()); JPanel panel = new JPanel(new BorderLayout()); JTextField fileName = new JTextField(); JList list = new JList(new String[]{"Asia","Europe","America","Africa"}); list.setDragEnabled(true);
5. Summary
This example is used to describe default as well as customized drag and drop. We have considered 4 different types of components to describe. For rest of the components and further study, supplied links can be referred.
6. Download the Source Code
You can download the full source code of this example here: Swing Drag and Drop Example.