尝试使用标准的 JTree 实现,但输出真的很乱

问题描述 投票:0回答:1

我正在尝试使用 JTree。这是我的示例测试类:

package inspector;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;


/**
 *
 * @author Alex
 */
public class TreeTest {

    private static ValueMap prepareTree() {
        ValueMap obj = new ValueMap();
        obj.set("x", new Value(1));
        obj.set("y", new Value(1));

        ValueArray users = new ValueArray();
        obj.set("users", users);

        ValueMap user = new ValueMap();
        user.set("login", new Value("Alex654"));
        user.set("password", new Value("123456"));

        ValueMap info = new ValueMap();
        info.set("city", new Value("Moscow"));
        info.set("job", new Value("Developer"));
        info.set("firstName", new Value("Alex"));
        info.set("lastName", new Value("Popov"));
        user.set("bio", info);

        users.push(user);

        ValueMap user2 = new ValueMap();
        user2.set("login", new Value("admin"));
        user2.set("password", new Value("test"));
        user2.set("bio", new Value(null));

        users.push(user2);

        return obj;
    }

    static class Value {

        Value() {
            value = null;
        }

        Value(Object val) {
            this.value = val;
        }

        @Override
        public String toString() {
            if (value instanceof Integer || value instanceof Double) {
                return value + "";
            } else {
                return "\"" + value.toString() + "\"";
            }
        }

        Object value;
    }

    static class ValueArray extends Value {

        ValueArray() {
            items = new ArrayList<Value>();
        }

        ValueArray(Value val) {
            items = new ArrayList<Value>();
            items.add(val);
        }

        void push(Value val) {
            items.add(val);
        }

        ArrayList<Value> items;
    }

    static class ValueMap extends Value {

        ValueMap() {
            items = new HashMap<String, Value>();
        }

        Value get(String key) {
            return items.get(key);
        }

        void put(String key, Value val) {
            items.put(key, val);
        }

        void set(String key, Value val) {
            items.put(key, val);
        }

        HashMap<String, Value> items;
    }

    public static class ValueWrapper {

        ValueWrapper(String label, Value val) {
            this.label = label;
            this.val = val;
        }

        String getLabel() {
            return label;
        }

        Value getValue() {
            return val;
        }

        @Override
        public String toString() {
            String result = label;
            if (val instanceof ValueArray) {
                result += ": Array";
            }
            else if (val instanceof ValueMap) {
                result += ": { Object }";
            }
            else result += ": " + val.toString();

            return result;
        }

        private String label;
        private Value val;
    }

    public static void processChildren(DefaultMutableTreeNode node) {
        Value val = ((ValueWrapper)node.getUserObject()).getValue();
        if (val instanceof ValueArray) {
            ArrayList<Value> items = ((ValueArray)val).items;
            for (int i = 0; i < items.size(); i++) {
                DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(new ValueWrapper(i + "", items.get(i)));
                node.add(newNode);
                processChildren(newNode);
            }
        } else if (val instanceof ValueMap) {
            HashMap<String, Value> props = ((ValueMap)val).items;
            Set<String> keys = props.keySet();
            for (String key: keys) {
                DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(new ValueWrapper(key, props.get(key)));
                node.add(newNode);
                if (!key.equals("__proto__")) {
                    processChildren(newNode);
                }
            }
        }
    }


    public static void main(String[] args) {

        try {
            UIManager.setLookAndFeel(
                UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {}

        final ValueMap root = prepareTree();
        if (root == null) return;

        final JFrame frame = new JFrame("Object Inspector");
        JPanel cp = new JPanel();
        cp.setBorder(BorderFactory.createEmptyBorder(9, 10, 9, 10));
        frame.setContentPane(cp);
        cp.setLayout(new BorderLayout());

        DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(new ValueWrapper("obj", root));
        processChildren(rootNode);

        DefaultTreeModel treeModel = new DefaultTreeModel(rootNode, true);
        final JTree tree = new JTree(treeModel);

        final JPanel contentpane = new JPanel();
        contentpane.setBackground(Color.WHITE);
        contentpane.setOpaque(true);
        contentpane.setLayout(new BoxLayout(contentpane, BoxLayout.PAGE_AXIS));
        contentpane.add(tree);

        //contentpane.setBounds(0, 0, 490, 380);
        final int width = 490, height = 418;

        final JScrollPane scrollpane = new JScrollPane(contentpane);
        scrollpane.setOpaque(false);
        scrollpane.getInsets();

        cp.add(scrollpane);
        scrollpane.setBackground(Color.WHITE);
        scrollpane.setOpaque(true);
        scrollpane.setPreferredSize(new Dimension(width, height));
        //setSize(518, 420);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                tree.setPreferredSize(new Dimension(tree.getParent().getWidth(), tree.getParent().getHeight()));
            }

        });

    }
}

我希望得到一棵漂亮的树,就像在我每天使用的 NetBeans IDE 中一样。

但是我明白了:

tree display

这到底有什么问题?还应该注意,当我的标签更长时(没有“包装器”内部类),叶子中的输出标签宽了 2-3 倍,但标签的宽度也大大减少了。

java swing display jtree
1个回答
0
投票

所以,马上,这让我觉得有问题

JPanel cp = new JPanel();
cp.setBorder(BorderFactory.createEmptyBorder(9, 10, 9, 10));
frame.setContentPane(cp);
cp.setLayout(new BorderLayout());

然后...

final JPanel contentpane = new JPanel();
contentpane.setBackground(Color.WHITE);
contentpane.setOpaque(true);
contentpane.setLayout(new BoxLayout(contentpane, BoxLayout.PAGE_AXIS));
contentpane.add(tree);

然后...

final JScrollPane scrollpane = new JScrollPane(contentpane);
scrollpane.setOpaque(false);
scrollpane.getInsets();

cp.add(scrollpane);
scrollpane.setBackground(Color.WHITE);
scrollpane.setOpaque(true);
scrollpane.setPreferredSize(new Dimension(width, height));

我的大脑完全...

JTree
应该直接包裹在
JScrollPane
中,我会避免
scrollpane.setPreferredSize
,那只会把事情搞砸。

最后...

SwingUtilities.invokeLater(new Runnable() {

    @Override
    public void run() {
        tree.setPreferredSize(new Dimension(tree.getParent().getWidth(), tree.getParent().getHeight()));
    }

});

会完全把你搞砸......再一次

所以,如果我重新编写代码...

final JFrame frame = new JFrame("Object Inspector");

JPanel borderPane = new JPanel(new BorderLayout());
borderPane.setBorder(BorderFactory.createEmptyBorder(9, 10, 9, 10));

frame.setContentPane(borderPane);

DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(new ValueWrapper("obj", root));
processChildren(rootNode);

DefaultTreeModel treeModel = new DefaultTreeModel(rootNode, true);
final JTree tree = new JTree(treeModel) {
    @Override
    public Dimension getPreferredScrollableViewportSize() {
        return new Dimension(200, 200);
    }          
};

frame.add(new JScrollPane(tree));

frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);

最后..

@Override
public String toString() {
    if (value instanceof Integer || value instanceof Double) {
        return value + "";
    } else {
        return "\"" + value.toString() + "\"";
    }
}

导致

NullPointerException
,可以用...修复

@Override
public String toString() {
    if (value == null) {
        return "null";
    } else if (value instanceof Integer || value instanceof Double) {
        return value + "";
    } else {
        return "\"" + value.toString() + "\"";
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.