通過兩種方法實(shí)現(xiàn)Drag and Drop:
1.比較初級的D&D:只利用java.awt.datatransfer.*中的類實(shí)現(xiàn).
2.高級D&D: 利用javax.awt.dnd.*中的類實(shí)現(xiàn).
比較初級D&D:只利用java.awt.datatransfer.*中的類實(shí)現(xiàn).
這種方法只支持對JComponent的拖拽.
Drag and Drop的問題簡單的說要涉及到兩個(gè)部分: Drag Source, Drop target和Transferable 即從哪里drag來的, 以及drop到哪里去, 以及傳輸?shù)臄?shù)據(jù).
Drag Source可以分為兩種:
1.第一種是這樣的JComponent, 他們有dragEnabled屬性.這些JComponent包括:
javax.swing.JColorChooser
javax.swing.JFileChooser
javax.swing.JList
javax.swing.JTable
javax.swing.JTree
javax.swing.text.JTextComponent
這些JComponent要想作為一個(gè)Drag Source只要調(diào)用setDragEnabled( true)即可, 不用多余的操作.
2. 另一種Drag Source沒有dragEnabled屬性, 也就沒有setDragEnabled方法, 要想作為Drag Source, 那就要給Component添加MouseMotionListener, 并實(shí)現(xiàn)mouseDragged方法, 后面會(huì)舉例介紹.
Drop Target, 任何JComponent都可以作為Drop Target, 但是也只有JComponent以及它的子類可以作為Drop Target, 其它的不行.
Transferable
所有的Transferable都是javax.swing.Transferable的子類, 但是細(xì)分還是可以分為兩種情況:
第一種是利用javax.swing.Transferable, 因?yàn)閖avax.swing.Transferable 是一個(gè)具體類我們可以直接調(diào)用new TransferHandler( String property )生成的transfer handler 作為Component的Transfer Handler, 這樣的transfer handler可以將 Java Bean 屬性從一個(gè)組件傳輸?shù)搅硪粋€(gè)組件的傳輸處理程序。
第二種則是自定義一個(gè)TransferHandler的子類, 你可以在這個(gè)類中實(shí)現(xiàn)復(fù)雜的拖拽操作.
下面有兩個(gè)例子.
第一個(gè)例子用簡單的javax.swing.Transferable, 第二個(gè)例子定義一個(gè)javax.swing.Transferable的子類.
例一
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;


public class LabelDnd ...{
private JFrame mainFrame;
private JPanel mainPanel;
private JLabel label;
private JTextField textField;
private JColorChooser colorChooser;
private JMenuBar menuBar = new JMenuBar();
private JMenu menu = new JMenu( "Menu" );
private JMenuItem menuItem = new JMenuItem( "Handle Foregound" );
private TransferHandler t1 = new TransferHandler( "text" ) ;
private TransferHandler t2 = new TransferHandler( "foreground" );

public LabelDnd() ...{
mainFrame = new JFrame();
mainPanel = new JPanel( new BorderLayout() );
label = new JLabel( "label" );
label.setTransferHandler( t1 );

menuItem.addActionListener( new ActionListener() ...{

public void actionPerformed( ActionEvent e ) ...{

if( label.getTransferHandler().equals( t1 ) ) ...{
LabelDnd.this.menuItem.setText( "Handle Text" );
label.setTransferHandler( t2 );

} else ...{
LabelDnd.this.menuItem.setText( "Handle Foreground" );
label.setTransferHandler( t1 );
}
}
});
menu.add( menuItem );
menu.setTransferHandler( t1 );
menuBar.add( menu );
mainFrame.setJMenuBar( menuBar );

label.addMouseListener( new MouseAdapter() ...{

public void mousePressed( MouseEvent e ) ...{
JComponent c = (JComponent)e.getSource();
TransferHandler handler = c.getTransferHandler();
handler.exportAsDrag( c, e, TransferHandler.COPY );
}
});
textField = new JTextField( 20 );
textField.setDragEnabled( true );
colorChooser = new JColorChooser();
colorChooser.setDragEnabled( true );
mainPanel.add( label, BorderLayout.PAGE_START );
mainPanel.add( textField, BorderLayout.PAGE_END );
mainPanel.add( colorChooser, BorderLayout.WEST );
mainFrame.getContentPane().add( mainPanel );
mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
mainFrame.pack();
mainFrame.setLocationRelativeTo( null );
mainFrame.setVisible( true );
}

public static void main( String[] args ) ...{
new LabelDnd();
}
}
效果如下:

