티스토리 뷰

IS & Audit/Tool & Tips

JTree Drag & Drop

Auditories 2011. 5. 17. 22:29
이너넷을 검색하여
발견한 몇 가지 소스들을 조합하여
Tree Node를 추가, 수정, 삭제하는 편집기능과
Drag & Drop을 통하여 위치 이동 및 복사하는 기능을 맹글었습니다.

다음 화면으로 간단히 확인하시고,
첨부한 소스를 활용하시길...



2011.05.17



/**
 * @(#) TreeDragAndDrop.java
 *
 * An example for testing the Drag and Drop with JTree.
 *
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any commercial and/or non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it as long as you retain this notice.
 *
 * @author: Hoyal Kim, hoyal.kim@gmail.com
 */
import java.awt.*;  
import java.awt.datatransfer.*;  
import java.awt.dnd.*;  
import java.util.*;  
import java.util.List;  
import javax.swing.*;  
import javax.swing.tree.*;  
import java.awt.event.MouseAdapter;  
import java.awt.event.MouseEvent;  
import java.awt.event.InputEvent;  
import java.awt.event.ActionEvent;  
import java.awt.event.ActionListener;  
/**
 * 노드 이동은 Drag&Drop
 * 노드 복사는 [Ctrl] + Drag&Drop
 * 오른쪽 버튼 팝업메뉴 - Add/Modify/Delete
 */
public class TreeDragAndDrop
{  
 JTree tree;
    boolean DEBUG = true;
    public static void main(String[] args)
 {  
        JFrame f = new JFrame("JTree DnD Demo");  
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
        f.add(new TreeDragAndDrop().getContent());  
        f.setSize(400,400);  
        f.setLocation(200,200);  
        f.setVisible(true);  
    }  
 private JScrollPane getContent()
 {  
  tree = new JTree();  
        tree.setDragEnabled(true);  
        tree.setDropMode(DropMode.ON_OR_INSERT);  
        tree.setTransferHandler(new TreeTransferHandler());  
        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);  
        expandTree(tree);  
     tree.addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent event) {
    // 선택 이벤트 테스트       
    if(DEBUG && tree.getSelectionCount() > 0) {
     DefaultMutableTreeNode selectedNode = getSelectedNode();
     Object obj = selectedNode.getUserObject();
     Object pobj = null;
     DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) selectedNode.getParent();
     if(parentNode != null) pobj = parentNode.getUserObject();
     System.out.println("Selected: [" + obj + "], isLeaf[" + selectedNode.isLeaf() + "], parent:[" + pobj + "]");
    }
    if (((event.getModifiers() & InputEvent.BUTTON3_MASK) != 0)
        && (tree.getSelectionCount() > 0)) {
     showMenu(event.getX(), event.getY());
    }
      }
     });
  return new JScrollPane(tree);  
    }  
   
 protected void showMenu(int x, int y) {
  JPopupMenu popup = new JPopupMenu();
     JMenuItem mi = new JMenuItem("추가");
     popup.add(mi);
     mi.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent event) {
         addNewNodeItem();
       }
     });
     mi = new JMenuItem("수정");
     TreePath path = tree.getSelectionPath();
     Object node = path.getLastPathComponent();
     if (node == tree.getModel().getRoot()) {
       mi.setEnabled(false);
     }
     popup.add(mi);
     mi.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent event) {
         modifySelectedNode();
       }
     });
     mi = new JMenuItem("삭제");
     if (node == tree.getModel().getRoot()) {
       mi.setEnabled(false);
     }
     popup.add(mi);
     mi.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent event) {
         deleteSelectedItems();
       }
     });
     popup.show(tree, x, y);
 }
 protected void deleteSelectedItems() {
     DefaultMutableTreeNode node = getSelectedNode();
     if(node.getChildCount() > 0) {
   JOptionPane.showMessageDialog(null, "하위 노드가 있는 경우 삭제할 수 없습니다.\n필요하다면 하위 노드부터 삭제하고 다시 시도하세요.", "주의", JOptionPane.WARNING_MESSAGE);
  }
  else {
   int res = JOptionPane.showConfirmDialog(null, "삭제하면 다시 복원할 수 없습니다.\n삭제하시겠습니까?", "삭제 확인", JOptionPane.YES_NO_OPTION);
   if(res == JOptionPane.OK_OPTION) {
          DefaultTreeModel model = (DefaultTreeModel) (tree.getModel());
          TreePath[] paths = tree.getSelectionPaths();
          for (int i = 0; i < paths.length; i++) {
            node = (DefaultMutableTreeNode) (paths[i].getLastPathComponent());
            model.removeNodeFromParent(node);
          }
   }
  }
 }
 private void modifySelectedNode() {
     DefaultMutableTreeNode node = getSelectedNode();
     if (node == null) {
   JOptionPane.showMessageDialog(null, "변경할 노드를 선택하세요.", "Error",
             JOptionPane.ERROR_MESSAGE);
   return;
     }
     String name = JOptionPane.showInputDialog(null, "새로운 노드 이름 입력하세요: ");
  if(name != null && !"".equals(name)) {
   node.setUserObject(name);
  }
 }
 private void addNewNodeItem() {
     DefaultMutableTreeNode parent = getSelectedNode();
     if (parent == null) {
   JOptionPane.showMessageDialog(null, "추가할 위치의 상위 노드를 선택하세요.", "Error",
     JOptionPane.ERROR_MESSAGE);
   return;
     }
     String name = JOptionPane.showInputDialog(null, "삽입할 노드 이름 입력하세요: ");
  if(name != null && !"".equals(name)) {
      DefaultTreeModel model = (DefaultTreeModel) (tree.getModel());
      model.insertNodeInto(new DefaultMutableTreeNode(name), parent, parent.getChildCount());
         tree.expandRow(tree.getLeadSelectionRow());
  }
 }
 private DefaultMutableTreeNode getSelectedNode() {
     return (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
 }
 private void expandTree(JTree tree)
 {  
        DefaultMutableTreeNode root = (DefaultMutableTreeNode)tree.getModel().getRoot();  
        Enumeration e = root.breadthFirstEnumeration();  
        while(e.hasMoreElements()) {  
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement();  
            if(node.isLeaf()) continue;  
            int row = tree.getRowForPath(new TreePath(node.getPath()));  
            tree.expandRow(row);  
        }  
    }  
}  
/**
 * TransferHandler Extension Class
 */
