学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Javaプログラミング入門その45 JTreeを利用したプログラム

>>この記事には書き直した新しいページがあります。<<


<<前  [TOP]  次>>


断層化されたデータを表示するような場合にはツリーを利用すると便利です。
ツリーを実現するための、コンポーネントは、javax.swing.JTreeですが、JTreeを処理するためのクラスとインターフェイスは、javax.swing.treeパッケージになります。
treeパッケージには、ツリーの表示に関する情報や、内容が編集されたときの動作、内容がある場所の情報、ツリーデータのモデルなどが定義されています。

java.lang.Object
    +--java.awt.Component
        +--java.awt.Container
            +--javax.swing.JComponent
                +--javax.swing.JTree



ツリーは、「ノード」と呼ばれる内容からなっています。
ノードは、子ノードを持つ「ブランチ(branch)・ノード」と、子ノードを持たない「リーフ(leaf)・ノード」と分けることが出来ます。
また、一番基になるノードは「ルート(root)・ノード」と呼ばれます。


以下のようなツリーを生成すると、「Colors」「Sports」「food」という、ブランチ・ノードを持ったサンプルで、ツリーが生成されます。

JTree tree = new JTree();    //サンプルモデルを持つツリーの生成



始めから自分でノードを定義して、ツリーを生成する場合には、javax.swing.treeパッケージのDefaultMutableTreeNodeクラスを使用してノードを作っていき、それらのノードを基にツリーを生成します。
DefaultMutableTreeNodeは、javax.swing.tree.MutableTreeNodeインターフェイスなどを実装しています。
MutableTreeNodeはjavax.swing.tree.TreeNodeインターフェイスを拡張したもので、ノードの挿入や削除、親子間の関係などを定義する場合に使用します。
ノードに子ノードを追加する場合は、「add(MutableTreeNode)」メソッドを用います。

//ノードの生成
DefaultMutableTreeNode root = new DefaultMutableTreeNode("根");
DefaultMutableTreeNode branch = new DefaultMutableTreeNode("枝");
DefaultMutableTreeNode leaf = new DefaultMutableTreeNode("葉");

//ノードに子を追加
root.add(branch);
branch.add(leaf);

//「root」ノードを元にツリーを生成
JTree tree = new JTree(root);



ツリーモデルを使用することで、ノードの情報取得や、追加や削除などの他にも、ツリーの情報が変更された場合の通知なども可能になります。
javax.swing.treeパッケージには、TreeModelインターフェイスを実装したDefaultTreeModelクラスが用意されています。
先のノード生成とあわせて使用すると良いでしょう。

//ノード生成
DefaultMutableTreeNode root = new DefaultMutableTreeNode("根");
DefaultMutableTreeNode branch = new DefaultMutableTreeNode("枝");
DefaultMutableTreeNode leaf = new DefaultMutableTreeNode("葉");

//ノードに子を追加
root.add(branch);
branch.add(leaf);

//ノードからツリーモデルを生成
DefaultTreeModel model = new DefaultTreeModel((TreeNode)root);

//ツリーモデルを元にツリーを生成
JTree tree = new JTree(model); 



JTreeクラスの「setEditable(boolean)」を用いることで、ノードの編集の可否を決めることが出来ます。

JTree tree = new JTree();
tree.setEditable(true);    //ノードの編集可

編集は「トリプルクリック」あるいは「休止をはさんでマウスクリック2回→1200ミリ秒待つ」で始まります。


ツリーで発行されるイベントを取得する手段のひとつとして、マウスイベントを利用する方法があります。
マウスボタンがクリックされた(一番近い)場所からノードを取得することが出来ます。

public class Sample implements MouseListener {

    JTree tree;

    public JTreeTest4() {
        tree = new JTree();
        tree.addMouseListener(this);    //ツリーにマウスイベント追加
     }