你可以試著拖拽下。
例二
PictureDnd.java
package dt;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;

import demo.gui.PictureComponent;

import java.awt.datatransfer.*;
import java.io.*;


public class PictureDnd ...{
JFrame mainFrame;
JPanel mainPanel;
PictureComponent[] pictures;

public static void main( String[] args ) ...{
new PictureDnd();
}

public PictureDnd() ...{
mainFrame = new JFrame();
mainPanel = new JPanel( new GridLayout( 2, 2 ) );
pictures = new PictureComponent[ 4 ];
pictures[ 0 ] = new PictureComponent( new ImageIcon( "Sunset.jpg" ).getImage() );
pictures[ 1 ] = new PictureComponent( new ImageIcon( "Winter.jpg" ).getImage() );
pictures[ 2 ] = new PictureComponent( null );
pictures[ 3 ] = new PictureComponent( null );
mainPanel.add( pictures[ 0 ] );
mainPanel.add( pictures[ 1 ] );
mainPanel.add( pictures[ 2 ] );
mainPanel.add( pictures[ 3 ] );
mainPanel.setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) );
mainFrame.getContentPane().add( mainPanel );
mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
mainFrame.setSize( 350, 400 );
mainFrame.setLocationRelativeTo( null );
mainFrame.setVisible( true );
}
}
PicrureComponent.java
package demo.gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashSet;

import javax.swing.JComponent;

public class PictureComponent extends JComponent

implements FocusListener, MouseListener ...{
Image image;
HashSet< PictureComponent > pcs = new HashSet< PictureComponent >();

public PictureComponent( Image image ) ...{
this.image = image;
setPreferredSize( new Dimension(125, 125 ) );
setFocusable( true );
setTransferHandler( new PictureTransferHandler() );
addFocusListener( this );
addMouseListener( this );
}

public HashSet< PictureComponent > getPcs() ...{
return this.pcs;
}

public void setPcs( HashSet< PictureComponent > pcs ) ...{
this.pcs = pcs;
}

public Image getImage() ...{
return this.image;
}

public void setImage( Image image )...{
this.image = image;
repaint();
}

public void paintComponent( Graphics graphics )...{
Graphics g = graphics.create();
g.setColor( Color.white );
g.fillRect( 0, 0, 125,125 );

if( image != null ) ...{
g.drawImage( image, 0, 0, 125, 125, Color.BLACK, this );
}

if( isFocusOwner() ) ...{
g.setColor( Color.red );
}

else ...{
g.setColor( Color.black );
}
g.drawRect( 0, 0, 125, 125 );
g.dispose();
}

public void focusGained( FocusEvent e ) ...{
repaint();
}

public void focusLost( FocusEvent e ) ...{
repaint();
}

public void mouseClicked( MouseEvent e ) ...{
requestFocusInWindow();
}

public void mouseEntered( MouseEvent e ) ...{}

public void mousePressed( MouseEvent e ) ...{}

public void mouseExited( MouseEvent e ) ...{}

public void mouseReleased( MouseEvent e ) ...{}
}

TransferablePicture:
package demo.gui;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;


/**//* Transferalbe */

