Swing/DnDBetweenTrees のバックアップ(No.1)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/DnDBetweenTrees へ行く。
- title: JTree間でのドラッグ&ドロップによるノードの移動 tags: [JTree, DragAndDrop, TransferHandler] author: aterai pubdate: 2016-02-22T00:58:53+09:00 description: JTree間でのドラッグ&ドロップによるノードの移動を行います。
概要
JTree
間でのドラッグ&ドロップによるノードの移動を行います。
Screenshot
Advertisement
サンプルコード
class TreeTransferHandler extends TransferHandler {
private static final DataFlavor FLAVOR = new ActivationDataFlavor(
DefaultMutableTreeNode[].class,
DataFlavor.javaJVMLocalObjectMimeType,
"Array of DefaultMutableTreeNode");
private JTree source;
@Override protected Transferable createTransferable(JComponent c) {
source = (JTree) c;
TreePath[] paths = source.getSelectionPaths();
DefaultMutableTreeNode[] nodes = new DefaultMutableTreeNode[paths.length];
for (int i = 0; i < paths.length; i++) {
nodes[i] = (DefaultMutableTreeNode) paths[i].getLastPathComponent();
}
return new DataHandler(nodes, FLAVOR.getMimeType());
}
@Override public int getSourceActions(JComponent c) {
return MOVE;
}
@Override public boolean canImport(TransferHandler.TransferSupport support) {
if (!support.isDrop()) {
return false;
}
if (!support.isDataFlavorSupported(FLAVOR)) {
return false;
}
JTree tree = (JTree) support.getComponent();
return !tree.equals(source);
}
@Override public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
DefaultMutableTreeNode[] nodes = null;
try {
Transferable t = support.getTransferable();
nodes = (DefaultMutableTreeNode[]) t.getTransferData(FLAVOR);
} catch (UnsupportedFlavorException | IOException ex) {
ex.printStackTrace();
}
TransferHandler.DropLocation tdl = support.getDropLocation();
if (tdl instanceof JTree.DropLocation) {
JTree.DropLocation dl = (JTree.DropLocation) tdl;
int childIndex = dl.getChildIndex();
TreePath dest = dl.getPath();
DefaultMutableTreeNode parent =
(DefaultMutableTreeNode) dest.getLastPathComponent();
JTree tree = (JTree) support.getComponent();
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
int idx = childIndex < 0 ? parent.getChildCount() : childIndex;
//DefaultTreeModel sm = (DefaultTreeModel) source.getModel();
for (DefaultMutableTreeNode node : nodes) {
//sm.removeNodeFromParent(node);
//model.insertNodeInto(node, parent, idx++);
DefaultMutableTreeNode clone = new DefaultMutableTreeNode(node.getUserObject());
model.insertNodeInto(deepCopyTreeNode(node, clone), parent, idx++);
}
return true;
}
return false;
}
private static DefaultMutableTreeNode deepCopyTreeNode(
DefaultMutableTreeNode src, DefaultMutableTreeNode tgt) {
for (int i = 0; i < src.getChildCount(); i++) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) src.getChildAt(i);
DefaultMutableTreeNode clone = new DefaultMutableTreeNode(node.getUserObject());
tgt.add(clone);
if (!node.isLeaf()) {
deepCopyTreeNode(node, clone);
}
}
return tgt;
}
@Override protected void exportDone(
JComponent source, Transferable data, int action) {
if (action == MOVE) {
JTree tree = (JTree) source;
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
for (TreePath path : tree.getSelectionPaths()) {
model.removeNodeFromParent((MutableTreeNode) path.getLastPathComponent());
}
}
}
}
View in GitHub: Java, Kotlin解説
上記のサンプルでは、JTree
間でのノード移動を可能にするTransferHanlder
を作成して、JTree#setTransferHandler(...)
で設定しています。
TransferHandler#importData(...)
メソッド内で、ドラッグして移動するDefaultMutableTreeNode
をドラッグ元のDefaultTreeModel
から削除せずに、DefaultTreeModel#insertNodeInto(...)
メソッドでドロップ先のJTree
のDefaultTreeModel
に挿入すると、ノードの親子関係がおかしくなって、ドラッグ元のJTree
からDefaultTreeModel#removeNodeFromParent(...)
メソッドでノードを削除できなくなります(DefaultTreeModel.reload()
ですべて再評価すると正常に表示されるが、ノードがすべて折り畳まれてしまう)。これを避けるために、移動するDefaultMutableTreeNode
のクローン(親ノードは未設定)を作成してドロップ元に追加し、ドラッグ元からの削除はTransferHandler#exportDone(...)
で実行するようにしています。
- 制限:
- 同一
JTree
内でのノード入れ替えには未対応 TreeSelectionModel.SINGLE_TREE_SELECTION
で選択、移動できるのは1
ノードのみに制限TransferHandler.MOVE
で移動のみに対応- ルートノードは、
JTree#setRootVisible(false)
で非表示にして移動禁止
- 同一