Row Number Table
Posted by Rob Camick on November 18, 2008
Sometimes you may have a requirement for your table to look like a spreadsheet. That is you want column headings on the top and row numbers along the side. Well, a JTable has a default API to show a column header. It does this by adding the JTableHeader component to the column header area of a JScrollPane. Although there is no component in the API to display row numbers, the scroll pane also supports a row header area for a row header component. So all we need to do is create a row header component and the problem is solved.
The RowNumberTable is such a component. It is a simple extension of JTable that shares properties of the main table along with the TableModel and SelectionModel of the main table. Although it shares the TableModel it does not actually use any of the data in the model, it just needs to be notified when rows are added or removed so it can paint itself correctly.
You can use the RowNumberTable in your program with code like the following…
JTable mainTable = new JTable(...);
JScrollPane scrollPane = new JScrollPane(mainTable);
JTable rowTable = new RowNumberTable(mainTable);
scrollPane.setRowHeaderView(rowTable);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
rowTable.getTableHeader());
which will generate a table looking something like…

Jan Zitniak said
We used your RowNumberTable.java solution. In the following case when we used first column of table as Boolean Type we got error:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
at javax.swing.JTable$BooleanRenderer.getTableCellRendererComponent(JTable.java:5406)
at javax.swing.JTable.prepareRenderer(JTable.java:5729)
...
Thank you for any help.
Rob Camick said
Thanks for the feedback.
RowNumberTable code has been modified to make sure the included RowNumberRenderer is used to render the row numbers. The renderer is now attached directly to the TableColumn.
Jan Zitniak said
Thank you, now it works ok.
M. said
Thanks for that useful class.
Rob Camick said
Glad you find it helpfull.
GP said
Very useful indeed!… I know JTable class is already packed full of methods… but just wished there would be a few more useful functions like this on offer. Maybe they could include a JTableAuxiliary or JTableUtilities or JTableConfigure class to assist in collecting all these extra goodies! :-)
ok thanks for tip.
Cheers.
Rob Camick said
Yes that was sort of the idea why I created the RXTable class. Sometimes you can add a static method as demonstrated by the
Table Column Reordering entry. Sometimes you need to override methods of the JTable as demonstrated by Table Select All Editor but sometime a separate class like this is more appropriate.
S.Mac said
Rob-
I am having the same issue in my JTable, getting the exception ‘Exception in thread “AWT-EventQueue-0″ java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
at javax.swing.JTable$BooleanRenderer.getTableCellRendererComponent(unknownSource)
at javax.swing.JTable.prepareRenderer(UnknownSource)…
Can you tell how you fixed it in your RowNumberTable component?
Many thanks.
Rob Camick said
This is not a forum for general Java questions. Please stick to comments/issues with the code or concepts presented here.
It sounds like you have a problem with the getColumnClass() method. You can try searching the Sun Java forum for my “TableBasic” example which shows how to use different renderers for different columns.
Debasish Layek said
I am using your RowNumberTable.java example but the row numbers not properly displaying the when I scrolling the actual table. It shows an empty area there. Please advice what to do?
Thanks for any kind of help.
Rob Camick said
I’ve never seen this kind of problem. Create a SSCCE and post the code in an email using the “Contact Us” page.
Thorsten said
see my post (#8)
Thorsten said
Very good… but i.ve found some issues.
- # Column is still moveable
- row height ov main table is not respected
Here my fix:
import java.awt.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
/*
* Use a JTable as a renderer for row numbers of a given main table.
* This table must be added to the row header of the scrollpane that
* contains the main table.
*/
public class RowNumberTable extends JTable
implements ChangeListener, PropertyChangeListener {
private final JTable table;
public RowNumberTable(JTable table) {
this.table = table;
table.addPropertyChangeListener(this);
setFocusable(false);
setAutoCreateColumnsFromModel(false);
updateRowHeight();
updateModel();
updateSelectionModel();
TableColumn column = new TableColumn();
column.setHeaderValue("");
addColumn(column);
column.setCellRenderer(new RowNumberRenderer());
getColumnModel().getColumn(0).setPreferredWidth(50);
setPreferredScrollableViewportSize(getPreferredSize());
getTableHeader().setReorderingAllowed(false);
}
@Override
public void addNotify() {
super.addNotify();
Component c = getParent();
// Keep scrolling of the row table in sync with the main table.
if (c instanceof JViewport) {
JViewport viewport = (JViewport) c;
viewport.addChangeListener(this);
}
}
/*
* Delegate method to main table
*/
@Override
public int getRowCount() {
return table.getRowCount();
}
@Override
public int getRowHeight(int row) {
return table.getRowHeight(row);
}
/*
* This table does not use any data from the main TableModel,
* so just return a value based on the row parameter.
*/
@Override
public Object getValueAt(int row, int column) {
return Integer.toString(row + 1);
}
/*
* Don't edit data in the main TableModel by mistake
*/
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
// implements ChangeListener
public void stateChanged(ChangeEvent e) {
// Keep the scrolling of the row table in sync with main table
JViewport viewport = (JViewport) e.getSource();
JScrollPane scrollPane = (JScrollPane) viewport.getParent();
scrollPane.getVerticalScrollBar().setValue(viewport.getViewPosition().y);
}
// implements PropertyChangeListener
public void propertyChange(PropertyChangeEvent e) {
// Keep the row table in sync with the main table
if ("rowHeight".equals(e.getPropertyName())) {
updateRowHeight();
}
if ("selectionModel".equals(e.getPropertyName())) {
updateSelectionModel();
}
if ("model".equals(e.getPropertyName())) {
updateModel();
}
}
private void updateRowHeight() {
setRowHeight( table.getRowHeight() );
}
private void updateModel() {
setModel(table.getModel());
}
private void updateSelectionModel() {
setSelectionModel(table.getSelectionModel());
}
/*
* Borrow the renderer from JDK1.4.2 table header
*/
private static class RowNumberRenderer extends DefaultTableCellRenderer {
public RowNumberRenderer() {
setHorizontalAlignment(JLabel.CENTER);
}
@Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (table != null) {
JTableHeader header = table.getTableHeader();
if (header != null) {
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
}
}
if (isSelected) {
setFont(getFont().deriveFont(Font.BOLD));
}
setText((value == null) ? "" : value.toString());
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
return this;
}
}
}
Thorsten said
Issue of poster #7 (row height not respected) should be most likely also fixed.
Debasish Layek said
Thanks Thorsten,
Now its working fine.
Andreas said
hi there,
nice one. I’ve already created a RowHeader with a JList. This RowNumberTable looks better.
But i found an issue, i mean.
When i selected the row 2 or 3, the RowHeader View at the selected row goes away, it shows only the view background (grey) without Border, without Number. I think it’s a renderer problem.
Anyone have the problem, too?
- Sorry for my “bad” english”.
greets
Andreas
Rob Camick said
Sorry I can’t duplicate the problem. I tested using JDK6.7 on XP using the Metal and Windows LAF.
Andreas said
hi,
thx for the answer.
I using jdk1.6.0_21 on Windows 7 and the Metal LAF.
Here’s a picture below of this what i mean:
http://www.dreamies.de/show.php?img=ajy2xpx23gm.jpg
Edit: i tested it in a new Test Project and all to be good.
Hmmm, i think i look at my code again… ;-)
Andreas said
i comment out this code row and the problem don’t exists:
// this.setSelectionModel(this.jtable.getSelectionModel());
But so i can’t set the selection in the rowheader…. :(
Andreas said
ok, i rebooted my pc and start eclipse and my projecct. The problem is away. All looks good. It’s curious but now it works.
greets
Andreas said
Ok, i still had the problem….
But now i know why and i have the answer. Anyone they have the same problem here’s the answer:
I feel intense shame…. ;)
My own JTable has a fixed cell height. The RowNumberTable must have the same Row Height like this (in the RowNumberTable):
this.setRowHeight(this.jtable.getRowHeight());
That’s all. All looks like good…
Thx to all.
truongkimminh said
Thank, this is help full
Rob Camick said
Glad you found the class helpful.
Mykolas said
Hello there,
thanks for the class. Great job! I used it on in my project and it works perfectly fine. But what do I do to change column numeration? I want to have 00, 01, 02 and so on. Is it possible? Thanks in advance.
Rob Camick said
Change the getValueAt(…) method to return the row number starting at 0. Change the renderer to format the value however you want.
Mykolas said
I managed to deal with row numbers, but I still can’t get the culumn numbers the way I want. Could you be more specific about how I should change the code of RowNumberRenderer to make it work (I can’t find out how those letters A, B, C,… appear)
Rob Camick said
The column headers have nothing to do with this class. I suggest you read the JTable API and follow the link to the Swing tutorial on “How to Use Table” for information on specifying the column header values.
Mykolas said
I thought it’s RowNumberTable that renders column names. Sorry for stupid questions, everything is working as it should now.Thanks.
Brandon Murphy said
I have a non-free solution at my site Hopsof.com, it takes care of custom resizing and all that for you. There is a demo you can look at too if you wish.
http://www.hopsof.com/java-components-1/swing-components/rowheadertable
hope that helps, and saves you some time/headache!
Thanks!
Brandon
Raghunandan Kavi said
how to color the cells which only display row numbers.
Rob Camick said
You need to further cusomize the renderer. The current customization just makes the text bold. If you want to change the color you would add your code in the same place.
Raghunandan Kavi said
Thanks dude, i figured it out. Your code is awesome. This was a great help to me. Thanks a lot……………
Anonymous said
Thanks Man….. It look Complicating at the beginning !!! But after a little research …. No other can do simpler than this. …. taking little patient and the code is working ….. for any one who do not get it to work , please, download “RowNumberTable.java” on top of this page … try it again … Good Luck …
szkoła jazdy said
I don’t even know the way I stopped up here, however I assumed this put up was once good. I don’t recognize who you’re but certainly you are going to a famous blogger in case you are not already. Cheers!
Rob Camick said
Glad you found the code helpful.
read more said
Pretty element of content. I just stumbled upon your site and in accession capital to say that I get actually loved account your weblog posts. Anyway I’ll be subscribing for your augment and even I achievement you get entry to consistently fast.