Displaying a jTable inside another jTable // JTable cellRenderer
This code in this post has been updated, you can find it here.
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.
In this post, 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
.
Let's start by defining some variables to hold the data for our example's model:
// We declare the variables where we'll store our data
// First an array Object which will be our main table
Object[][] data = null;
// We declare an Array String to hold the name of the main table columns
// In this example case we are going to store:
// contact name, email address(es), phone number(s) and creation date.
String[] columns = {"Name", "E-Mail","Phone","Creation Date"};
Next, let's create a function to populate the variables with some sample data:
// First, populate our data object with some example values
public void populateData(){
/* Two contacts*/
data = new Object[3][columns.length];
data[0][0] = "Peter";
String[] emails = {"peter@yahoo.com", "strange@name.com"};
data[0][1] = emails;
String[] phones = {"555 35 25 65" , "555 35 24 63"};
data[0][2] = phones;
data[0][3] = new Date();
data[1][0] = "Jackson";
data[1][1] = "Jack@hotmail.com";
String[] phones2 = {"555 35 24 33" , "555 11 88 88", "332 55 25 34"};
data[1][2] = phones2;
data[1][3] = new Date();
data[2][0] = "Robert";
data[2][1] = "rob@hotmail.com";
data[2][2] = "555 28 95 81";
data[2][3] = new Date();
/* As you can see, we've stored two contacts one with two e-mail accounts and two phone numbers,
and another member with three phone numbers */
}
Finally, we create our table models and the cell renderer that will allow us to display the data in a nested JTable
:
// Next, we create our table models
public void createModel(){
/* First we create the main model
We overide the AbstractTableModel necessary methods*/
AbstractTableModel modelo = new AbstractTableModel() {
public String getColumnName(int col) {
return columns[col];
}
public Class getColumnClass(int col) {
if(getRowCount() <1) {
return null;
}
return data[0][col].getClass();
}
public int getRowCount() {
return data.length;
}
public int getColumnCount() {
return columns.length;
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public boolean isCellEditable(int row, int col){
return true;
}
public void setValueAt(Object value, int row, int col) {
data[row][col] = value; fireTableCellUpdated(row, col);
}
};
/* We apply the model to the main jTable */
jTableData.setModel(modelo);
/* We create a cell Renderer to display the data of the multivalue fields*/
TableCellRenderer jTableCellRenderer = new TableCellRenderer() {
/* These are necessary variables to store the row's height */
private int minHeight = -1;
private int currHeight = -1;
/* Magic Happens */
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
/* If what we're displaying isn't an array of values we return the normal renderer*/
if(!value.getClass().isArray()){
return table.getDefaultRenderer(value.getClass())
.getTableCellRendererComponent(table, value, isSelected, hasFocus,row, column);
} else{
final Object[] passed = (Object[])value;
/* We calculate the row's height to display data
* This is not complete and has some bugs that
* will be analyzed in further articles */
if(minHeight == -1){
minHeight = table.getRowHeight();
}
if(currHeight != passed.length*minHeight){
currHeight = passed.length * minHeight;
table.setRowHeight(row,currHeight);
}
/* We create the table that will hold the multivalue
* fields and that will be embedded in the main table */
return new JTable(new AbstractTableModel() {
public int getColumnCount() {
return 1;
}
public int getRowCount() {
return passed.length;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return passed[rowIndex];
}
public boolean isCellEditable(int row, int col){
return true;
}
});
}
}
}; /* Finally we apply the new cellRenderer to the whole table */
TableColumnModel tcm = jTableData.getColumnModel();
for(int it = 0; it < tcm.getColumnCount(); it++){
tcm.getColumn(it).setCellRenderer(jTableCellRenderer);
}
// Note: if we need to edit the values inside the embedded jtable
// we will need to create a TableCellEditor too.
}
If everything goes well, you should see a table like the following:
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.