mdaum
mdaum

Reputation: 55

dynamically changing data model for JTree

I have a small GUI application, that processes mouse clicks, and stores them in a list:

package test;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TestGUI extends JFrame {

    private final List<String> objects = new ArrayList<>();
    private TestTree testTree;

    final JPanel canvas = new JPanel() {
        @Override
        public void paintComponent(final Graphics g) {
            super.paintComponent(g);
            g.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
            g.setColor(Color.BLACK);
            for (final String object : objects) {
                final String[] parts = object.split("--");
                g.drawOval(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), 5, 5);
            }
        }
    };

    public TestGUI() {
        final Container cp = getContentPane();
        cp.setLayout(new BorderLayout());
        cp.add(canvas, BorderLayout.CENTER);
        testTree = new TestTree(objects);
        cp.add(testTree, BorderLayout.EAST);
        setTitle("TestGUI");
        canvas.addMouseListener(new MouseListener() {
            @Override
            public void mouseReleased(MouseEvent me) {}
            @Override
            public void mousePressed(MouseEvent me) {}
            @Override
            public void mouseExited(MouseEvent me) {}
            @Override
            public void mouseEntered(MouseEvent me) {}
            @Override
            public void mouseClicked(MouseEvent me) {
                objects.add(me.getX() + "--" + me.getY());
                testTree.update();
                canvas.repaint();
            }
        });
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500, 500);
        setVisible(true);
    }

    public static void main(final String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestGUI();
            }
        });
    }

}

I want to represent an overview of the list using a JTree at the side of the canvas. The class responsible for the JTree is as follows:

package test;

import java.util.List;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;

public class TestTree extends JPanel {

    final List<String> objects;

    private JTree tree;
    private final DefaultMutableTreeNode root;

    public TestTree(final List<String> theObjects) {
        objects = theObjects;

        root = new DefaultMutableTreeNode("root");
        tree = new JTree(root);

        add(new JScrollPane(tree));
    }

    private void updateTree(final List<String> objects) {
        root.removeAllChildren();
        final DefaultMutableTreeNode result = new DefaultMutableTreeNode(objects.size() + " objects");
        for (final String object : objects) {
            final DefaultMutableTreeNode objectNode = new DefaultMutableTreeNode(object);
            result.add(objectNode);
        }
        root.add(result);
        tree.updateUI();
    }

    public void update() {
        updateTree(objects);
        tree = new JTree(root);
        add(new JScrollPane(tree));
    }

}

So, which is the correct way of updating the JTree by submitting the list? Because after some clicks my application renders a seperate tree for each added element, instead of one tree that gets updated over time: screenshot

Any suggestions would be appreciated. Thank you very much!

Upvotes: 0

Views: 142

Answers (1)

Abra
Abra

Reputation: 20914

Your problem is in method update() of class TestTree. You keep adding another JScrollPane to the TestTree. You only want one JScrollPane.

You correctly update the model of the JTree and that's all you need to do. The JTree will automatically update itself whenever its model changes.

Also, don't set the size of the JFrame. Set the size of its components and call method pack() which will make the JFrame big enough to contain all its components.

In the below code I have commented out the lines you need to remove from your code.

Class TestTree

package test;

import java.awt.Dimension;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;

public class TestTree extends JPanel {
    final List<String> objects;

    private JTree tree;
    private final DefaultMutableTreeNode root;

    public TestTree(final List<String> theObjects) {
        objects = theObjects;
        root = new DefaultMutableTreeNode("root");
        tree = new JTree(root);
        JScrollPane scrollPane = new JScrollPane(tree);
        scrollPane.setPreferredSize(new Dimension(100, 490));
        add(scrollPane);
    }

    private void updateTree() {
        root.removeAllChildren();
        final DefaultMutableTreeNode result = new DefaultMutableTreeNode(objects.size() + " objects");
        for (String object : objects) {
            final DefaultMutableTreeNode objectNode = new DefaultMutableTreeNode(object);
            result.add(objectNode);
        }
        root.add(result);
        tree.updateUI();
    }

    public void update() {
        updateTree();
//        tree = new JTree(root);
//        add(new JScrollPane(tree));
    }
}

Class TestGUI

package test;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TestGUI extends JFrame {

    private final List<String> objects = new ArrayList<>();
    private TestTree testTree;

    final JPanel canvas = new JPanel() {
        @Override
        public void paintComponent(final Graphics g) {
            super.paintComponent(g);
            g.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
            g.setColor(Color.BLACK);
            for (final String object : objects) {
                final String[] parts = object.split("--");
                g.drawOval(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), 5, 5);
            }
        }
    };

    public TestGUI() {
        final Container cp = getContentPane();
        cp.setLayout(new BorderLayout());
        cp.add(canvas, BorderLayout.CENTER);
        testTree = new TestTree(objects);
        cp.add(testTree, BorderLayout.EAST);
        setTitle("TestGUI");
        canvas.addMouseListener(new MouseListener() {
            @Override
            public void mouseReleased(MouseEvent me) {}
            @Override
            public void mousePressed(MouseEvent me) {}
            @Override
            public void mouseExited(MouseEvent me) {}
            @Override
            public void mouseEntered(MouseEvent me) {}
            @Override
            public void mouseClicked(MouseEvent me) {
                objects.add(me.getX() + "--" + me.getY());
                testTree.update();
                TestGUI.this.pack();
                canvas.repaint();
            }
        });
        canvas.setPreferredSize(new Dimension(400, 490));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
//        setSize(500, 500);
        setVisible(true);
    }

    public static void main(final String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestGUI();
            }
        });
    }
}

Upvotes: 2

Related Questions