我正在尝试使用 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 中一样。
但是我明白了:
这到底有什么问题?还应该注意,当我的标签更长时(没有“包装器”内部类),叶子中的输出标签宽了 2-3 倍,但标签的宽度也大大减少了。
所以,马上,这让我觉得有问题
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() + "\"";
}
}