Java中的Drag and Drop详解与代码示例

    技术2022-05-11  112

     我最近对对Java中的Drag and Drop做了一个总结, 觉得大致可以通过两种方法实现Drag and Drop: 1.比较初级的D&D:只利用java.awt.datatransfer.*中的类实现. 2.高级D&D: 利用javax.awt.dnd.*中的类实现.

    比较初级D&D:只利用java.awt.datatransfer.*中的类实现. 这种方法只支持对JComponent的拖拽. Drag and Drop的问题简单的说要涉及到两个部分: Drag Source, Drop target和Transferable 即从哪里drag来的, 以及drop到哪里去, 以及传输的数据.  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要想作为一个Drag Source只要调用setDragEnabled( true)即可, 不用多余的操作. 2. 另一种Drag Source没有dragEnabled属性, 也就没有setDragEnabled方法, 要想作为Drag Source, 那就要给Component添加MouseMotionListener, 并实现mouseDragged方法, 后面会举例介绍.  Drop Target, 任何JComponent都可以作为Drop Target, 但是也只有JComponent以及它的子类可以作为Drop Target, 其它的不行.  Transferable 所有的Transferable都是javax.swing.Transferable的子类, 但是细分还是可以分为两种情况: 第一种是利用javax.swing.Transferable, 因为javax.swing.Transferable 是一个具体类我们可以直接调用new TransferHandler( String property )生成的transfer handler 作为Component的Transfer Handler, 这样的transfer handler可以将 Java Bean 属性从一个组件传输到另一个组件的传输处理程序。 第二种则是自定义一个TransferHandler的子类, 你可以在这个类中实现复杂的拖拽操作.下面有两个例子.第一个例子用简单的javax.swing.Transferable, 第二个例子定义一个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( 22 ) );        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( 20202020 ) );        mainFrame.getContentPane().add( mainPanel );        mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );        mainFrame.setSize( 350400 );        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(125125 ) );        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( 00,  125,125 );        if( image != null ) {            g.drawImage( image, 00125125, Color.BLACK, this );        }        if( isFocusOwner() ) {            g.setColor( Color.red );        }        else {            g.setColor( Color.black );        }        g.drawRect( 00125125 );        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.*中的类实现. 第二种实现方法和第一种的区别主要是在Drag Source和Drop Target上.而且这第二种实现方法支持所有Component及其子类上实现拖拽,而不止是JComponent. Drag Target   一个对象那个如果想作为拖拽源的话,必须和五个对象建立联系,这五个对象分别是:    * java.awt.dnd.DragSource    获取DragSource的方法很简单,直接调用DragSource.getDefaultDragSource();就可以得到DragSource对象    * java.awt.dnd.DragGestureRecognizer    DragGestureRecognizer类中实现了一些与平台无关的方法,我们如果想在自己的组件上实现拖拽的话只要调用createDefaultDragGestureRecognizer()方法就可以了    该方法接收三个参数,建立组件和拖拽动作之间的关系    * java.awt.dnd.DragGestureListener    当建立了组件和拖拽动作之间的联系后,如果用户执行了拖拽操作,组件将发送一个消息给DragGestureListener监听器    DragGestureListener监听器接下来会发送一个startDrag()消息给拖拽源对象,告诉组件应该执行拖拽的初始化操作了    拖拽源会产生一个DragSourceContext对象来监听动作的状态,这个监听过程是通过监听本地方法DragSourceContextPeer来实现的    * java.awt.datatransfer.Transferable    * java.awt.dnd.DragSourceListener     DragSourceListener接口负责当鼠标拖拽对象经过组件时的可视化处理, DragSourceListener接口的显示结果只是暂时改变组件的外观    同时他提供一个feedback,当用户的拖拽操作完成之后会收到一个dragDropEnd的消息,我们可以在这个函数中执行相应的操作    再来回顾一下拖拽源的建立过程 1.DragGestureRecognizer 确认一个拖拽操作,同时告知 DragGestureListener. 2.假如actions and/or flavors are OK, DragGestureListener 让 DragSource 调用 startDrag(). 3.DragSource建立一个 DragSourceContext和一个DragSourceContextPeer.  4.DragSourceContext 把它自己作为一个DragSourceListener,侦听DragSourceContextPeer.DragSourceContextPeer会从本地系统得到Coponent的状态改变的通知(component entered/exited/is over), 并把他们代理给DragSourceContext.5.DragSourceContext通知 DragSourceListener,而DragSourceListener提供 drag over 的反馈(如果DropTargetListener接受这个动作). 典型的反馈包括让DrogSourceContext改变鼠标.   6.一旦drop完毕, DragSourceListener就得到一个dragDropEnd的通知消息. Drop Source   创建一个 droppable Component必须和下面两个对象发生关联       * java.awt.dnd.DropTarget    DropTarget构造函数使DropTarget 和 DropTargetListener objects发生关联    Droptarget对象提供 setComponent 和addDropTargetListener 两个方法        * java.awt.dnd.DropTargetListener     DropTargetListener需要与一个Component联系, 以让DropTargetListener在Component操作的时候能够显示”drag under”效果.        下面的这个例子以第二种方式实现拖拽: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( 10538125 ) );        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( 400300 );        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;    }}

    效果如下:

    参考网页:http://blog.csdn.net/XXKKFF/archive/2007/01/11/1480506.aspxhttp://showmealone.blog.sohu.com/8609852.html3. Drag and Drop Specifications:    http://java.sun.com/j2se/1.5/pdf/dnd1.pdf 


    最新回复(0)