    /** マウスが押されたときの処理 */
    public void mousePressed(MouseEvent evt) {
        //クリックされたノードの行数取得
         int selectRow = tree.getRowForLocation(evt.getX(), evt.getY());

        //クリックされたノードのパス取得
         TreePath selectPath = tree.getPathForLocation(evt.getX(), evt.getY());

        //選択されているノードがある場合処理
         if (selectRow != -1) {
            //クリックされたノード名
             String selectName = selectPath.getLastPathComponent().toString();
        }
    }

    /** マウスリスナーを用いたときに必須なメソッド(内容はなし)*/
    public void mouseClicked(MouseEvent evt) { }
    public void mouseReleased(MouseEvent evt) { }
    public void mouseEntered(MouseEvent evt) { }
    public void mouseExited(MouseEvent evt) { }
}



ツリー内の座標を元に「getRowForLocation()」(行数取得)、「getPathForLocation()」(パス取得)などで、クリックされた場所(ノード)を判別することが出来ます。


また、javax.swing.eventパッケージに定義されているリスナやイベントを用いることで、以下のような情報の取得も出来ます。

リスナイベント内容
TreeExpansionListenerTreeExpansionEventツリーがノードの展開や収納を行った
TreeModelListenerTreeModelEventノードの挿入や削除があった
TreeSelectionListenerTreeSelectionEvent選択範囲が変更された
TreeWillExpandListenerTreeExpansionEventツリーがノードの展開や収納を行った(実際に行う前に通知)


ノードの追加は、現在のノードを取得した上で、そのノードに追加します。
また、追加された情報を表示に反映させるにはjavax.swing.tree.TreePathクラスを用いて、再度パスを構築しなおすことが必要です。
追加の一例を示します。
「model」はツリーモデルのインスタンスとします。

