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

        这是修改“Java中的Drag and Drop详解与代码示例(3)”的示例,原来的示例是把树节点拖到JTextArea中,并在JTextArea后面显示出树节点的名,这个示例是在单个树JTree中进行拖拽,把一个树节点拖到另一个树节点下。

一、代码
Frame1.java
        这个类是显示树的主面板类,中间是一颗树,下方是“增加”和“删除”按钮。拖拽中涉及的两个主要类DragGestureListener和DragSourceListener的子类放在Frame1.java中作为内部类。

package test.a.testtree;

import java.awt.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DnDConstants;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragSourceContext;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.util.ArrayList;

public class Frame1 extends JFrame implements TreeSelectionListener{
    JPanel contentPane;
    BorderLayout borderLayout1 = new BorderLayout();
    DefaultMutableTreeNode node = new DefaultMutableTreeNode("根目录 ");
    DefaultTreeModel model = new DefaultTreeModel(node);
    JTree tree = new JTree(model);
    JButton btDel = new JButton();
    JButton btAdd = new JButton();
    JPanel jPanel1 = new JPanel();
    GridBagLayout gridBagLayout1 = new GridBagLayout();
    //拖动的树节点
    DefaultMutableTreeNode dragTreeNode = null;
    //树的所有树节点名称
    ArrayList allTreeNodeNameList = new ArrayList();

    public Frame1() {
        try {
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            jbInit();
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /**
     *   Component   initialization.
     *
     *   @throws   java.lang.Exception
     */
    private void jbInit() throws Exception {
        contentPane = (JPanel) getContentPane();
        contentPane.setLayout(borderLayout1);
        setSize(new Dimension(400, 300));
        setTitle("Frame   Title ");
        btDel.setText("删除 ");
        btDel.addActionListener(new Frame1_jButton1_actionAdapter(this));
        btAdd.setText("增加 ");
        btDel.setEnabled(false);
        btAdd.setEnabled(false);
        initalTree();
        btAdd.addActionListener(new Frame1_jButton2_actionAdapter(this));
        jPanel1.setLayout(gridBagLayout1);
        contentPane.add(tree, java.awt.BorderLayout.CENTER);
        contentPane.add(jPanel1, java.awt.BorderLayout.SOUTH);

        jPanel1.add(btDel, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
                                                  , GridBagConstraints.EAST,
                                                  GridBagConstraints.NONE,
                                                  new Insets(5, 5, 5, 5), 0, 0));
        jPanel1.add(btAdd, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0
                                                  , GridBagConstraints.EAST,
                                                  GridBagConstraints.NONE,
                                                  new Insets(5, 5, 5, 5), 0, 0));
        //JTree不能设置setDragEnabled(true),如果设置了会出现
        //java.awt.dnd.InvalidDnDOperationException: Drag and drop in progress 的异常
        //        tree.setDragEnabled(true);
        //拖动源是单一的实例
        DragSource dragSource = DragSource.getDefaultDragSource();
        //设置drap(拖)数据源对应的对象jtr,并且添加监听器
        dragSource.createDefaultDragGestureRecognizer(tree,
                DnDConstants.ACTION_MOVE, new DragAndDropDragGestureListener());
        //设置放置目标jtr,并且添加监听器
        DropTarget dropTarget = new DropTarget(tree,
                                               new
                                               DragAndDropDropTargetListener());

    }

    /**
     * 初始化树
     */
    private void initalTree() {
        allTreeNodeNameList.add("根目录");
        //设置可以看见句柄
        tree.setShowsRootHandles(true);
        DefaultMutableTreeNode parent1 = new DefaultMutableTreeNode("jsp ");
        allTreeNodeNameList.add("jsp");
        node.add(parent1);
        DefaultMutableTreeNode parent = new DefaultMutableTreeNode("书籍 ");
        allTreeNodeNameList.add("书籍");
        node.add(parent);
        DefaultMutableTreeNode java = new DefaultMutableTreeNode("java ");
        allTreeNodeNameList.add("java");

        parent.add(java);
        DefaultMutableTreeNode java1 = new DefaultMutableTreeNode("完整参考资料 ");
        allTreeNodeNameList.add("完整参考资料");
        parent.add(java1);
        DefaultMutableTreeNode java2 = new DefaultMutableTreeNode("java编程");
        allTreeNodeNameList.add("java编程");
        parent.add(java2);
        DefaultMutableTreeNode jsp = new DefaultMutableTreeNode("学习jsp");
        allTreeNodeNameList.add("学习jsp");
        parent1.add(jsp);
        //添加树的选择监听器
        tree.addTreeSelectionListener(this);
    }