class TreeTransferHandler extends TransferHandler
{  
    DataFlavor nodesFlavor;  
    DataFlavor[] flavors = new DataFlavor[1];  
    DefaultMutableTreeNode[] nodesToRemove;  
   
    public TreeTransferHandler()
 {  
        try {  
            String mimeType = DataFlavor.javaJVMLocalObjectMimeType +  
                              ";class=\"" +  
                javax.swing.tree.DefaultMutableTreeNode[].class.getName() +  
                              "\"";  
            nodesFlavor = new DataFlavor(mimeType);  
            flavors[0] = nodesFlavor;  
        } catch(ClassNotFoundException e) {  
            System.out.println("ClassNotFound: " + e.getMessage());  
        }  
    }  
   
    public boolean canImport(TransferHandler.TransferSupport support)
 {  
        if(!support.isDrop()) {  
            return false;  
        }  
        support.setShowDropLocation(true);  
        if(!support.isDataFlavorSupported(nodesFlavor)) {  
            return false;  
        }  
        // 드래그한 소스 위에 떨어뜨리는 건 허용하지 않음
  // Do not allow a drop on the drag source selections.  
        JTree.DropLocation dl = (JTree.DropLocation)support.getDropLocation();  
        JTree tree = (JTree)support.getComponent();  
        int dropRow = tree.getRowForPath(dl.getPath());  
        int[] selRows = tree.getSelectionRows();  
        for(int i = 0; i < selRows.length; i++) {  
            if(selRows[i] == dropRow) {  
                return false;  
            }  
        }  
        // 넌-리프 노드가 선택되었는데 하위 자식노드들이 모두 선택되지 않았다면
  // 이동하여 떨어뜨리는 걸 허용하지 않음
  // (즉 넌-리프 노드의 이동은 하위 노드들을 모두 선택해야 이동 가능함)
  // Do not allow MOVE-action drops if a non-leaf node is  
        // selected unless all of its children are also selected.  
        int action = support.getDropAction();  
        if(action == MOVE) {  
            return haveCompleteNode(tree);  
        }
  // 넌-리프 노드는 원래 레벨보다 낮은 레벨에 복사하지 못함
        // Do not allow a non-leaf node to be copied to a level  
        // which is less than its source level.  
        TreePath dest = dl.getPath();  
        DefaultMutableTreeNode target = (DefaultMutableTreeNode)dest.getLastPathComponent();  
        TreePath path = tree.getPathForRow(selRows[0]);  
        DefaultMutableTreeNode firstNode = (DefaultMutableTreeNode)path.getLastPathComponent();  
        if(firstNode.getChildCount() > 0 && target.getLevel() < firstNode.getLevel()) {  
            return false;  
        }  
        return true;  
    }  
   
    private boolean haveCompleteNode(JTree tree)
 {  
        int[] selRows = tree.getSelectionRows();  
        TreePath path = tree.getPathForRow(selRows[0]);  
        DefaultMutableTreeNode first = (DefaultMutableTreeNode)path.getLastPathComponent();  
        int childCount = first.getChildCount();  
        // first has children and no children are selected.  
        if(childCount > 0 && selRows.length == 1)  
            return false;  
        // first may have children.  
        for(int i = 1; i < selRows.length; i++) {  
            path = tree.getPathForRow(selRows[i]);  
            DefaultMutableTreeNode next = (DefaultMutableTreeNode)path.getLastPathComponent();  
            if(first.isNodeChild(next)) {  
                // Found a child of first.  
                if(childCount > selRows.length-1) {  
                    // Not all children of first are selected.  
                    return false;  
                }  
            }  
        }  
        return true;  
    }  
   
