Displaying a jTable inside another jTable // JTable cellRenderer
Java is one of the greatest object oriented languages. This can easily be seen when using swing components. JTables are a great example. Briefly, jTables are just a base to display a matrix of JComponents. So inside a JTable
you can embed any object which extends the JComponent class.
Today I'll show you an easy way to display a JTable
inside another JTable
as a cellRenderer
. If you've ever worked with multivalued data models this can be of great help. In this simple example I'll create a small contact manager where the name, phones, and e-mail addresses of the contact can be stored. If the contact has more than one e-mail address or phone number, then they'll be displayed using an embedded JTable
.
1// We declare the variables where we'll store our data
2// First an array Object which will be our main table
3Object[][] data = null;
4// We declare an Array String to hold the name of the main table columns
5// In this example case we are going to store:
6// contact name, email address(es), phone number(s) and creation date.
7String[] columns = {"Name", "E-Mail","Phone","Creation Date"};
1// First, populate our data object with some example values
2public void populateData(){
3 /* Two contacts*/
4 data = new Object[3][columns.length];
5 data[0][0] = "Peter";
6 String[] emails = {"peter@yahoo.com", "strange@name.com"};
7 data[0][1] = emails;
8 String[] phones = {"555 35 25 65" , "555 35 24 63"};
9 data[0][2] = phones;
10 data[0][3] = new Date();
11 data[1][0] = "Jackson";
12 data[1][1] = "Jack@hotmail.com";
13 String[] phones2 = {"555 35 24 33" , "555 11 88 88", "332 55 25 34"};
14 data[1][2] = phones2;
15 data[1][3] = new Date();
16 data[2][0] = "Robert";
17 data[2][1] = "rob@hotmail.com";
18 data[2][2] = "555 28 95 81";
19 data[2][3] = new Date();
20 /* As you can see, we've stored two contacts one with two e-mail accounts and two phone numbers,
21 and another member with three phone numbers */
22}
23// Next, we create our table models
24public void createModel(){
25 /* First we create the main model
26 We overide the AbstractTableModel necessary methods*/
27 AbstractTableModel modelo = new AbstractTableModel() {
28 public String getColumnName(int col) {
29 return columns[col];
30 }
31 public Class getColumnClass(int col) {
32 if(getRowCount() <1) {
33 return null;
34 }
35 return data[0][col].getClass();
36 }
37 public int getRowCount() {
38 return data.length;
39 }
40 public int getColumnCount() {
41 return columns.length;
42 }
43 public Object getValueAt(int row, int col) {
44 return data[row][col];
45 }
46 public boolean isCellEditable(int row, int col){
47 return true;
48 }
49 public void setValueAt(Object value, int row, int col) {
50 data[row][col] = value; fireTableCellUpdated(row, col);
51 }
52 };
53 /* We apply the model to the main jTable */
54 jTableData.setModel(modelo);
55 /* We create a cell Renderer to display the data of the multivalue fields*/
56 TableCellRenderer jTableCellRenderer = new TableCellRenderer() {
57 /* These are necessary variables to store the row's height */
58 private int minHeight = -1;
59 private int currHeight = -1;
60 /* Magic Happens */
61 public Component getTableCellRendererComponent(
62 JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
63 /* If what we're displaying isn't an array of values we return the normal renderer*/
64 if(!value.getClass().isArray()){
65 return table.getDefaultRenderer(value.getClass())
66 .getTableCellRendererComponent(table, value, isSelected, hasFocus,row, column);
67 } else{
68 final Object[] passed = (Object[])value;
69 /* We calculate the row's height to display data
70 * This is not complete and has some bugs that
71 * will be analyzed in further articles */
72 if(minHeight == -1){
73 minHeight = table.getRowHeight();
74 }
75 if(currHeight != passed.length*minHeight){
76 currHeight = passed.length * minHeight;
77 table.setRowHeight(row,currHeight);
78 }
79 /* We create the table that will hold the multivalue
80 * fields and that will be embedded in the main table */
81 return new JTable(new AbstractTableModel() {
82 public int getColumnCount() {
83 return 1;
84 }
85 public int getRowCount() {
86 return passed.length;
87 }
88 public Object getValueAt(int rowIndex, int columnIndex) {
89 return passed[rowIndex];
90 }
91 public boolean isCellEditable(int row, int col){
92 return true;
93 }
94 });
95 }
96 }
97 }; /* Finally we apply the new cellRenderer to the whole table */
98 TableColumnModel tcm = jTableData.getColumnModel();
99 for(int it = 0; it < tcm.getColumnCount(); it++){
100 tcm.getColumn(it).setCellRenderer(jTableCellRenderer);
101 }
102 // Note: if we need to edit the values inside the embedded jtable
103 // we will need to create a TableCellEditor too.
104}

In the above image, you can see the result. The code will only allow you to display the data, but you won't be able to edit. If you want to edit the data you must also create a table cell editor. I'll analyze this in further posts.
Comments in "Displaying a jTable inside another jTable // JTable cellRenderer"
Also, I sent you email, and it bounced with a "Message could not be delivered to the domain - marcnuri.com." message.
For the time being you can try adapting this code Creating a Custom Table Cell Editor in a JTable Component
About the E-Mail bouncing, maybe the server was down when you tried, thanks for the heads-up.
thanks for your code, it was really useful to me but I have some problems when I display the table, if I go to other window then when I return, the table and also the menu and other components that I have in the same window where is the table disappear, you know why its happening this??
Thanks a lot.
thanks
I have question.Can we add Combox in Jtable header e.g. if we select any action in combo box then it affects whole table (e.g. table bacground color) ?
what should I do? Thanks!
I am trying to use it to make nested tables n levels deep but unable to select the cell present in inner table. Could you please help by suggesting the way forward?
Uso o jtable do Netbeans
Thank you, the code is perfectly working for me.
If I try to copy the table data, the embedded cell values are copied as an Object
i.e. Peter [Ljava.lang.Object;@20785a37 [Ljava.lang.Object;@2d649736 04-abr-2007
How can i copy the data as it is for embedded cells instead of Objects.