//現在選択されているパスを取得
DefaultMutableTreeNode tn =
    (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();

//追加ノード作成
DefaultMutableTreeNode nn = new DefaultMutableTreeNode("新ノード");

//選択されているノードの子ノードとしてモデルに追加
model.insertNodeInto(n, tn, tn.getChildCount());

//ルートノードからの道筋を取得
TreeNode[] nodes = model.getPathToRoot(nn);

//ツリーパスを再生成
TreePath path = new TreePath(nodes);

//選択されたノードが見えるように設定(treeはJTreeのインスタンスとする)
tree.scrollPathToVisible(path); 



また、削除についても方法はいくつかありますが、下記はツリーモデルのメソッドを利用して、親ノードからノードを削除します。

//現在選択されているパスを取得
DefaultMutableTreeNode tn = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();

//親ノードから削除(modelはDefaultTreeModelのインスタンス)
model.removeNodeFromParent(tn);



以下のサンプルプログラムを作成して、実行してみましょう。


【SwingJTreeTest1.java】

/**JTreeのテスト(初期設定のツリーの表示とスクロールとノード名編集の付加)*/

import javax.swing.*;

public class SwingJTreeTest1 {

	private JTree tree;
	private JScrollPane sp;

	/**コンストラクタ*/
	public SwingJTreeTest1(){
		tree = new JTree();		//サンプルモデルを持つツリーを生成
		tree.setEditable(false);	//ノード名編集不可

		sp = new JScrollPane(tree);	//スクロールペインに配置
	}

	/**main() */
	public static void main(String[] args){
		SwingJTreeTest1 tree = new SwingJTreeTest1();

		JFrame frame = new JFrame("JTreeTest1");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(200,200);
		frame.getContentPane().add(tree.sp,"Center");
		frame.setVisible(true);
	}
}



実行すると、ツリー構造が表示されます。
フォルダをクリックすると、内容が表示されます。
ノード名の変更は出来ません。








以下のサンプルプログラムを作成して、実行してみましょう。


【SwingJTreeTest2.java】

import javax.swing.*;

public class SwingJTreeTest2 {

	private JTree tree;
	private JScrollPane sp;

	/**コンストラクタ*/
	public SwingJTreeTest2(){
		tree = new JTree();		//サンプルモデルを持つツリーを生成
		tree.setEditable(true);	//ノード名編集可

		sp = new JScrollPane(tree);	//スクロールペインに配置
	}

	/**main() */
	public static void main(String[] args){
		SwingJTreeTest2 tree = new SwingJTreeTest2();

		JFrame frame = new JFrame("JTreeTest2");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(200,200);
		frame.getContentPane().add(tree.sp,"Center");
		frame.setVisible(true);
	}
}



実行すると、ツリー構造が表示されます。
フォルダをクリックすると、内容が表示されます。
ノード名の変更ができます。
編集は「トリプルクリック」あるいは「休止をはさんでマウスクリック2回→1200ミリ秒待つ」で始まります。








以下のサンプルプログラムを作成して、実行してみましょう。


【SwingJTreeTest3.java】

/**JTreeのテスト(自分でノードを作成する)*/

import javax.swing.*;
import javax.swing.tree.*;	//ノードを作成するために必要

public class SwingJTreeTest3 {

	private JTree tree;
	private JScrollPane sp;

	/**コンストラクタ*/
        public SwingJTreeTest3(){

		//ルート(一番上)ノード
		DefaultMutableTreeNode root = new DefaultMutableTreeNode("food");

		//ルートノードへの追加
                DefaultMutableTreeNode fruit = new DefaultMutableTreeNode("fruit");
		
		//ルートノードへの追加
                DefaultMutableTreeNode vegetable = new DefaultMutableTreeNode("vegetable");

		root.add(fruit);
		root.add(vegetable);

		//「fruit」ノードへの追加
		DefaultMutableTreeNode apple = new DefaultMutableTreeNode("apple");

		DefaultMutableTreeNode orange = new DefaultMutableTreeNode("orange");

		fruit.add(apple);
		fruit.add(orange);

		//「vegetable」ノードへの追加
		DefaultMutableTreeNode lettuce = new DefaultMutableTreeNode("lettuce");

                DefaultMutableTreeNode tomato = new DefaultMutableTreeNode("tomato");

                vegetable.add(lettuce);
                vegetable.add(tomato);

		//ノードからツリーを生成
		tree = new JTree(root);
		sp = new JScrollPane(tree);		//スクロールペインに配置
	}

	/**main() */
        public static void main(String[] args){
		SwingJTreeTest3 tree = new SwingJTreeTest3();

		JFrame frame = new JFrame("JTreeTest3");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setSize(200,200);
                frame.getContentPane().add(tree.sp,"Center");
                frame.setVisible(true);
        }
}



実行すると、ツリー構造が表示されます。
ノードの配置を自分で自由に決めました。
ソースに追加すれば好きな配置で作成できます。
ノード名の編集は出来ません。








以下のサンプルプログラムを作成して実行してみましょう。


【SwingJTreeTest4.java】

/**JTreeのテスト(モデルからの作成とイベント処理)*/

import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;      //ノードを作成するために必要

public class SwingJTreeTest4 implements ActionListener, MouseListener {
	private JTree tree;
        private JScrollPane sp;
	private DefaultTreeModel model;
	private JPanel editPanel;
	private JLabel infoLabel;

	/**コンストラクタ*/
        public SwingJTreeTest4(){

 		//パネルに「追加」「削除」ボタンを配置
		editPanel = new JPanel();
		JButton addButton = new JButton("Add");
		JButton removeButton = new JButton("Remove");
		editPanel.add(addButton);
		editPanel.add(removeButton);

		//マウスクリック時の情報を表示
		infoLabel = new JLabel(" ");

		//ルート(一番上)ノード
                DefaultMutableTreeNode root = new DefaultMutableTreeNode("food");

		//ルートノードへの追加
                DefaultMutableTreeNode fruit = new DefaultMutableTreeNode("fruit");

                //ルートノードへの追加
                DefaultMutableTreeNode vegetable = new DefaultMutableTreeNode("vegetable");

		root.add(fruit);
                root.add(vegetable);

		//「fruit」ノードへの追加
                DefaultMutableTreeNode apple = new DefaultMutableTreeNode("apple");
                DefaultMutableTreeNode orange = new DefaultMutableTreeNode("orange");

                fruit.add(apple);
                fruit.add(orange);

                //「vegetable」ノードへの追加
                DefaultMutableTreeNode lettuce = new DefaultMutableTreeNode("lettuce");
                DefaultMutableTreeNode tomato = new DefaultMutableTreeNode("tomato");

                vegetable.add(lettuce);
                vegetable.add(tomato);

		//ノードからモデルを生成
		model = new DefaultTreeModel((TreeNode)root);

		//モデルからツリーを生成
		tree = new JTree(model);
		tree.setEditable(true);	//編集可

		sp = new JScrollPane(tree);             //スクロールペインに配置

		//ボタンにイベント登録
		addButton.addActionListener(this);
		removeButton.addActionListener(this);

		//ツリーにマウスイベント登録
		tree.addMouseListener(this);
	}
	/**ボタンを押した時の処理*/
	public void actionPerformed(ActionEvent evt){

		DefaultMutableTreeNode tn = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();

		String command = evt.getActionCommand();

		//ノードが選択されている時に処理を行う
		if(tn != null) {

			//追加ボタンを押した時の処理		
			if(command.equals("Add")) {

				//追加ノード作成		
				DefaultMutableTreeNode nn = new DefaultMutableTreeNode("new Node");

				//選択されているノードの子ノードとして追加
				model.insertNodeInto(nn, tn, tn.getChildCount());

				//ルートノードからの道筋を取得
				TreeNode[] nodes = model.getPathToRoot(nn);

				//ツリーパスを再生成
				TreePath path = new TreePath(nodes);

				//選択されたノードが見えるように設定
				tree.scrollPathToVisible(path);

			}
			else if (command.equals("Remove")) {	//削除ボタン時

				//ルートノードは削除しない
				if(tn.getParent() != null) {

					model.removeNodeFromParent(tn);	//親ノードから削除
				}
			}
		}
	}

	/**マウスが押された時の処理*/
	public void mousePressed(MouseEvent evt) {

		//クリックされたノードの行数取得
		int selectRow = tree.getRowForLocation(evt.getX(), evt.getY());

		//クリックされたノードのパス取得
                TreePath selectPath = tree.getPathForLocation(evt.getX(), evt.getY());

		//選択されているノードがある場合の処理
		if(selectRow != -1) {

			//クリックされたノード名	
			String selectName = selectPath.getLastPathComponent().toString();

			//ダブルクリックの時だけの処理
			if(evt.getClickCount() == 2) {

				//ラベルに情報を表示
				infoLabel.setText("Row=" + selectRow + "Path=" + selectPath + "Name=" + selectName);
			}
		}
	}

	/**マウスリスナーを用いた時に必須なメソッド(今回は内容無し)*/
	public void mouseClicked(MouseEvent evt) { }
	public void mouseReleased(MouseEvent evt) { }
	public void mouseEntered(MouseEvent evt) { }
	public void mouseExited(MouseEvent evt) { }
	/**main()*/
	public static void main(String[] args){
                SwingJTreeTest4 tree = new SwingJTreeTest4();

                JFrame frame = new JFrame("JTreeTest4");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setSize(400,200);
		
		//上から「ノード編集」「ツリー」「ノード情報」を配置
                frame.getContentPane().add(tree.editPanel,"North");
		frame.getContentPane().add(tree.sp,"Center");
		frame.getContentPane().add(tree.infoLabel,"South");
                frame.setVisible(true);
        }
}



実行するとツリー構造が表示されます。
ノードをボタンひとつで自由に追加、削除出来ます。
ノード名の変更ができます。
編集は「トリプルクリック」あるいは「休止をはさんでマウスクリック2回→1200ミリ秒待つ」で始まります。








<<前  [TOP]  次>>