2008年1月3日木曜日

Java6 JTree クリップボードにコピー、切り取り、貼り付けテスト + ファイルドロップ、コピペ


package JTreeClipBoardTest2;
import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.InputEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

/**
* Java6 JTree ClipBoard Copy Cut Paste Test + File Drop Copy Paste

* Java6 JTree クリップボードにコピー、切り取り、貼り付けテスト + ファイルドロップ、コピペ

*

* サンプルなので1つのファイルに必要なクラスを全部詰め込んであります。

*

* 起動すると、JTreeが2枚表示されます。

* JTree間でコピペ、カトペ、ドラッグアンドドロップできます。

* 他のアプリケーションからドロップしようとしても禁止マークがでます。

* DnDでムーブ、Ctrl+DnDでコピーも有効です。

* ※JTreeDnDTest.javaをベースに作成したのですが、コピペ対応のために弄ってる間に、対応できちゃったようです。

*

* エクスプローラからのファイルのコピペ、DnDに対応します。

* 文字列のコピペ、DnDも対応してみました。

*

* 自分自身にドロップ禁止、子ノードにドロップ禁止してみた。

* canImportの中で判定するとうまくいかなかったので、ドロップ後に判定するようにしてみた。(canImport2)

* exportAsDragで、JTreeをクラス変数に設定して、exportDoneでクラス変数をnullに設定。

* importDataのJComponentと、クラス変数が同じ場合、ツリーパスの判定を行う。

*/
public class JTreeClipBoardTest2 {

/**
* @param args
*/
public static void main(String[] args) {
JFrame f = new JFrame();
JTree t = new MyTree3();
JTree t2 = new MyTree3();
f.add(t, BorderLayout.CENTER);
f.add(t2, BorderLayout.EAST);
f.setSize(200, 200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}

/**
* JTreeを継承して、初期化メソッドと、コピペ、DnD用のセッタゲッタを追加したクラス。
*/
class MyTree3 extends JTree {
public MyTree3() {
super();
init();
}

private void init() {
// ドラッグを許可します。
setDragEnabled(true);
// トランスファハンドラを設定します。
setTransferHandler(new TreePathTransferHandler("selectionPathsDnd"));
// ※selectionPathsDndは、内部でsetほにゃらら、getほにゃららのメソッド検索に使われます。
}
/**
* TransferHandlerのプロパティに対応するため、DnD、コピペ用のセッタゲッタを用意します。
* @return
*/
public TreePath[] getSelectionPathsDnd() {
return getSelectionPaths();
}
/**
* オブジェクトを受けとるインポートメソッド。

* ここからクラスを判定して個別のメソッドを実行します。

* 名前はDndついてますが、コピペでも同じメソッドが使われます。

* @param paths
* @return
*/
public boolean setSelectionPathsDnd(Object obj) {
System.out.println("setSelectionPathsDnd");
System.out.println("class = " + obj.getClass());
if (obj == null) {
return false;
}
if (obj instanceof TreePath[]) {
TreePath[] paths = (TreePath[])obj;
return setSelectionPathsDnd(paths);
}
if (obj instanceof List) {
List files = (List)obj;
return setSelectionPathsDnd(files);
}
if (obj instanceof String) {
String files = obj.toString();
return setSelectionPathsDnd(files);
}
return false;
}
/**
* ファイルリスト用インポートメソッド
*/
public boolean setSelectionPathsDnd(List files) {
if (files == null ) {
return false;
}
List filess = (List)files;
javax.swing.JTree.DropLocation loc = getDropLocation();
TreePath putPath = null;
if (loc != null) {
// ドロップしたパスを取得します。
putPath = loc.getPath();
} else {
// ドロップロケーションがnullだったら、貼り付けと判断して選択済みのパスを取得します。
putPath = getSelectionPath();
}
DefaultMutableTreeNode putNode = (DefaultMutableTreeNode)putPath.getLastPathComponent();
for (File file : filess) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(file.getName());
putNode.add(node);
((DefaultTreeModel)getModel()).reload(putNode);
}
return true;
}
/**
* ツリーパス用インポートメソッド
*/
public boolean setSelectionPathsDnd(TreePath[] paths) {
if (paths == null ) {
return false;
}
javax.swing.JTree.DropLocation loc = getDropLocation();
TreePath putPath = null;
if (loc != null) {
// ドロップしたパスを取得します。
putPath = loc.getPath();
} else {
// ドロップロケーションがnullだったら、貼り付けと判断して選択済みのパスを取得します。
putPath = getSelectionPath();
}
DefaultMutableTreeNode putNode = (DefaultMutableTreeNode)putPath.getLastPathComponent();
for (TreePath path : paths) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
putNode.add(node);
((DefaultTreeModel)getModel()).reload(putNode);
}
return true;
}
/**
* 文字列用インポートメソッド
*/
public boolean setSelectionPathsDnd(String str) {
if (str == null ) {
return false;
}
javax.swing.JTree.DropLocation loc = getDropLocation();
TreePath putPath = null;
if (loc != null) {
// ドロップしたパスを取得します。
putPath = loc.getPath();
} else {
// ドロップロケーションがnullだったら、貼り付けと判断して選択済みのパスを取得します。
putPath = getSelectionPath();
}
DefaultMutableTreeNode putNode = (DefaultMutableTreeNode)putPath.getLastPathComponent();
String[] strAry = str.split("\n");
for (String path : strAry) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(path);
putNode.add(node);
((DefaultTreeModel)getModel()).reload(putNode);
}
return true;
}
}
/**
* ツリーパストランスファハンドラ
*/
class TreePathTransferHandler extends TransferHandler {
JComponent comp;
/**
* コンストラクタ プロパティ設定なし
*/
public TreePathTransferHandler() {
super();
}
/**
* コンストラクタ プロパティ設定あり
*/
public TreePathTransferHandler(String property) {
super(property);
}
/**
* 転送データ作成処理。
*/
@Override
protected Transferable createTransferable(JComponent c){
if (c instanceof MyTree3) {
MyTree3 tree = (MyTree3)c;
Transferable tf = new TreePathTransferable(tree);
return tf;
}
return null;
}
@Override
public void exportAsDrag(JComponent comp, InputEvent e, int action) {
this.comp = comp;
super.exportAsDrag(comp, e, action);
}
/**
* アクションを返します。
*/
@Override
public int getSourceActions(JComponent c) {
// スーパークラスの戻り値がCOPYの場合、COPY_OR_MOVEに変換します。
// ※スーパークラスがCOPYかNONEしか返さないため。
int action = super.getSourceActions(c);
if (action == COPY) {
action = COPY_OR_MOVE;
}
return action;
}
@Override
public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
// 受け入れ可能かどうかを返します。
// ツリーパスフレーバとファイルフレーバ以外のフレーバを受け入れないようにします。
Transferable f = createTransferable(comp);
boolean flg = false;
for (DataFlavor df : transferFlavors) {
if (f.isDataFlavorSupported(df)) {
flg = true;
break;
}
}
return flg;
}