    public void jButton1_actionPerformed(ActionEvent e) {
        DefaultMutableTreeNode selected = (DefaultMutableTreeNode) tree.
                                          getLastSelectedPathComponent();
        if (selected != null) {
            model.removeNodeFromParent(selected);
        }
    }

    public void jButton2_actionPerformed(ActionEvent e) {
        String name = javax.swing.JOptionPane.showInputDialog(this, "输入节点名字: ");
        if (name == null || name.equals(" ")) {
            return;
        }
        if (allTreeNodeNameList.contains(name.trim())) {//节点名称不能有重复的
                // 数据库操作失败,无法验证用户! 系统错误
         JOptionPane.showMessageDialog(this, "节点名称已经存在,添加失败!","错误",
                                       JOptionPane.ERROR_MESSAGE);
         return;

        }
        DefaultMutableTreeNode selected = (DefaultMutableTreeNode) tree.
                                          getLastSelectedPathComponent();
        if (selected == null) {
            return;
        }
        DefaultMutableTreeNode node = new DefaultMutableTreeNode(name);
        //添加到树节点
        model.insertNodeInto(node, selected, 0);
        TreePath path = new TreePath(node.getPath());
        tree.makeVisible(path);
    }

   

    public void valueChanged(TreeSelectionEvent e) {
        TreePath path = e.getPath();
        if (path == null) {
            btAdd.setEnabled(false);
            btDel.setEnabled(false);
            return;
        }
        if (((DefaultMutableTreeNode) path.getLastPathComponent()).isRoot()) {
            btAdd.setEnabled(false);
            btDel.setEnabled(false);
        }
        btAdd.setEnabled(true);
        btDel.setEnabled(true);

    }

    /**
     * 获取拖动的树节点
     * @return DefaultMutableTreeNode
     */
    public DefaultMutableTreeNode getDragTreeNode(){
        return dragTreeNode;
    }
    
    /**
     * 设置拖动的树节点
     */
    public void setDragTreeNode(DefaultMutableTreeNode dragTreeNode){
        this.dragTreeNode = dragTreeNode;
    }
    
    /**
     * 获取树
     * @return JTree
     */
    public JTree getTree(){
       return tree; 
    }

    //因为要JTreee既为拖动源又是放置目标,所以把DragGestureListener作为一个内部类比较好
    class DragAndDropDragGestureListener implements DragGestureListener {
        public void dragGestureRecognized(DragGestureEvent dge) {
            JTree tree = (JTree) dge.getComponent();
            TreePath path = tree.getSelectionPath();
            if (path != null) {
                dragTreeNode = (DefaultMutableTreeNode)
                        path.getLastPathComponent();
               if (dragTreeNode!= null) {
                   DragAndDropTransferable dragAndDropTransferable = new
                           DragAndDropTransferable(dragTreeNode);
                   //启动拖动操作,dragAndDropTransferable为封装移动、复制或连接的数据
                   //DragAndDropDragSourceListener实例十跟踪操作进程和完成操作启动者的任务
                   dge.startDrag(DragSource.DefaultMoveDrop,
                                 dragAndDropTransferable,
                                 new DragAndDropDragSourceListener());
               }
            }
        }
    }
    
    
    //因为要JTreee既为拖动源又是放置目标,所以把DragGestureListener作为一个内部类比较好
    class DragAndDropDragSourceListener implements DragSourceListener {

    //dragEnter(),dragExit(),dragOver(),dropActionChanged()这几个方法只有在调用放置目标监听器中
    //的对应方法并且防止目标不拒绝操作后,才调用这个拖动源的方法。
    /**
     * 在光标进入放置组件的显示区时调用
     * @param e DragSourceDragEvent
     */
    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);
        }
    }

    /**
     * 在光标退出放置组件的显示区时发生
     * @param e DragSourceEvent
     */
    public void dragExit(DragSourceEvent e) {}

    /**
     * 在光标进入放置组件显示区之后移动时调用
     * @param e DragSourceDragEvent
     */
    public void dragOver(DragSourceDragEvent e) {}

    /**
     * 选择放置操作的修饰键的状态变化
     * @param e DragSourceDragEvent
     */
    public void dropActionChanged(DragSourceDragEvent e) {}

    /**
     *放置发生并调用DropTargetListener的drop()方法后,调用dragDropEnd()方法,
     * 告诉拖动源放置已经完成
     * @param e DragSourceDropEvent
     */
    public void dragDropEnd(DragSourceDropEvent e) {
        //getDropSuccess()对应DropTargetListener的drop()方法调用dropcomplete()时指目标指定的值
        //getDropAction()对应DropTargetListener的drop()方法调用acceptDrop()时指定的操作
        if (!e.getDropSuccess()||e.getDropAction()!= DnDConstants.ACTION_MOVE) {
            return;
        }

        DragSourceContext context = e.getDragSourceContext();
        Object comp = context.getComponent();
        if (comp==null||!(comp instanceof JTree)) {
            return ;
        }
        DefaultMutableTreeNode dragTreeNode = getDragTreeNode();
        
        if (dragTreeNode!=null) {
            ((DefaultTreeModel) tree.getModel()).removeNodeFromParent(dragTreeNode);
            //设置拖动的树节点为空
            setDragTreeNode(null);
        }

    }
}



    public static void main(String[] args) {
       new Frame1().setVisible(true);
   }
}



class Frame1_jButton2_actionAdapter implements ActionListener {
    private Frame1 adaptee;
    Frame1_jButton2_actionAdapter(Frame1 adaptee) {
        this.adaptee = adaptee;
    }

    public void actionPerformed(ActionEvent e) {
        adaptee.jButton2_actionPerformed(e);
    }
}


class Frame1_jButton1_actionAdapter implements ActionListener {
    private Frame1 adaptee;
    Frame1_jButton1_actionAdapter(Frame1 adaptee) {
        this.adaptee = adaptee;
    }

    public void actionPerformed(ActionEvent e) {
        adaptee.jButton1_actionPerformed(e);
    }
}

 

DragAndDropTransferable.java


      这个类实现了Transferable.java,用于在拖拽中传递数据

 

 

package test.a.testtree;

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;
    //创建自己的DataFlavor
    public final static DataFlavor TREENODE_FLAVOR = new DataFlavor(DefaultMutableTreeNode.class,"TreeNode instance");
    public DataFlavor[] flavors = new DataFlavor[] {TREENODE_FLAVOR};


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

    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 {
        if (df.equals(TREENODE_FLAVOR)) {
            return treeNode;
        }
       throw new UnsupportedFlavorException(df);
    }
}

 

DragAndDropDropTargetListener.java 

       这个类实现了DropTargetListener.java,用于放置目标

 

package test.a.testtree;

import java.awt.Component;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.*;

import javax.swing.JTree;
import javax.swing.tree.*;

//* Drop Target Listener */
public class DragAndDropDropTargetListener implements DropTargetListener {

    //e.rejectDrop()只可以在dragEnter()、dragOver()和dropActionChanged()中调用,不能在drop()中调用

    /**
     * 在光标进入放置组件的显示区时调用
     * @param e DropTargetDragEvent
     */
    public void dragEnter(DropTargetDragEvent e) {
    }

    /**
     * 在光标进入放置组件显示区之后移动时调用
     * @param e DropTargetDragEvent
     */
    public void dragOver(DropTargetDragEvent e) {
    }

    /**
     * 选择放置操作的修饰键的状态变化
     * @param e DropTargetDragEvent
     */
    public void dropActionChanged(DropTargetDragEvent e) {}

    /**
     * 在光标退出放置组件的显示区时发生
     * @param e DropTargetEvent
     */
    public void dragExit(DropTargetEvent e) {}


    /**
     * 在发生放置时调用,负责接受或拒绝放置请求和处理放置的数据
     * @param e DropTargetDropEvent
     */
    public void drop(DropTargetDropEvent e) {
        //获取要传递的数据
        Transferable transfer = e.getTransferable();
        DefaultMutableTreeNode dragSource = null;
        //是否支持树节点数据的传递
        if (transfer.isDataFlavorSupported(DragAndDropTransferable.TREENODE_FLAVOR)) {
            try {
                //设置接受移动的操作
                e.acceptDrop(DnDConstants.ACTION_MOVE);
                //获取传递的数据
                dragSource = (DefaultMutableTreeNode) transfer.getTransferData(
                        DragAndDropTransferable.TREENODE_FLAVOR);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        if (dragSource == null) { //拖动的数据源为空则退出
            //放置不成功
            e.dropComplete(false);
            return;
        }
        //获取dropTo对象
        DropTarget dt = (DropTarget) e.getSource();
        Component comp = dt.getComponent();
        if (!(comp instanceof JTree)) {
            //放置不成功
            e.dropComplete(false);
            return;
        }
        JTree jtr = (JTree) comp;
        TreePath treePath = jtr.getPathForLocation(e.getLocation().x,e.getLocation().y);
        if (treePath==null) {
             //放置不成功
            e.dropComplete(false);
            return;
        }
        DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
        if (!isCanDrop(dragSource,treeNode,jtr)) {
            //放置不成功
            e.dropComplete(false);
            return;
        }

        //把节点添加到当前树节点下
        treeNode.add(dragSource);
        //更新树节点
        ((DefaultTreeModel)jtr.getModel()).reload(treeNode);

        //设置放置成功
        e.dropComplete(true);
    }

    /**
     * 判断是否可以放置操作
     * @param dragTreeNode DefaultMutableTreeNode 拖动源的树节点
     * @param dropTreeNode DefaultMutableTreeNode 放置目标的树节点
     * @return boolean
     */
    public boolean isCanDrop(DefaultMutableTreeNode dragTreeNode,
                             DefaultMutableTreeNode dropTreeNode, JTree jtr) {
        if (dragTreeNode == null) { //拖动源为空则退出
            return false;
        }
        //设置放置目标为空时不可放置
        if (dropTreeNode == null ) {
            return false;
        }
        //放置目标是拖动源则退出
        if (dragTreeNode==dropTreeNode) {
         return false;
        }
       TreePath dragPath = new TreePath (((DefaultTreeModel )jtr.getModel()).getPathToRoot(dragTreeNode));
       TreePath dropPath = new TreePath (((DefaultTreeModel )jtr.getModel()).getPathToRoot(dropTreeNode));
       String strDragPath = dragPath.toString();
       String strDropPath = dropPath.toString();
       String subDragPath = strDragPath.substring(0,strDragPath.length()-1);

       if (strDropPath.startsWith(subDragPath)) {//放置目标是拖动源的子孙节点
           return false;
       }
       if ( dragPath.getParentPath().toString().equals(strDropPath)) {//放置目标是拖动源的父节点
           return false;
       }

       //放置目标是拖动源的父节点则退出
       if (dragTreeNode.getParent().equals(dropTreeNode)) {
           return false;
       }

       return true;
    }
}

 

二、拖拽流程
 
 1、创建拖动源,拖动是单实例的:
 //拖动源是单一的实例
 DragSource dragSource = DragSource.getDefaultDragSource();
 
 2、给拖动源添加监听器
 
  //设置drap(拖)数据源对应的对象jtr,并且添加监听器
  dragSource.createDefaultDragGestureRecognizer(tree,DnDConstants.ACTION_MOVE, new DragAndDropDragGestureListener());
 
  参数:
  tree:是拖动源
  DnDConstants.ACTION_MOVE:表示要做的操作---移动
  new DragAndDropDragGestureListener():创建一个监听实例
 
 3、设置放置目标,并且添加监听器
 //设置放置目标tree,并且添加监听器
 DropTarget dropTarget = new DropTarget(tree, new DragAndDropDropTargetListener());
 
 参数:
 tree: 放置目标的对象
 new DragAndDropDropTargetListener():创建放置目标监听器
 
 
 4、在拖动源的监听器DragAndDropDragGestureListener的方法dragGestureRecognized()中
   调用:
  dge.startDrag(DragSource.DefaultMoveDrop,dragAndDropTransferable,new DragAndDropDragSourceListener());
 
  方法startDrag()表示实现托的操作
  参数:                         
  DragSource.DefaultMoveDrop:要实现的操作
  dragAndDropTransferable:要传递的数据实例
  new DragAndDropDragSourceListener():拖动事件的监听器
 
  5、放置目标的监听器DragAndDropDropTargetListener.java
  放置目标的监听器的主要方法是drop(),实现放置的操作
 
  6、 拖动事件的监听器DragAndDropDragSourceListener
  这个监听器主要是用于清理工作。
 
 
 主要流程:(1)、创建拖动源、放置目标----〉DragGestureListener.java的方法dragGestureRecognized()调用startDrag()方法,(这样就可以实现拖拽,但没有实现具体的功能) ----->DropTargetListener的drop()方法-----〉DragSourceListener的dragDropEnd()方法。
 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值