问题
I have a JTree where some of the data to be shown should be shown in a JTable. So to do this, I created a renderer class (extending DefaultTreeCellRenderder) to change the rendered component returned depending on what the object value contains when initially passed into the renderer.
If it is a table to be shown, it is contained within a JScrollPane (as the below code shows).
This works (in that the JScrollPane containing the JTable is shown in its entirety) with the Cross Platform Look and Feel but when using the System Look and Feel, the JScrollPane seems to be constrained to the height of the leaf node. Is there a way of changing this so it acts like the Cross Platform look and feel?
JFrame
public class ExampleJTreeWithJTable extends JFrame {
public ExampleJTreeWithJTable() {
setLayout(new BorderLayout(0, 0));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Example");
root.add(new DefaultMutableTreeNode("TABLE:Column A=Cell 1.1,Cell 2.1,Cell 3.1¬Column B=Cell 1.2,Cell 2.2,Cell 3.2"));
JTree tree = new JTree(root);
tree.setCellRenderer(new ExampleRenderer());
add(tree, BorderLayout.CENTER);
pack();
}
public static void main(String... args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); // Using getCrossPlatformLookAndFeelClassName works...
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
ExampleJTreeWithJTable window = new ExampleJTreeWithJTable();
window.setLocationRelativeTo(null);
window.setVisible(true);
}
});
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
}
Renderer
public class ExampleRenderer extends DefaultTreeCellRenderer {
private Map<String, JScrollPane> tables = new HashMap<String, JScrollPane>();
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
if (value.toString().startsWith("TABLE:")) {
c = tables.get(value.toString());
if (c == null) {
JTable table = new JTable(createModel(value.toString()));
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JScrollPane pane = new JScrollPane(table);
tables.put(value.toString(), pane);
c = tables.get(value.toString());
}
}
return c;
}
private TableModel createModel(String tableData) {
tableData = tableData.substring(6, tableData.length());
DefaultTableModel model = new DefaultTableModel();
String[] colData = tableData.split("¬");
for (String data : colData) {
String[] components = data.split("=");
model.addColumn(components[0], components[1].split(","));
}
return model;
}
}
Examples of output
Cross Platform Look and Feel
System Look and Feel
I've tried manually setting the JScrollPane to the preferred size of the JTable with no effect. I have a feeling it is to do with how the System LAF calculates the height of the component against the leaf node but I am not certain here.
I have also tried simply showing the JTable rather than the JScrollPane. In the Cross Platform LAF, this works. In the System LAF, it shows the first row of the table.
回答1:
I figured this out from the below link:
https://www.daniweb.com/software-development/java/threads/386037/different-height-of-jtree-nodes
In essence, all that is needed to do is set the row height to 0 to make the leaf node height variable, depending on the component being rendered as opposed to a fixed (I presume) default value.
Therefore, the code would look like this:
JTree tree = new JTree(root);
tree.setRowHeight(0);
tree.setCellRenderer(new ExampleRenderer());
The result is this:
来源:https://stackoverflow.com/questions/28675009/showing-a-jtable-in-a-jtree-behaves-differently-with-different-look-and-feels