/**
* 出力側のドロップ完了処理。
* actionがMOVEの場合、ツリーを削除します。
* ※importDataがfalseを返した場合、actionはNONEになります。
*/
@Override
protected void exportDone(JComponent source, Transferable data,
int action) {
// 出力完了時にcompとnullに設定します。
comp = null;
if (!(source instanceof JTree)) {
return;
}
MyTree3 tree = (MyTree3)source;
if (action == MOVE) {
try {
for (DataFlavor df : data.getTransferDataFlavors()) {
Object obj = data.getTransferData(df);
// エクスポートの場合、処理するのはTreePathの場合だけでよい。
if (obj instanceof TreePath[]) {
TreePath[] patha = (TreePath[])obj;
TreePath path = patha[0];
Object oo = path.getLastPathComponent();
DefaultMutableTreeNode node = (DefaultMutableTreeNode)oo;
node.removeFromParent();
((DefaultTreeModel)tree.getModel()).reload(node);
}
if (obj instanceof List) {
super.exportDone(source, data, action);
}
}
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
} else {
super.exportDone(source, data, action);
}
}
/**
* 入力側のドロップ処理。
* ドロップされたノードに、ドラッグされたノードを追加します。
*/
@Override
public boolean importData(JComponent comp, Transferable t) {
if (!(comp instanceof MyTree3)) {
return false;
}
if (!canImport(comp, t.getTransferDataFlavors())) {
return false;
}
if (!canImport2(comp, t)) {
return false;
}
MyTree3 tree = (MyTree3)comp;
DataFlavor[] dfa = t.getTransferDataFlavors();
for (DataFlavor df : dfa) {
try {
if (tree.setSelectionPathsDnd(t.getTransferData(df))) {
return true;
}
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}

}
return false;
}
private boolean canImport2(JComponent comp, Transferable t) {
boolean flg = true;
if (comp == this.comp) {
try {
// 同じJTreeにドロップする場合。
MyTree3 tree = (MyTree3)comp;
if (tree.getDropLocation() != null) {
TreePath dropPath = tree.getDropLocation().getPath();
TreePath[] paths = (TreePath[])t.getTransferData(TreePathDataFravor.treePathFlavor);
for (TreePath dragPath : paths) {
if (dragPath.getPathCount() > dropPath.getPathCount()) {
continue;
}
if (dropPath.equals(dragPath)) {
flg = false;
break;
}
Object[] dragPathObject = dragPath.getPath();
Object[] dropPathObject = dropPath.getPath();
boolean sameFlg = true;
for (int i = 0; i < dragPathObject.length; i++) {
if (!dragPathObject[i].toString().equals(dropPathObject[i].toString())) {
sameFlg = false;
break;
}
}
if (sameFlg == true) {
flg = false;
break;
}
}
} else {
flg = false;
}
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
System.out.println(flg);
return flg;
}
}
/**
* ツリーパスデータフレーバクラス。
* 作ったはいいけど、ツリーパスフレーバーの定数を保管しているだけである。
*/
class TreePathDataFravor extends DataFlavor {
public static final DataFlavor treePathFlavor = new DataFlavor(TreePath[].class, javaJVMLocalObjectMimeType);

}
/**
* ツリーパス用トランスファエイブル
* ツリーパスの配列と、データフレーバーの配列を持つ。
*/
class TreePathTransferable implements Transferable
{
TreePath[] paths;
// ツリーパスフレーバとファイルリストフレーバ
static final DataFlavor[] dflv = {
TreePathDataFravor.treePathFlavor, // ツリーパスフレーバ
TreePathDataFravor.javaFileListFlavor, // ファイルリストフレーバ
TreePathDataFravor.stringFlavor // 文字列フレーバ
};

public TreePathTransferable(TreePath[] paths){
this.paths = paths;
}
public TreePathTransferable(MyTree3 tree) {
this(tree.getSelectionPathsDnd());
}
/**
* オブジェクト取得メソッド。

* フレーバに対応したオブジェクトを返します。

*/
@Override
public Object getTransferData(DataFlavor flavor){
if (TreePathDataFravor.treePathFlavor.equals(flavor)) {
// ツリーパスフレーバの場合
return paths;
} else if (TreePathDataFravor.javaFileListFlavor.equals(flavor)) {
// ファイルリストフレーバの場合
// ※偶然ファイルが存在しない限り、何も転送できない筈です。
List files = new ArrayList();
for (TreePath path : paths) {
files.add(new File(path.getLastPathComponent().toString()));
}
return files;
} else if (TreePathDataFravor.stringFlavor.equals(flavor)) {
// 文字列フレーバの場合
StringBuffer sb = new StringBuffer();
for (TreePath path : paths) {
sb.append(path.getLastPathComponent().toString() + "\n");
}
return sb.toString();
}
return null;
}
@Override
public DataFlavor[] getTransferDataFlavors(){
return dflv;
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor){
DataFlavor[] flv = getTransferDataFlavors();
for(int i = 0 ; i < flv.length ; i++){
if(flv[i].equals(flavor)){
return true;
}
}
return false;
}
}


//

Java6 JTree クリップボードにコピー、切り取り、貼り付けテスト


package JTreeClipBoardTest;
import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

/**
* Java6 JTree ClipBoard Copy Cut Paste Test

* Java6 JTree クリップボードにコピー、切り取り、貼り付けテスト

*

* 起動すると、JTreeが2枚表示されます。

* JTree間でコピペ、カトペ、ドラッグアンドドロップできます。

* 他のアプリケーションからドロップしようとしても禁止マークがでます。

* DnDでムーブ、Ctrl+DnDでコピーも有効です。

* ※JTreeDnDTest.javaをベースに作成したのですが、コピペ対応のために弄ってる間に、対応できちゃったようです。

*/
public class JTreeClipBoardTest {

/**
* @param args
*/
public static void main(String[] args) {
JFrame f = new JFrame();
JTree t = new MyTree3();
JTree t2 = new MyTree3();
f.add(t, BorderLayout.CENTER);
f.add(t2, BorderLayout.EAST);
f.setSize(200, 200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}

/**
* JTreeを継承して、初期化メソッドと、コピペ、DnD用のセッタゲッタを追加したクラス。
*/
class MyTree3 extends JTree {
public MyTree3() {
super();
init();
}

private void init() {
// ドラッグを許可します。
setDragEnabled(true);
// トランスファハンドラを設定します。
setTransferHandler(new TreePathTransferHandler("selectionPathsDnd"));
// ※selectionPathsDndは、内部でsetほにゃらら、getほにゃららのメソッド検索に使われます。
}
/**
* TransferHandlerのプロパティに対応するため、DnD、コピペ用のセッタゲッタを用意します。
* @return
*/
public TreePath[] getSelectionPathsDnd() {
return getSelectionPaths();
}
/**
* 名前はDndついてますが、コピペでも同じメソッドが使われます。
* @param paths
* @return
*/
public boolean setSelectionPathsDnd(TreePath[] paths) {
if (paths == null ) {
return false;
}
javax.swing.JTree.DropLocation loc = getDropLocation();
TreePath putPath = null;
if (loc != null) {
// ドロップしたパスを取得します。
putPath = loc.getPath();
} else {
// ドロップロケーションがnullだったら、貼り付けと判断して選択済みのパスを取得します。
putPath = getSelectionPath();
}
DefaultMutableTreeNode putNode = (DefaultMutableTreeNode)putPath.getLastPathComponent();
for (TreePath path : paths) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
putNode.add(node);
((DefaultTreeModel)getModel()).reload();
}
return true;
}
}
/**
* ツリーパストランスファハンドラ
*/
class TreePathTransferHandler extends TransferHandler {
/**
* コンストラクタ プロパティ設定なし
*/
public TreePathTransferHandler() {
super();
}
/**
* コンストラクタ プロパティ設定あり
*/
public TreePathTransferHandler(String property) {
super(property);
}
/**
* 転送データ作成処理。
*/
@Override
protected Transferable createTransferable(JComponent c){
if (c instanceof MyTree3) {
MyTree3 tree = (MyTree3)c;
Transferable tf = new TreePathTransferable(tree);
return tf;
}
return super.createTransferable(c);
}
/**
* アクションを返します。
*/
@Override
public int getSourceActions(JComponent c) {
// スーパークラスの戻り値がCOPYの場合、COPY_OR_MOVEに変換します。
// ※スーパークラスがCOPYかNONEしか返さないため。
int action = super.getSourceActions(c);
if (action == COPY) {
action = COPY_OR_MOVE;
}
return action;
}
@Override
public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
// 受け入れ可能かどうかを返します。
// ツリーパスフレーバ以外のフレーバを受け入れないようにします。
for (DataFlavor df : transferFlavors) {
if (!df.equals(TreePathDataFravor.treePathFravor)) {
return false;
}
}
return true;
}

/**
* 出力側のドロップ完了処理。
* actionがMOVEの場合、ツリーを削除します。
* ※importDataがfalseを返した場合、actionはNONEになります。
*/
@Override
protected void exportDone(JComponent source, Transferable data,
int action) {
if (!(source instanceof JTree)) {
return;
}
MyTree3 tree = (MyTree3)source;
if (action == MOVE) {
try {
for (DataFlavor df : data.getTransferDataFlavors()) {
TreePath[] patha = (TreePath[]) data.getTransferData(df);
TreePath path = patha[0];
Object oo = path.getLastPathComponent();
DefaultMutableTreeNode node = (DefaultMutableTreeNode)oo;
node.removeFromParent();
((DefaultTreeModel)tree.getModel()).reload();
}
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
} else {
super.exportDone(source, data, action);
}
}
/**
* 入力側のドロップ処理。
* ドロップされたノードに、ドラッグされたノードを追加します。
*/
@Override
public boolean importData(JComponent comp, Transferable t) {
if (!(comp instanceof MyTree3)) {
return false;
}
if (!canImport(comp, t.getTransferDataFlavors())) {
return false;
}
MyTree3 tree = (MyTree3)comp;
DataFlavor[] dfa = t.getTransferDataFlavors();
for (DataFlavor df : dfa) {
try {
TreePath[] orgPathA = (TreePath[])t.getTransferData(df);
return tree.setSelectionPathsDnd(orgPathA);
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}

}
return false;
}
}
/**
* ツリーパスデータフレーバクラス。
* 作ったはいいけど、ツリーパスフレーバーの定数を保管しているだけである。
*/
class TreePathDataFravor extends DataFlavor {
public static final DataFlavor treePathFravor = new DataFlavor(TreePath[].class, javaJVMLocalObjectMimeType);
}
/**
* ツリーパス用トランスファエイブル
* ツリーパスの配列と、データフレーバーの配列を持つ。
*/
class TreePathTransferable implements Transferable
{
TreePath[] paths;
// データフレーバ(フレーバ=食品への風味付け)
static final DataFlavor[] dflv = {TreePathDataFravor.treePathFravor};

public TreePathTransferable(TreePath[] paths){
this.paths = paths;
}
public TreePathTransferable(MyTree3 tree) {
this(tree.getSelectionPathsDnd());
}
@Override
public Object getTransferData(DataFlavor flavor){
for (DataFlavor df : dflv) {
if (df.equals(flavor)){
return paths;
}
}
return null;
}
@Override
public DataFlavor[] getTransferDataFlavors(){
return dflv;
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor){
DataFlavor[] flv = getTransferDataFlavors();
for(int i = 0 ; i < flv.length ; i++){
if(flv[i].equals(flavor)){
return true;
}
}
return false;
}
}

2008年1月2日水曜日

Java6 JTree DnD Test(ドラッグアンドドロップテスト)

ugnagさんの解説を元に作成しました。

1.ドラッグを許可します。
2.トランスファハンドラを設定します。
3.転送データを作成します。
4.アクションを返します。
5.ドロップ可能かどうかを返します。
6.ドロップされたデータを受け取ります。
7.ドロップ完了後の処理をします。



import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

/**
* Java6 JTree DnD Test
* Java6 JTree ドラッグアンドドロップテスト
* http://ugnag.lar.jp/pgm/java/dd/index.html
* ※ugnagさんの解説を元に作成しました。
*/
public class JTreeDnDTest {

/**
* @param args
*/
public static void main(String[] args) {
JFrame f = new JFrame();
JTree t = new MyTree3();
JTree t2 = new MyTree3();
f.add(t, BorderLayout.CENTER);
f.add(t2, BorderLayout.EAST);
f.setSize(200, 200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}

class MyTree3 extends JTree {
public MyTree3() {
super();
init();
}

private void init() {
// 1.ドラッグを許可します。
setDragEnabled(true);
// 2.トランスファハンドラを設定します。
setTransferHandler(new TreePathTransferHandler());
}
}
/**
* ツリーパストランスファハンドラ
*
*/
class TreePathTransferHandler extends TransferHandler {
@Override
protected Transferable createTransferable(JComponent c){
// 3.転送データを作成します。
if (c instanceof JTree) {
JTree tree = (JTree)c;
TreePath[] paths = tree.getSelectionPaths();

return new TreePathTransferable(paths);
}
return null;
}
@Override
public int getSourceActions(JComponent c) {
// 4.アクションを返します。
// 今回は無条件にMOVEとする。
return MOVE;
}
@Override
public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
// 5.ドロップ可能かどうかを返します。
// 受け入れ判定をせずに、無条件でTRUE。FALSEを返すと、UIでドロップ禁止となる。
return true;
}
/**
* 出力側のドロップ完了処理。
* actionがMOVEの場合、ツリーを削除します。
* ※importDataがfalseを返した場合、actionはNONEになります。
*/
@Override
protected void exportDone(JComponent source, Transferable data,
int action) {
// 7.ドロップ完了後の処理をします。
if (!(source instanceof JTree)) {
return;
}
JTree tree = (JTree)source;
if (action == MOVE) {
for (DataFlavor df : data.getTransferDataFlavors()) {
try {
TreePath[] patha = (TreePath[]) data.getTransferData(df);
TreePath path = patha[0];
Object oo = path.getLastPathComponent();
DefaultMutableTreeNode node = (DefaultMutableTreeNode)oo;
node.removeFromParent();
((DefaultTreeModel)tree.getModel()).reload();
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
} else {
super.exportDone(source, data, action);
}
}
/**
* 入力側のドロップ処理。
* ドロップされたノードに、ドラッグされたノードを追加します。
*/
@Override
public boolean importData(JComponent comp, Transferable t) {
// 6.ドロップされたデータを受け取ります。
if (!(comp instanceof JTree)) {
return false;
}
JTree tree = (JTree)comp;
javax.swing.JTree.DropLocation loc = tree.getDropLocation();
TreePath path = loc.getPath();
DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
DataFlavor[] dfa = t.getTransferDataFlavors();
for (DataFlavor df : dfa) {
try {
TreePath[] orgPathA = (TreePath[])t.getTransferData(df);
for (TreePath orgPath : orgPathA) {
DefaultMutableTreeNode oNode = (DefaultMutableTreeNode)orgPath.getLastPathComponent();
node.add(oNode);
}
((DefaultTreeModel)tree.getModel()).reload();
return true;
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}

}
return true;
}
}

/**
* ツリーパス用トランスファエイブル
* ツリーパスの配列と、データフレーバーの配列を持つ。
* http://ugnag.lar.jp/docs/java/dd/index.html
* ※ugnagさんのコードをほぼそのまま利用しています。
*/
class TreePathTransferable implements Transferable
{
TreePath[] paths;
// データフレーバ(フレーバ=食品への風味付け)
DataFlavor[] dflv;

public TreePathTransferable(TreePath[] paths){
this.paths = paths;
dflv = new DataFlavor[]{new DataFlavor(TreePath[].class, "array of TreePath")};
}
@Override
public Object getTransferData(DataFlavor flavor){
for (DataFlavor df : dflv) {
if (df.getMimeType().equals(flavor.getMimeType())){
if (df.getClass().equals(flavor.getClass())){
return paths;
}
}
}
return null;
}
@Override
public DataFlavor[] getTransferDataFlavors(){
return dflv;
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor){
DataFlavor[] flv = getTransferDataFlavors();
for(int i = 0 ; i < flv.length ; i++){
if(flv[i].equals(flavor)){
return true;
}
}
return false;
}
}



1.ドラッグを許可します。

2.トランスファハンドラを設定します。

3.転送データを作成します。
ドラッグ操作を契機に呼び出されます。

4.アクションを返します。
NONE,COPY,MOVE,COPY_OR_MOVE,LINKの5種類があります。
NONE,COPY,MOVEまではいいとして、COPY_OR_MOVE,LINKが謎です。

5.ドロップ可能かどうかを返します。
ドロップ可能な場合TRUE。ドロップ不可の場合FALSEを返します。
FALSEを返すと、マウスカーソルが車両通行止めになります。

6.ドロップされたデータを受け取ります。
3.で作成したデータを受け取ります。
JTree.getDropLocation().getPath()で、どのツリーパスにドロップされたかが分ります。
今回はドラッグしたツリーを、ドロップされたツリーに追加しています。

7.ドロップ完了後の処理をします。
6.でFALSEを返すと、パラメータのアクションがNONEになります。
今回は、MOVEの場合だけ、ドラッグしたツリーを削除しています。

2008年1月1日火曜日

JAVA6 Swing JTreeでヒントの表示 ヒントの表示位置を、ツリーアイテムに被せる(winのエクスプローラ風)



1.JTreeをツールチップマネージャーに登録します。
2.セルレンダラを設定します。
3.セルレンダラのgetToolTipText(MouseEvent event)を実装(オーバーライド)します。
4.JTreeのgetToolTipLocation(MouseEvent event)を実装(オーバーライド)します。(new!!)


import java.awt.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTree;
import javax.swing.ToolTipManager;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;


public class JTreeHintTest2 {

/**
* @param args
*/
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(200, 200);
JTree t = new MyTree2();
ToolTipManager.sharedInstance().registerComponent(t); // 1.JTreeをツールチップマネージャーに登録します。
t.setCellRenderer(new MyRendrer2()); // 2.セルレンダラを設定します。
f.add(t);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class MyRendrer2 extends DefaultTreeCellRenderer {
// 3.セルレンダラのgetToolTipText(MouseEvent event)を実装します。
@Override
public String getToolTipText(MouseEvent event) {
return getText();
}
}

class MyTree2 extends JTree {
// 4.JTreeのgetToolTipLocation(MouseEvent event)を実装(オーバーライド)します。
@Override
public Point getToolTipLocation(MouseEvent event) {
Point p = null;
if(event != null) {
p = event.getPoint();
int selRow = getRowForLocation(p.x, p.y);
TreeCellRenderer r = getCellRenderer();

if(selRow != -1 && r != null) {
TreePath path = getPathForRow(selRow);
Object lastPath = path.getLastPathComponent();
Component rComponent = r.getTreeCellRendererComponent
(this, lastPath, isRowSelected(selRow),
isExpanded(selRow), getModel().isLeaf(lastPath), selRow,
true);

if(rComponent instanceof TreeCellRenderer) {
JLabel r2 = (JLabel)rComponent;
Rectangle pathBounds = getPathBounds(path);
int iconWidth = r2.getIcon().getIconWidth();
p = new Point(pathBounds.x + iconWidth, pathBounds.y);
}
}
}
return p;
}
}



■ 解説
1.JTreeをツールチップマネージャーに登録します。
ヒントを表示するには、まずツールチップマネージャーにコンポーネントを登録する必要があります。

2.セルレンダラを設定します。
ヒントに表示する文字列は、セルレンダラのgetToolTipText(MouseEvent event)から取得されます。
よって、getToolTipText(MouseEvent event)を実装したセルレンダラをJTreeに設定する必要があります。

3.セルレンダラのgetToolTipText(MouseEvent event)を実装します。
2.と同じなので割愛。

4.JTreeのgetToolTipLocation(MouseEvent event)を実装(オーバーライド)します。
ヒントの表示位置は、JTreeのgetToolTipLocation(MouseEvent event)で設定します。

JTreeにはデフォルトの実装がありますが、これをオーバーライドして自分好みの座標に変換します。
今回のコードは、デフォルトの実装をコピペして改造した物です。

Rectangle pathBounds = getPathBounds(path);
int iconWidth = r2.getIcon().getIconWidth();
p = new Point(pathBounds.x + iconWidth, pathBounds.y);

アイテムの表示位置の端っこに、アイコンの幅だけ横にずらした座標を設定しています。

JAVA6 Swing JTreeでヒントの表示



1.JTreeをツールチップマネージャーに登録します。
2.セルレンダラを設定します。
3.セルレンダラのgetToolTipText(MouseEvent event)を実装します。


import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.ToolTipManager;
import javax.swing.tree.DefaultTreeCellRenderer;


public class JTreeHintTest {

/**
* @param args
*/
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(200, 200);
JTree t = new MyTree();
ToolTipManager.sharedInstance().registerComponent(t); // 1.JTreeをツールチップマネージャーに登録します。
t.setCellRenderer(new MyRendrer()); // 2.セルレンダラを設定します。
f.add(t);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

}

class MyRendrer extends DefaultTreeCellRenderer {
// 3.セルレンダラを設定します。
@Override
public String getToolTipText(MouseEvent event) {
return getText();
}
}

class MyTree extends JTree {
@Override
public String getToolTipText(MouseEvent event) {
return super.getToolTipText(event);
}
}



■ 解説
1.JTreeをツールチップマネージャーに登録します。
ヒントを表示するには、まずツールチップマネージャーにコンポーネントを登録する必要があります。

2.セルレンダラを設定します。
ヒントに表示する文字列は、セルレンダラのgetToolTipText(MouseEvent event)から取得されます。
よって、getToolTipText(MouseEvent event)を実装したセルレンダラをJTreeに設定する必要があります。

3.セルレンダラのgetToolTipText(MouseEvent event)を実装します。
2.と同じなので割愛。