tic final DataFlavor objectsFlavor = new DataFlavor( DraggedObjects.class, "Objects" );
public Object getTransferData( DataFlavor flavor )
{
if (flavor.equals( objectsFlavor ))
return this;
else if (flavor.equals( DataFlavor.stringFlavor ) )
return this.toString();
return null;
}
public DataFlavor[] getTransferDataFlavors()
{
return new DataFlavor[] { objectsFlavor, DataFlavor.stringFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor)
{
return (flavor.equals( objectsFlavor ) || flavor.equals( DataFlavor.stringFlavor ));
}
}
}
Just select a node and click on it again. You should see an edit box displayed. Then edit the name of one of the nodes. If you press enter, the name change is committed. If you press escape, the rename is aborted. If you click the mouse on a different node, the rename is aborted. That's the problem. Clicking on another node should commit the change not abort the change.
In addition, when the tree starts a name edit, the text in the edit box should be selected and it is not.
======================================================================
Name: rv122619 Date: 03/23/2004
In a JTree, start editing a node. When the user clicks outside of the edit area on another node, the edit should be stopped which commits the changes as opposed to cancelled. In addition, the user should be able to click anywhere in the JTree not just on another node.
/**
* Title: MainFrame.java
* Description:
* Copyright: Copyright (c) 2002
*/
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
/*
*
*
*
*
*/
public class MainFrame extends JFrame
{
private AbstractAction m_actFile;
private AbstractAction m_actExit;
private JTree m_tree;
private DefaultTreeModel m_mdl;
private DragSourceListener m_lsnrDragSource;
private DragSource m_dragSource;
public MainFrame()
{
setDefaultCloseOperation( EXIT_ON_CLOSE );
initialize();
setLocation( new Point( 200, 200 ) );
setSize( new Dimension( 550, 250 ) );
}
private void initialize()
{
setTitle( "Drag And Drop Test" );
createActions();
createMainMenu();
createContents();
createListeners();
}
private void createActions()
{
m_actFile = new cFileAction();
m_actExit = new cExitAction();
}
private void createListeners()
{
m_dragSource = new DragSource();
m_dragSource.createDefaultDragGestureRecognizer( m_tree, DnDConstants.ACTION_COPY_OR_MOVE, new cDragGestureListener() );
m_lsnrDragSource = new cDragSourceListener();
new DropTarget( m_tree, DnDConstants.ACTION_COPY_OR_MOVE, new cDropTargetListener() );
}
private void createMainMenu()
{
JMenuBar menuMain = new JMenuBar();
JMenu menuFile = new JMenu( m_actFile );
menuFile.add( m_actExit );
menuMain.add( menuFile );
setJMenuBar( menuMain );
}
private void createContents()
{
m_tree = new JTree();
m_mdl = (DefaultTreeModel) m_tree.getModel();
expand( m_tree, (TreeNode) m_mdl.getRoot() );
m_tree.getSelectionModel().setSelectionMode( TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION );
m_tree.setAutoscrolls( true );
JScrollPane scrTree = new JScrollPane( m_tree );
JPanel pnlContents = (JPanel) getContentPane();
pnlContents.setLayout( new GridBagLayout() );
pnlContents.add( scrTree, new GridBagConstraints( 0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets( 0, 0, 0, 0 ), 0, 0 ) );
}
private void expand( JTree tree, TreeNode node )
{
if (node.isLeaf())
return;
TreeNode[] aPathNodes = ((DefaultTreeModel) m_tree.getModel()).getPathToRoot( node );
tree.expandPath( new TreePath( aPathNodes ) );
for ( int iChild=0; iChild<node.getChildCount(); iChild++ )
expand( tree, node.getChildAt( iChild ) );
}
public static void main( String[] saArgs )
{
// set the UI to the system UI
try
{
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
}
catch (ClassNotFoundException e) {}
catch (IllegalAccessException e) {}
catch (InstantiationException e) {}
catch (UnsupportedLookAndFeelException e) {}
// create the main frame and show it
MainFrame f = new MainFrame();
f.setVisible( true );
}
//---------------------------------------------------------------------------
// Actions
//---------------------------------------------------------------------------
protected class cFileAction extends AbstractAction
{
public cFileAction()
{
putValue( AbstractAction.NAME, "File" );
putValue( AbstractAction.SHORT_DESCRIPTION, "Files" );
putValue( AbstractAction.MNEMONIC_KEY, new Integer( 'F' ) );
putValue( AbstractAction.SMALL_ICON, null );
}
public void actionPerformed( ActionEvent e )
{
}
} // cFileAction
protected class cExitAction extends AbstractAction
{
public cExitAction()
{
putValue( AbstractAction.NAME, "Exit" );
putValue( AbstractAction.SHORT_DESCRIPTION, "Exits" );
putValue( AbstractAction.MNEMONIC_KEY, new Integer( 'x' ) );
putValue( AbstractAction.SMALL_ICON, null );
}
public void actionPerformed( ActionEvent e )
{
// there should be a better way to do this but there is no close
// and this seems to be what the system exit menu does, so ...
MainFrame.this.dispatchEvent( new WindowEvent( MainFrame.this, WindowEvent.WINDOW_CLOSING ) );
}
} // cExitAction
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
protected class cDragGestureListener implements DragGestureListener
{
public void dragGestureRecognized(DragGestureEvent event)
{
TreePath[] aSelectedPaths = m_tree.getSelectionPaths();
if (aSelectedPaths.length != 0)
{
DraggedObjects draggedObjects = new DraggedObjects();
for ( int iSelectedPath=0; iSelectedPath < aSelectedPaths.length; iSelectedPath++ )
{
TreeNode node = (TreeNode) aSelectedPaths[ iSelectedPath ].getLastPathComponent();
if (!node.isLeaf())
return;
System.out.println( "Dragging " + node );
draggedObjects.add( node );
}
m_dragSource.startDrag( event,
DragSource.DefaultCopyDrop,
// image, new Point( 0, 0 ),
draggedObjects, m_lsnrDragSource );
}
}
} // cDragGestureListener
protected class cDragSourceListener implements DragSourceListener
{
/**
* Handles the drag operation termination event. This event occurs for
* all types of termination (accepted drops, rejected drops, and
* terminations that occur outside of any drop target). This event is
* handled by changing the dragging flag back to false.
*
* @param e the drag event for the drag source
*/
public void dragDropEnd( DragSourceDropEvent e )
{
// System.out.println( "drag source end" );
}
/**
* Handles the drag entering a drop target event. This event is handled
* by doing nothing.
*
* @param e the drag event for the drag source
*/
public void dragEnter( DragSourceDragEvent e )
{
// System.out.println( "drag source enter" );
}
/**
* Handles the drag exiting a drop target event. This event is handled by
* doing nothing.
*
* @param e the event for the drag source
*/
public void dragExit( DragSourceEvent event )
{
// System.out.println( "drag source exit" );
}
/**
* Handles the drag over the drop target event. This event is handled by
* doing nothing.
*
* @param e the drag event for the drag source
*/
public void dragOver( DragSourceDragEvent e )
{
// System.out.println( "drag source over" );
}
/**
* Handles the drop action being changed by the user (by changing the drag
* gesture). This event is handled by doing nothing.
*
* @param e the drag event for the drag source
*/
public void dropActionChanged( DragSourceDragEvent e )
{
// System.out.println( "drag source action changed" );
}
}
//---------------------------------------------------------------------------
// cDropTargetListener - handles drop target events by checking to make sure
// the drag operation is over a node that can be a drop
// target.
//---------------------------------------------------------------------------
protected class cDropTargetListener implements DropTargetListener
{
protected boolean m_bFirstDragOver; // true = next DragOver is first DragOver
// for drag cursor kludge
protected TreePath[] m_aOriginalSelectedPaths; // the originally selected paths
/**
* Handles the drag operation entering the drop target event. The event
* is handled by selecting the node (if any) over which the drag occurred.
* The drag is accepted if the drag is over a node that can be a drop
* target.
*
* @param e the drag entering the drop target event.
*/
public void dragEnter( DropTargetDragEvent e )
{
// System.out.println( "drop target enter" );
// save the originally selected path
m_aOriginalSelectedPaths = m_tree.getSelectionPaths();
// get and select the node that drag event is over
Point pt = e.getLocation();
TreePath path = m_tree.getPathForLocation( pt.x, pt.y );
m_tree.setSelectionPath( path );
// if not over any node, reject
if (path == null)
e.rejectDrag();
// otherwise, ...
else
{
// if the node is not a drop target, reject
// otherwise, accept
TreeNode node = (TreeNode) path.getLastPathComponent();
if (node.isLeaf() || m_mdl.getRoot() == node)
{
System.out.println( "drag rejected in enter" );
e.rejectDrag();
}
else
{
System.out.println( "drag accepted in enter" );
e.acceptDrag( e.getSourceActions() );
}
}
}
/**
* Handles the event that the drag operation has exited the drop target.
* The event is handled by reselecting the originally selected paths.
*
* @param e the drop target event
*/
public void dragExit( DropTargetEvent e )
{
// System.out.println( "drop target exit" );
m_tree.setSelectionPaths( m_aOriginalSelectedPaths );
}
/**
* Handles the drag over the drop target event. The event is handled by
* by selecting the node (if any) over which the drag occurred. The drag
* is accepted if the drag is over a node that can be a drop target.
*
* @param e the drag over the drop target event.
*/
public void dragOver( DropTargetDragEvent e )
{
// System.out.println( "drop target drag over" );
// get and select the node that drag event is over
Point pt = e.getLocation();
TreePath path = m_tree.getPathForLocation( pt.x, pt.y );
if (!m_tree.isPathSelected( path ))
m_tree.setSelectionPath( path );
// if not over any node, reject
if (path == null)
e.rejectDrag();
// otherwise, ...
else
{
// if the node is not a drop target, reject
// otherwise, accept
TreeNode node = (TreeNode) path.getLastPathComponent();
if (node.isLeaf() || m_mdl.getRoot() == node)
{
System.out.println( "drag rejected in over" );
e.rejectDrag();
}
else
{
System.out.println( "drag accepted in over" );
e.acceptDrag( e.getSourceActions() );
}
}
}
/**
* Handles the event when the drag operation has terminated with a drop on
* the drop target. The event is handled by by selecting the node (if
* any) on which the drop occurred. The drop is accepted if the drop is
* on a node that can be a drop target. The node is then notified of the
* drop.
*
* @param e the drop event on the drop target
*/
public void drop( DropTargetDropEvent e )
{
// System.out.println( "drop target drop" );
// get and select the node that drag event is over
Point pt = e.getLocation();
TreePath path = m_tree.getPathForLocation( pt.x, pt.y );
if (!m_tree.isPathSelected( path ))
m_tree.setSelectionPath( path );
// if not over any node, reject
if (path == null)
e.rejectDrop();
// otherwise, ...
else
{
// if the node is a drop target, accept and notify the node of the drop
// otherwise, reject
// if the node is not a drop target, reject
// otherwise, accept
TreeNode node = (TreeNode) path.getLastPathComponent();
if (node.isLeaf() || m_mdl.getRoot() == node)
{
System.out.println( "Drop rejected" );
e.rejectDrop();
}
else
{
e.acceptDrop( e.getSourceActions() );
System.out.println( "Dropped on " + node );
e.dropComplete( true );
}
}
}
/**
* Handles the event when the user changes the current drop gesture. The
* event is handled by doing nothing.
*
* @param e the new drop target drag event
*/
public void dropActionChanged( DropTargetDragEvent e )
{
}
} // cDropTargetListener
protected static class DraggedObjects extends ArrayList implements Transferable
{
public sta