public class TransferablePicture implements Transferable ...{

DataFlavor[] flavors = ...{ DataFlavor.imageFlavor };
Image image;

public TransferablePicture( Image image ) ...{
this.image = image;
}

public DataFlavor[] getTransferDataFlavors() ...{
return flavors;
}

public Object getTransferData( DataFlavor flavor ) ...{

if( flavor.equals( DataFlavor.imageFlavor ) ) ...{
return image;
}
return null;
}

public boolean isDataFlavorSupported( DataFlavor flavor ) ...{
return flavor.equals( DataFlavor.imageFlavor );
}
}

PictureTransferHandler.java
package demo.gui;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.TransferHandler;

import dt.TransferablePicture;


/**//* Transfer Handler */

class PictureTransferHandler extends TransferHandler ...{

public Transferable createTransferable( JComponent c ) ...{
PictureComponent pc = (PictureComponent)c;
return new TransferablePicture( pc.getImage() );
}

public boolean canImport( JComponent c, DataFlavor[] flavors ) ...{

for( DataFlavor flavor : flavors ) ...{

if( flavor.equals( DataFlavor.imageFlavor ) ) ...{
return true;
}
}
return false;
}

public boolean importData( JComponent c, Transferable t ) ...{

if( canImport(c, t.getTransferDataFlavors() ) ) ...{
PictureComponent pc = ( PictureComponent )c;

try ...{
Image image = (Image)t.getTransferData( DataFlavor.imageFlavor );
pc.setImage( image );
System.out.println( "它能接受" );
return true;

} catch( UnsupportedFlavorException e ) ...{
e.printStackTrace();

} catch( IOException e ) ...{
e.printStackTrace();
}
}
System.out.println( "它不能接受" );
return false;
}

public void exportDone( JComponent c, Transferable data, int action ) ...{
PictureComponent picture = ( PictureComponent )c;

if( action == MOVE ) ...{
picture.setImage( null );
}
}

public int getSourceActions( JComponent c )...{
return COPY_OR_MOVE;
}

public Icon getVisualRepresentation( Transferable t ) ...{
Image image = null;

try ...{
System.out.println( "getVisualRepresentation" );
image = (Image)t.getTransferData( DataFlavor.imageFlavor );

} catch( Exception e ) ...{
e.printStackTrace();
}
return new ImageIcon( image );
}
}
效果如下:

2.高級D&D:利用javax.awt.dnd.*中的類實(shí)現(xiàn).
第二種實(shí)現(xiàn)方法和第一種的區(qū)別主要是在Drag Source和Drop Target上.而且這第二種實(shí)現(xiàn)方法支持所有Component及其子類上實(shí)現(xiàn)拖拽,而不止是JComponent.
Drag Target 一個(gè)對象那個(gè)如果想作為拖拽源的話,必須和五個(gè)對象建立聯(lián)系,這五個(gè)對象分別是: * java.awt.dnd.DragSource 獲取DragSource的方法很簡單,直接調(diào)用DragSource.getDefaultDragSource();就可以得到DragSource對象 * java.awt.dnd.DragGestureRecognizer DragGestureRecognizer類中實(shí)現(xiàn)了一些與平臺(tái)無關(guān)的方法,我們?nèi)绻朐谧约旱慕M件上實(shí)現(xiàn)拖拽的話只要調(diào)用createDefaultDragGestureRecognizer()方法就可以了 該方法接收三個(gè)參數(shù),建立組件和拖拽動(dòng)作之間的關(guān)系 * java.awt.dnd.DragGestureListener 當(dāng)建立了組件和拖拽動(dòng)作之間的聯(lián)系后,如果用戶執(zhí)行了拖拽操作,組件將發(fā)送一個(gè)消息給DragGestureListener監(jiān)聽器 DragGestureListener監(jiān)聽器接下來會(huì)發(fā)送一個(gè)startDrag()消息給拖拽源對象,告訴組件應(yīng)該執(zhí)行拖拽的初始化操作了 拖拽源會(huì)產(chǎn)生一個(gè)DragSourceContext對象來監(jiān)聽動(dòng)作的狀態(tài),這個(gè)監(jiān)聽過程是通過監(jiān)聽本地方法DragSourceContextPeer來實(shí)現(xiàn)的 * java.awt.datatransfer.Transferable * java.awt.dnd.DragSourceListener DragSourceListener接口負(fù)責(zé)當(dāng)鼠標(biāo)拖拽對象經(jīng)過組件時(shí)的可視化處理, DragSourceListener接口的顯示結(jié)果只是暫時(shí)改變組件的外觀 同時(shí)他提供一個(gè)feedback,當(dāng)用戶的拖拽操作完成之后會(huì)收到一個(gè)dragDropEnd的消息,我們可以在這個(gè)函數(shù)中執(zhí)行相應(yīng)的操作 再來回顧一下拖拽源的建立過程 1.DragGestureRecognizer 確認(rèn)一個(gè)拖拽操作,同時(shí)告知 DragGestureListener. 2.假如actions and/or flavors are OK, DragGestureListener 讓 DragSource 調(diào)用 startDrag(). 3.DragSource建立一個(gè) DragSourceContext和一個(gè)DragSourceContextPeer. 4.DragSourceContext 把它自己作為一個(gè)DragSourceListener,偵聽DragSourceContextPeer.DragSourceContextPeer會(huì)從本地系統(tǒng)得到Coponent的狀態(tài)改變的通知(component entered/exited/is over), 并把他們代理給DragSourceContext.5.DragSourceContext通知 DragSourceListener,而DragSourceListener提供 drag over 的反饋(如果DropTargetListener接受這個(gè)動(dòng)作). 典型的反饋包括讓DrogSourceContext改變鼠標(biāo).
6.一旦drop完畢, DragSourceListener就得到一個(gè)dragDropEnd的通知消息.
Drop Source 創(chuàng)建一個(gè) droppable Component必須和下面兩個(gè)對象發(fā)生關(guān)聯(lián) * java.awt.dnd.DropTarget DropTarget構(gòu)造函數(shù)使DropTarget 和 DropTargetListener objects發(fā)生關(guān)聯(lián) Droptarget對象提供 setComponent 和addDropTargetListener 兩個(gè)方法 * java.awt.dnd.DropTargetListener
DropTargetListener需要與一個(gè)Component聯(lián)系, 以讓DropTargetListener在Component操作的時(shí)候能夠顯示”drag under”效果.
下面的這個(gè)例子以第二種方式實(shí)現(xiàn)拖拽:
DragAndDrop.java
package dnd;
import java.awt.*;
import javax.swing.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.io.*;
import javax.swing.tree.*;


public class DragAndDrop extends JFrame ...{
JScrollPane jScrollPane1 = new JScrollPane();
JTextArea jTextArea1 = new JTextArea();

public DragAndDrop() ...{
this.getContentPane().setLayout( new BorderLayout() );
jScrollPane1.getViewport().setBackground( new Color( 105, 38, 125 ) );
jTextArea1.setBackground( Color.orange );
jTextArea1.setToolTipText( "" );
JTree jtr = new JTree();
jtr.setBackground( Color.BLUE );
jScrollPane1.getViewport().add( jtr );
this.getContentPane().add( jTextArea1, BorderLayout.PAGE_END );
this.getContentPane().add( jScrollPane1, BorderLayout.PAGE_START );
// Drag And Drop Relative.
DragSource dragSource = DragSource.getDefaultDragSource();
dragSource.createDefaultDragGestureRecognizer( jtr, DnDConstants.ACTION_COPY_OR_MOVE, new DragAndDropDragGestureListener() );
DropTarget dropTarget = new DropTarget( jTextArea1, new DragAndDropDropTargetListener() );
}

public static void main( String[] args ) ...{
DragAndDrop dad = new DragAndDrop();
dad.setTitle( "拖拽演示" );
dad.setSize( 400, 300 );
dad.setVisible( true );
}
}
DragAndDropDragGestureListener.java
package dnd;

import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;