    protected Transferable createTransferable(JComponent c)
 {  
        JTree tree = (JTree)c;  
        TreePath[] paths = tree.getSelectionPaths();  
        if(paths != null) {  
            // Make up a node array of copies for transfer and  
            // another for/of the nodes that will be removed in  
            // exportDone after a successful drop.  
            List<DefaultMutableTreeNode> copies = new ArrayList<DefaultMutableTreeNode>();  
            List<DefaultMutableTreeNode> toRemove = new ArrayList<DefaultMutableTreeNode>();  
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)paths[0].getLastPathComponent();  
            DefaultMutableTreeNode copy = copy(node);  
            copies.add(copy);  
            toRemove.add(node);  
            for(int i = 1; i < paths.length; i++) {  
                DefaultMutableTreeNode next = (DefaultMutableTreeNode)paths[i].getLastPathComponent();  
                // Do not allow higher level nodes to be added to list.  
                if(next.getLevel() < node.getLevel()) {  
                    break;  
                } else if(next.getLevel() > node.getLevel()) {  // child node  
                    copy.add(copy(next));  
                    // node already contains child  
                } else {                                        // sibling  
                    copies.add(copy(next));  
                    toRemove.add(next);  
                }  
            }  
            DefaultMutableTreeNode[] nodes = copies.toArray(new DefaultMutableTreeNode[copies.size()]);  
            nodesToRemove = toRemove.toArray(new DefaultMutableTreeNode[toRemove.size()]);  
            return new NodesTransferable(nodes);  
        }  
        return null;  
    }  
   
    /** Defensive copy used in createTransferable. */ 
    private DefaultMutableTreeNode copy(TreeNode node)
 {  
        return new DefaultMutableTreeNode(node);  
    }  
   
    protected void exportDone(JComponent source, Transferable data, int action)
 {  
        if((action & MOVE) == MOVE) {  
            JTree tree = (JTree)source;  
            DefaultTreeModel model = (DefaultTreeModel)tree.getModel();  
            // Remove nodes saved in nodesToRemove in createTransferable.  
            for(int i = 0; i < nodesToRemove.length; i++) {  
                model.removeNodeFromParent(nodesToRemove[i]);  
            }  
        }  
    }  
   
    public int getSourceActions(JComponent c)
 {  
        return COPY_OR_MOVE;  
    }  
   
    public boolean importData(TransferHandler.TransferSupport support)
 {  
        if(!canImport(support)) {  
            return false;  
        }  
        // Extract transfer data.  
        DefaultMutableTreeNode[] nodes = null;  
        try {  
            Transferable t = support.getTransferable();  
            nodes = (DefaultMutableTreeNode[])t.getTransferData(nodesFlavor);  
        } catch(UnsupportedFlavorException ufe) {  
            System.out.println("UnsupportedFlavor: " + ufe.getMessage());  
        } catch(java.io.IOException ioe) {  
            System.out.println("I/O error: " + ioe.getMessage());  
        }  
        // Get drop location info.  
        JTree.DropLocation dl =  
                (JTree.DropLocation)support.getDropLocation();  
        int childIndex = dl.getChildIndex();  
        TreePath dest = dl.getPath();  
        DefaultMutableTreeNode parent = (DefaultMutableTreeNode)dest.getLastPathComponent();  
        JTree tree = (JTree)support.getComponent();  
        DefaultTreeModel model = (DefaultTreeModel)tree.getModel();  
        // Configure for drop mode.  
        int index = childIndex;    // DropMode.INSERT  
        if(childIndex == -1) {     // DropMode.ON  
            index = parent.getChildCount();  
        }  
        // Add data to model.  
        for(int i = 0; i < nodes.length; i++) {  
            model.insertNodeInto(nodes[i], parent, index++);  
        }  
        return true;  
    }  
   
    public String toString()
 {  
        return getClass().getName();  
    }  
   
   /**
 * Transferable Implementation Class
 */
    public class NodesTransferable implements Transferable
 {  
        DefaultMutableTreeNode[] nodes;  
   
        public NodesTransferable(DefaultMutableTreeNode[] nodes)
  {  
            this.nodes = nodes;  
         }  
   
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException
  {  
            if(!isDataFlavorSupported(flavor)) throw new UnsupportedFlavorException(flavor);  
            return nodes;  
        }  
   
        public DataFlavor[] getTransferDataFlavors()
  {  
            return flavors;  
        }  
   
        public boolean isDataFlavorSupported(DataFlavor flavor)
  {  
            return nodesFlavor.equals(flavor);  
        }  
    }  






최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함