Java Tips Weblog

  • Blog Stats

    • 1,181,454 hits
  • Categories

  • Archives

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…

row-number-table

Get The Code

RowNumberTable.java

Related Reading

Using a Scroll Pane: Providing Custom Decorations

About these ads

46 Responses to “Row Number Table”

  1. 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.

  2. 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.

  3. Jan Zitniak said

    Thank you, now it works ok.

  4. M. said

    Thanks for that useful class.

  5. 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.

  6. 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.

  7. 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.

  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;
    }
    }
    }

  9. 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

  10. 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… ;-)

  11. 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.

  12. Thank, this is help full

  13. 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.

  14. 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

  15. 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……………

  16. 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 …

  17. 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!

  18. 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.

  19. Marefe said

    Hi. Your code is really helpful. My question is somehow related to Mykolas’ question: “But what do I do to change column numeration? I want to have 00, 01, 02 and so on.” My problem is my main table can be sorted and can be filtered and I want the row number table to rearrange as the main table is sorted or filtered. Is it possible? Thanks ahead.

    • Rob Camick said

      No, it is not possible to use sorting or filtering with this class. Maybe you can use the Fixed Column Table from this blog. You would need to add the row number as data in the first column of your TableModel. Then, because the row is part of the model it will be filtered and sorted with the rest of the TableModel.

  20. toushif said

    dude u r AWESOME …it worked

  21. George said

    Hello,

    How is it possible to print the whole table?

  22. VikarIT said

    Nice share broe,

  23. Sweet said

    Hi
    I want to change the color of the first row of the table, I tried to change your getTableCellRendererComponent function, but only works in the rowNumber column, so, I made a TableCellRenderer class, and use it in the main table, mainTable.setDefaultRenderer(String.class, new CellRenderer());, but it’s not working. Any idea why this is happening, and what else can I do?

    Thanks

    • Rob Camick said

      “but it’s not working.Any idea why this is happening” – your code is wrong. Adding a custom render to a table is a question you should ask in a forum. It has nothing to do with this class. Maybe you can check out the Table Row Rendering blog entry which shows a different approach to coloring a table row without using a custom renderer.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 91 other followers

%d bloggers like this: