시간이 지남에 따라 Swing 구성요소 세트로 끌어서 놓기 기능이 많이 변경되었습니다. 이전 버전에서는 java.awt.dnd
패키지에 기본 API가 있었지만(java.awt.datatransfer
의 지원) 초기 사용자 클릭에서 놓기 조작까지 끌기 작업의 모든 측면을 정의해야 했습니다. J2SE 1.4는 기능 세트에 따라 향상되고 이전 팁 Dragging Text and Images with Swing에 설명된 API를 업데이트합니다.
이전 API의 변경으로 끌어서 놓기 작업이 훨씬 쉬워졌습니다. 수많은 구성요소가 끌어서 놓기 작업을 내장 지원하기 때문입니다. 예를 들어, JTextField
에서 끌기 작업을 사용 가능하게 설정하려면 텍스트 구성요소에서 setDragEnabled(true)
를 호출하기만 하면 됩니다. 그러면 사용자는 텍스트 구성요소의 텍스트를 끌어서, 놓기 지역 역할을 하는 다른 애플리케이션이나 텍스트 필드 자체 내에 놓을 수 있습니다.
텍스트 구성요소는 JColorChooser
구성요소와 같이 내장된 놓기 지원을 제공하지만 JList
, JTable
또는 JTree
와 같은 다른 Swing 구성요소에 놓기 지원을 추가하려면 약간의 추가 작업을 수행해야 합니다. 작업이 복잡하게 들릴 수 있겠지만 TransferHandler
의 1.6 내부 DropLocation
클래스의 새로운 기능 덕분에 이 작업은 비교적 쉬워졌습니다. 놓기 가능한 데이터 종류 및 일단 놓은 후에 수행해야 하는 작업에 대해 정의하는 JTree
에 대한 TransferHandler
를 생성하기만 하면 됩니다. 이러한 작업은 각각 canImport!
및 import!Data
메소드로 제공됩니다. TransferSupport
내부 클래스는 1.6의 새로운 기능으로, 전송 처리기를 정의하는 보다 간단한 방법을 제공해 줍니다.
이미지나 텍스트를 나뭇잎에 놓도록 허용하는 멋진 JTree
를 작성할 수 있지만 다음 예제는 문자열만 수락합니다. 이미지도 수락하도록 예제를 활용해 보십시오. 문자열을 지원하려면 TransferHandler.TransferSupport
인수로 canImport!
메소드를 정의해서 지원되는 데이터 유형(문자열) 및 작업 유형을 확인해야 합니다. TransferSupport
에는 작업의 TransferHandler.DropLocation
을 가져오는 getDropLocation
메소드도 있습니다. 위치가 유효한 지점이면 canImport!
메소드는 참을 반환해야 합니다. 다음은 널이 아닌 트리 경로에서 문자열 유형의 놓기 전송에 대해 참을 반환하는 메소드입니다.
public boolean canImport!(TransferHandler.TransferSupport support) { if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) { return false; } JTree.DropLocation dropLocation = (JTree.DropLocation)support.getDropLocation(); return dropLocation.getPath() != null; } |
JTree.DropLocation
은 JTree
구성요소에 대한 TransferHandler.DropLocation
의 사전 정의된 구현입니다. JList
로 작업하기 위한 JList.DropLocation
및 JTree.DropLocation
이 있는 JTree
에 대한 다른 것도 있습니다. 기본 텍스트 구성요소 놓기 처리 동작을 원하지 않을 경우 JTextComponent.DropLocation
에 네 번째 구현이 있습니다.
JTree
에 놓기 지원을 추가하는 나머지 역할은 import!Data
메소드가 수행합니다. import!Data
메소드의 이전 버전인 import!Data(JComponent comp, Transferable t)
는 직접 호출되지 않지만 여전히 지원됩니다. 새로운 처리기는 실제로 import!Data(TransferHandler.TransferSupport support)
버전을 대신 구현해야 합니다. 이 메소드에서 전송된 데이터를 얻어 TreePath
의 올바른 위치에 배치해야 합니다.
전송된 데이터를 얻어도 이전 import!Data
메소드에서 새 메소드로 이동하는 데는 실제로 영향을 주지 않습니다. 메소드에 Transferable 인수를 가지는 대신 support.getTransferable
메소드로 TransferSupport
에서 가져옵니다. 그런 다음 적절한 유형의 데이터를 가져오기만 하면 됩니다.
Transferable transferable = support.getTransferable(); String transferData; try { transferData = (String)transferable.getTransferData( DataFlavor.stringFlavor); } catch (IOException e) { return false; } catch (UnsupportedFlavorException e) { return false; } |
놓기 작업의 위치를 결정하려면 JTree.DropLocation
클래스를 사용하십시오. DropLocation
의 getChildIndex
메소드를 호출하면 트리에 새 노드를 추가할 위치가 제공됩니다. -1의 하위 인덱스 값은 사용자가 트리의 빈 부분에 노드를 놓았다는 의미입니다. 이 예제에서는 노드가 끝에 추가됩니다. DropLocation
의 getPath
메소드를 호출하면 놓기 위치에 대해 TreePath
를 반환합니다. 그런 다음 놓기 위치와 연관된 상위 노드를 찾으려면 경로의 getLastPathComponent
메소드를 호출하십시오.
JTree.DropLocation dropLocation = (JTree.DropLocation)support.getDropLocation(); TreePath path = dropLocation.getPath(); int childIndex = dropLocation.getChildIndex(); if (childIndex == -1) { childIndex = model.getChildCount(path.getLastPathComponent()); } DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData); DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)path.getLastPathComponent(); model.insertNodeInto(newNode, parentNode, childIndex); |
새 경로 요소가 표시되는지 확인하는 것도 도움이 됩니다. 전체 import!Data
메소드는 다음과 같습니다.
public boolean import!Data(TransferHandler.TransferSupport support) { if (!canImport!(support)) { return false; } JTree.DropLocation dropLocation = (JTree.DropLocation)support.getDropLocation(); TreePath path = dropLocation.getPath(); Transferable transferable = support.getTransferable(); String transferData; try { transferData = (String)transferable.getTransferData( DataFlavor.stringFlavor); } catch (IOException e) { return false; } catch (UnsupportedFlavorException e) { return false; } int childIndex = dropLocation.getChildIndex(); if (childIndex == -1) { childIndex = model.getChildCount(path.getLastPathComponent()); } DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData); DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)path.getLastPathComponent(); model.insertNodeInto(newNode, parentNode, childIndex); TreePath newPath = path.pathByAddingChild(newNode); tree.makeVisible(newPath); tree.scrollRectToVisible(tree.getPathBounds(newPath)); return true; } |
완전히 작동하는 놓기 가능한 JTree
를 가지도록 충분한 정보를 자세히 보여 드렸습니다. 여기서 놓기 지원에 관련된 중요한 정보인 DropMode
에 대해 알려드리겠습니다. DropMode
는 구성요소에서 놓기 작업이 발생되는 위치를 표시하는 방식에 관한 모드를 열거한 것입니다. JTree
에 대해 다음 네 가지 모드가 지원됩니다.
DropMode.USE_SELECTION
DropMode.ON
DropMode.INSERT
DropMode.ON_OR_INSERT
그러나 열거는 다른 구성요소의 특정 모드에 대해 더 커집니다(JTable
로 작업할 경우 INSERT_COLS
또는 INSERT_ROWS
).
놓기 모드는 어떻게 처리할까요? 기본적으로 이 모드는 USE_SELECTION
입니다. 이것은 JTree
에서 선택된 항목을 더 이상 강조 표시하지 않음을 의미합니다. 대신 선택 메커니즘을 사용하여 놓기 위치를 강조 표시하십시오. JTree
가 놓기를 지원하면 기본값을 변경하는 것이 좋습니다. 더 나은 모드는 on입니다. 이 모드를 사용하여 JTree
및 잠재적 놓기 위치에서 현재 선택을 모두 확인할 수 있습니다. INSERT
모드를 사용하여 현재 선택 사항을 보면서 기존 노드 사이에 새 노드를 삽입할 수 있습니다. ON_OR_INSERT
는 후자 두 개를 결합한 것입니다. 다음 그림 4개는 네 가지 옵션을 보여 줍니다. 완료된 프로그램은 다른 동작을 시도하도록 모드 콤보 상자를 제공합니다.
|
|
|
|
다음은 놓기 가능한 전체 트리 프로그램입니다. 프로그램에는 중간에 선택하여 JTree
에 놓을 수 있는 텍스트 항목의 맨 위에 텍스트 영역이 있습니다. 놓기 모드는 맨 아래의 콤보 상자에서 설정할 수 있습니다. 트리에 대한 데이터 모델은 JTree
를 작성할 때 지정되지 않은 경우 작성된 기본 모델에서 나옵니다.
import! java.awt.*; import! java.awt.datatransfer.*; import! java.awt.event.*; import! java.io.*; import! javax.swing.*; import! javax.swing.tree.*; public class DndTree { public static void main(String args[]) { Runnable runner = new Runnable() { public void run() { JFrame f = new JFrame("D-n-D JTree"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel top = new JPanel(new BorderLayout()); JLabel dragLabel = new JLabel("Drag me:"); JTextField text = new JTextField(); text.setDragEnabled(true); top.add(dragLabel, BorderLayout.WEST); top.add(text, BorderLayout.CENTER); f.add(top, BorderLayout.NORTH); final JTree tree = new JTree(); final DefaultTreeModel model = (DefaultTreeModel)tree.getModel(); tree.setTransferHandler(new TransferHandler() { public boolean canImport!(TransferHandler.TransferSupport support) { if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) { return false; } JTree.DropLocation dropLocation = (JTree.DropLocation)support.getDropLocation(); return dropLocation.getPath() != null; } public boolean import!Data(TransferHandler.TransferSupport support) { if (!canImport!(support)) { return false; } JTree.DropLocation dropLocation = (JTree.DropLocation)support.getDropLocation(); TreePath path = dropLocation.getPath(); Transferable transferable = support.getTransferable(); String transferData; try { transferData = (String)transferable.getTransferData( DataFlavor.stringFlavor); } catch (IOException e) { return false; } catch (UnsupportedFlavorException e) { return false; } int childIndex = dropLocation.getChildIndex(); if (childIndex == -1) { childIndex = model.getChildCount(path.getLastPathComponent()); } DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData); DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)path.getLastPathComponent(); model.insertNodeInto(newNode, parentNode, childIndex); TreePath newPath = path.pathByAddingChild(newNode); tree.makeVisible(newPath); tree.scrollRectToVisible(tree.getPathBounds(newPath)); return true; } }); JScrollPane pane = new JScrollPane(tree); f.add(pane, BorderLayout.CENTER); JPanel bottom = new JPanel(); JLabel comboLabel = new JLabel("DropMode"); String options[] = {"USE_SELECTION", on", "INSERT", on_OR_INSERT" }; final DropMode mode[] = {DropMode.USE_SELECTION, DropMode.ON, DropMode.INSERT, DropMode.ON_OR_INSERT}; final JComboBox combo = new JComboBox(options); combo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int selectedIndex = combo.getSelectedIndex(); tree.setDropMode(mode[selectedIndex]); } }); bottom.add(comboLabel); bottom.add(combo); f.add(bottom, BorderLayout.SOUTH); f.setSize(300, 400); f.setVisible(true); } }; EventQueue.invokeLater(runner); } } |
끌어서 놓기 지원 및 데이터 전송 API에 대한 자세한 내용은
자바 온라인 자습서의 Introduction to Drag and Drop and Data Transfer 내역을 참조하십시오.
'IT_Programming > Java' 카테고리의 다른 글
jxl을 통한 엑셀 저장하기 (0) | 2008.01.25 |
---|---|
클래스에서 enhanced For-Loop 사용 (0) | 2008.01.24 |
JavaTM Web Start (0) | 2008.01.23 |
[Tip] Java Main Class를 .exe파일로 실행시키는 방법 (0) | 2008.01.22 |
일시적 태스크 실행시에 쓰레드 풀링 이용하기 (0) | 2007.11.22 |