import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;


/**//* Drag Gesture Listener */

public class DragAndDropDragGestureListener implements DragGestureListener ...{

public void dragGestureRecognized( DragGestureEvent dge ) ...{
JTree tree = (JTree)dge.getComponent();
TreePath path = tree.getSelectionPath();

if( path != null ) ...{
DefaultMutableTreeNode selection = ( DefaultMutableTreeNode )path.getLastPathComponent();
DragAndDropTransferable dragAndDropTransferable = new DragAndDropTransferable( selection );
dge.startDrag( DragSource.DefaultCopyDrop, dragAndDropTransferable, new DragAndDropDragSourceListener() );
}
}
}
DragAndDropDragSourceListener.java
package dnd;

import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceContext;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;

import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;


/**//* Drag Source Listener */

public class DragAndDropDragSourceListener implements DragSourceListener ...{

public void dragDropEnd( DragSourceDropEvent e ) ...{

if( e.getDropSuccess() ) ...{
int dropAction = e.getDropAction();

if( dropAction == DnDConstants.ACTION_MOVE ) ...{
//System.out.println( "MOVE: remove node" );
}
}
}

public void dragEnter( DragSourceDragEvent e ) ...{
DragSourceContext context = e.getDragSourceContext();
int dropAction = e.getDropAction();

if( ( dropAction & DnDConstants.ACTION_COPY ) != 0 ) ...{
context.setCursor( DragSource.DefaultCopyDrop );

} else if( ( dropAction & DnDConstants.ACTION_MOVE ) != 0 ) ...{
context.setCursor( DragSource.DefaultMoveDrop );

} else ...{
context.setCursor( DragSource.DefaultCopyNoDrop );
}
}

public void dragExit( DragSourceEvent e ) ...{}

public void dragOver( DragSourceDragEvent e )...{}

public void dropActionChanged( DragSourceDragEvent e )...{}
}
DragAndDropDropTargetListener.java
package dnd;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
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.io.IOException;

import javax.swing.JTextArea;


/**//* Drop Target Listener */

public class DragAndDropDropTargetListener implements DropTargetListener ...{

public void dragEnter( DropTargetDragEvent e ) ...{}

public void dragOver( DropTargetDragEvent e ) ...{}

public void dropActionChanged( DropTargetDragEvent e ) ...{}

public void dragExit( DropTargetEvent e ) ...{}

public void drop( DropTargetDropEvent e ) ...{
Transferable t = e.getTransferable();
String s = "";

try ...{

if( t.isDataFlavorSupported( DataFlavor.stringFlavor ) ) ...{
s = t.getTransferData( DataFlavor.stringFlavor ).toString();
}

} catch( IOException ioe ) ...{
ioe.printStackTrace();

} catch( UnsupportedFlavorException ufe ) ...{
ufe.printStackTrace();
}
System.out.println( s );
DropTarget dt = (DropTarget)e.getSource();
JTextArea d = ( JTextArea )dt.getComponent();

if( s != null && s.equals( "" ) == false ) ...{
d.append( s + " ");
}
}
}
DragAndDropTransferable.java
package dnd;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

import javax.swing.tree.DefaultMutableTreeNode;


/**//* Drop Transferable */

public class DragAndDropTransferable implements Transferable ...{
private DefaultMutableTreeNode treeNode;

public DragAndDropTransferable( DefaultMutableTreeNode treeNode ) ...{
this.treeNode = treeNode;
}

DataFlavor[] flavors = ...{ DataFlavor.stringFlavor };

public DataFlavor[] getTransferDataFlavors() ...{
return flavors;
}

public boolean isDataFlavorSupported( DataFlavor flavor ) ...{

for( DataFlavor df : flavors ) ...{

if( df.equals( flavor ) ) ...{
return true;
}
}
return false;
}

public Object getTransferData( DataFlavor df ) throws UnsupportedFlavorException, IOException ...{
return treeNode;
}
}
效果如下:
