`

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

    博客分类:
  • java
阅读更多

        这是修改“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()方法。
 

 

 

 

 

分享到:
评论
1 楼 fv3386 2009-05-31  
Thanks for your example

相关推荐

    Java 程序设计之经典代码

    本文将深入探讨《Java开发者手册2000》中提到的一些经典代码示例,旨在帮助读者理解如何运用特定的类及其成员来完成具体的任务,并展示这些类之间是如何相互作用的。 #### 二、经典代码示例(Examplets) **定义:...

    Java经典代码

    7. **Drag and Drop**:这部分内容介绍了如何在Java程序中实现拖拽功能,使得用户能够方便地进行文件或数据的移动。 8. **Events**:事件处理是Java图形用户界面开发中的重要组成部分。这部分内容将探讨如何处理...

    java swing拖放功能

    其中,拖放(Drag and Drop)功能是 Java Swing 中的一种重要功能,允许用户在应用程序中实现拖放操作。在本文中,我们将详细介绍 Java Swing 中的拖放功能,包括其实现原理、常用组件支持、事件处理机制等方面的...

    基于Java的实例开发源码-SwingSet.zip

    Java SwingSet 示例开发源码详解 Java Swing 是Java标准库中的一个组件,用于构建桌面应用程序的用户界面。SwingSet 是一套用Java Swing编写的示例程序,它展示了Swing的各种组件、布局管理器以及事件处理机制。这...

    javaSwing编程

    - Swing 不依赖于本地代码,因此与 Java2D、Accessibility 和 Drag & Drop 等组件在实现上有本质的区别。 #### 八、学习资源 - **《Java Tutorial》:** - Sun Microsystems 提供的在线教程,详细介绍了 Java 编程...

    DragAndDropDemo

    在用户交互设计中,拖放(Drag and Drop)功能是一个常用且实用的设计,它使得用户可以通过直观的手势来移动、排列或交换屏幕上的元素。本篇文章将围绕一个名为"DragAndDropDemo"的小型示例项目,深入探讨如何在...

    SWT API 帮助文档 及源码

    7. **拖放支持(Drag and Drop)**:SWT 支持控件间的拖放操作,开发者可以注册拖放监听器来处理这一过程。 8. **打印支持(Printing)**:SWT 提供了打印API,使得开发者能够将内容打印到物理打印机。 9. **可...

    swt api chm格式

    4. **学习示例**:API文档通常包含代码示例,这有助于理解如何在实际项目中应用API。 总之,SWT API CHM文件是Eclipse开发者不可或缺的参考资料,它提供了详细的API描述和实例,能够帮助开发者更好地理解和使用SWT...

    Android应用源码之DragList(可拖拽移动的ListView).rar

    通常,这样的源码示例包含完整的代码结构,包括布局文件、Java类、可能的XML配置等,有助于初学者或者有经验的开发者学习和实践。 【知识点详解】 1. **ListView基础**:首先,我们需要了解ListView的基本用法,它...

    SwingUI-JFC好书.pdf

    7. **高级特性**:除了基本的GUI构建功能外,Swing还支持许多高级特性,比如拖放操作(Drag and Drop)、剪贴板操作(Clipboard)、打印支持等。 #### 五、参考资源 - **官方文档**:[Swing官方文档]...

    selenium2.0

    - **拖拉**:使用 `Actions` 类的 `dragAndDrop` 方法实现拖拽功能。 - **导航**:使用 `navigate()` 方法实现前进、后退等操作。 ##### 3.3 高级使用 - **特性**: - **改变 User Agent**:通过设置浏览器配置...

    DragAndDropImageSample:用于使用 Haxe 的 html

    在这个示例中,Haxe编写的JavaScript代码会监听拖放事件,如`dragstart`、`dragover`、`drop`等,这些事件在用户与网页元素交互时触发,从而实现图像的拖放操作。 7. **跨平台能力**: Haxe的一个关键特性是跨...

Global site tag (gtag.js) - Google Analytics