swing

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

ComponentDrag  SupportDrop  Support
JColorChooserYesYes
JEditorPaneYesYes
JFileChooserYesNo
JFormattedTextFieldYesYes
JLabelClick to seeClick to see
JListYesNo
JPasswordFieldNoYes
JTableYesNo
JTextAreaYesYes
JTextFieldYesYes
JTextPaneYesYes
JTreeYesNo

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.

Drag and drop block diagram.

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.

JTree component contains drives, folders and .txt files in hierarchical fashion.

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.

JTextArea and JTextField as drop target.

One JList component is added to the right of the JTextArea .

JList component as drag source for default drag and drop display.

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.

.txt files dragged on to JTextArea showing content.

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.

Default drag and drop operation.

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

Download
You can download the full source code of this example here: Swing Drag and Drop Example.

Koushik Sanyal

Koushik Sanyal is a resident of a small town Uttarpara, in the suburbs of Kolkata (erstwhile Calcutta) which is one of the biggest cities in India and capital of the state of ‘West Bengal’. He completed Diploma in Information Technology from DoEACC Society (Currently NIELIT), a government of India run autonomous society dedicated for pertaining training in Information Technology. He has spent more than 11 years in IT professional domain as Trainer, Software Developer and Senior Software Developer. Currently he's working as a ‘Senior Software Developer’ in java domain at ‘Greenfield Software Pvt. Ltd in Kolkata, India.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button