Put JTable in the JTree
in connection with thread Jtable as a Jtree Node I put JTable to JTree, but JTree
View isn't rendered correctly on start_up, how can I setPreferredSize
for JTable
, because PreferredScrollableViewportSize
shrinked JTable
with rendering TableHeader
+ one Row
, one Row
remain hidden, but after expanding Node(s) TreeRenderer change and repaint the setPreferredSize
to the expected Dimension
import java.awt.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.*;
public class TreeWithTableRenderer extends JFrame {
private static final long serialVersionUID = 1L;
private JTree tree;
public TreeWithTableRenderer() {
DefaultMutableTreeNode AA1 = new DefaultMutableTreeNode("AA1");
DefaultMutableTreeNode AA2 = new DefaultMutableTreeNode("AA2");
DefaultMutableTreeNode A = new DefaultMutableTreeNode("A");
A.add(AA1);
A.add(AA2);
DefaultMutableTreeNode BB1 = new DefaultMutableTreeNode("BB1");
DefaultMutableTreeNode BB2 = new DefaultMutableTreeNode("BB2");
DefaultMutableTreeNode B = new DefaultMutableTreeNode("B");
B.add(BB1);
B.add(BB2);
DefaultMutableTreeNode CC1 = new DefaultMutableTreeNode("CC1");
DefaultMutableTreeNode CC2 = new DefaultMutableTreeNode("CC2");
DefaultMutableTreeNode C = new DefaultMutableTreeNode("C");
C.add(CC1);
C.add(CC2);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
root.add(A);
root.add(B);
root.add(C);
tree = new JTree(root);
tree.setCellRenderer(new MyTableInTreeCellRenderer());
tree.setRowHeight(0);
JScrollPane jsp = new JScrollPane(tree);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(jsp, BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
}
class MyTableInTreeCellRenderer extends JPanel implements TreeCellRenderer {
private static final long serialVersionUID = 1L;
private JTable table;
public MyTableInTreeCellRenderer() {
super(new BorderLayout());
table = new JTable();
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
final String v = (String) ((DefaultMutableTreeNode) value).getUserObject();
table.setModel(new DefaultTableModel() {
private static final long serialVersionUID = 1L;
@Override
public int getRowCount() {
return 2;
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public Object getValueAt(int row, int column) {
return v + ":" + row + ":" + column;
}
});
table.setPreferredScrollableViewportSize(table.getPreferredSize());
return this;
}
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TreeWithTableRenderer().setVisible(true);
}
});
}
}
Get rid of the scrollPane, it's dysfunctional anyway (so far I agree with Russell :-) and add the table and its header to the panel, using an appropriate LayoutManager:
public MyTableInTreeCellRenderer() {
super();
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
table = new JTable();
add(table.getTableHeader());
add(table);
}
you'll probably need to tweak the visuals a bit, the left and top border lines are missing - not entirely sure which component paints them normally, could be the scrollPane
Edit
Forgot: the reason querying the scrollPane's prefSize in calculating the required size (done in the ui delegate, namely the VariableHeightLayoutCache) of the rendering component is that the scrollPane not yet configured with the header. The query happens before the panel is added to the rendererPane, the complete configuration is done in the table's addNotify which happens only after adding the panel to the hierarchy
You might just get rid of the ScrollPane and lay out the header and table in the panel directly (with a null
LayoutManager so you can control everything yourself):
static class TableTreeCellRenderer extends JPanel implements TreeCellRenderer {
private final JTable table;
TableTreeCellRenderer() {
table = new JTable();
setLayout(null);
add(table.getTableHeader());
add(table);
}
public Dimension getPreferredSize() {
Dimension headerSize = table.getTableHeader().getPreferredSize();
Dimension tableSize = table.getPreferredSize();
return new Dimension(Math.max(headerSize.width, tableSize.width),
headerSize.height + tableSize.height);
}
public void setBounds(int x, int y, int width, int height) {
super.setBounds(x, y, width, height);
int headerHeight = table.getTableHeader().getPreferredSize().height;
table.getTableHeader().setBounds(0, 0, width, headerHeight);
table.setBounds(0, headerHeight, width, height - headerHeight);
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
final String v = (String) ((DefaultMutableTreeNode) value).getUserObject();
table.setModel(new DefaultTableModel(new Object[][] {
{ v + "0", "1" },
{ v + "2", "3" }
}, new Object[] { "id", "value" } ));
invalidate();
return this;
}
}