Java Tips Weblog

  • Blog Stats

    • 814,389 hits
  • Categories

  • Archives

Table Button Column

Posted by Rob Camick on July 12, 2009

A JTable is used to disply rows of data. There may be times when you want to do some processing on a row of data. Maybe you want to display a popup form with more details or maybe you simply want to delete a row. In these cases it may be desireable to add a button to one of the table columns so you can invoke this processing. The problem is that JTable doesn’t support a button renderer or editor.

After playing around a bit, the best solution I could come up with was to create a class that is both a renderer and an editor. The result is the ButtonColumn class. You store text (or an Icon) in the TableModel (the same way you store data for any other column) and the ButtonColumn will render the text (or the Icon) on a button. When you create the class you specify an Action that is to be invoked when the button is pressed. You also specify the column that is used to contain the button so that the renderer and editor can be automatically installed on the appropriate TableColumn of the TableColumnModel.

A table using a ButtonColumn as a renderer would look like this:

Table-Button-Column

The button can be invoked by using the mouse or the keyboard. Using the Metal or Windows LAF you would use the space bar to invoke the button (I’m not sure about other LAF’s). You can also set a mnemonic to invoke the button. You can set the mnemonic using the setMnemonic() method. In the example above I used KeyEvent.VK_D as the mnemonic.

Notice how the border on the first button is a different color? This indicates that the button has focus and can be invoked by using the keyboard as mentioned above. I decided to use this approach since I couldn’t figure out how to invoke the normal “focus painted” code on a rendered button. You can change the Border using the setFocusBorder() method.

The key to the ButtonColumn class is the usage of an Action to perform the custom processing. When the button is clicked an ActionEvent is created and the actionPerformed() method of the Action is invoked. The table will be the source of the event. Also, the action command will contain the “model” row number of the clicked button. The reason for passing a row number is that multiple rows could be selected so you can’t depend on the table.getSelectedRow() method to return the appropriate row number. The reason for passing the model row is so you can access the TableModel using the same index whether the table uses a RowSorter or not.

The code to delete a row from a table using the DefaultTableModel would be:

Action delete = new AbstractAction()
{
    public void actionPerformed(ActionEvent e)
    {
        JTable table = (JTable)e.getSource();
        int modelRow = Integer.valueOf( e.getActionCommand() );
        ((DefaultTableModel)table.getModel()).removeRow(modelRow);
    }
};

ButtonColumn buttonColumn = new ButtonColumn(table, delete, 2);
buttonColumn.setMnemonic(KeyEvent.VK_D);

Of course you would probably want to add a confirm dialog before actually deleting the row. Anyway, hopefully you will find the ButtonColumn class easy to use.
 

Try The Demo

Launch – Using Java™ Web Start (JRE 6 required)

Get The Code

ButtonColumn.java

Related Reading

Java Tutorials: Concepts – Editors and Renderers

About these ads

70 Responses to “Table Button Column”

  1. sarcan said

    Hi Rob,

    always a pleasure reading your blog. There seems to be a glitch with this particular example, though. The actionCommand property generated by ButtonColumn contains the ‘view row’, not the ‘model row’. If you install a RowSorter on your table and change the row order you’ll end up deleting the wrong one, so the line in actionPerformed should probably read

    int row = table.convertRowIndexToModel(Integer.valueOf( e.getActionCommand()));

    best regards,
    sarcan

  2. Eitan said

    Hi Rob,

    Like Sarcan said “it is a pleasure”.

    If I am not mistaken you do not need
    the

    public void mouseMoved(MouseEvent e) {}

    • Rob Camick said

      Boy, I was sleeping while doing this one. Thanks, the line has been removed.

      Its nice to know people actually take the time to read and understand the code.

  3. André Uhres said

    Well done. Just one minor point: you use the terms “TableButton”, “TableColumn” and “ButtonColumn” to refer to the same class, which is a little bit confusing at first reading. I suppose you changed the class name and forgot to update the text.

  4. Anonymous said

    It’s not Madge, it’s Marge ;)

  5. Peter Hon said

    Hi rob,

    I am new to java programming and I have read the ButtonColumn.java source code. But I have no idea
    on how to use the ButtonColumn.java in my code. Can u suggest any complete example code that shows how
    to use ButtonColumn.java. i.e. A Class with main() using the ButtonColumn.java Code. Thanks.

    • Rob Camick said

      This is not a forum. If you don’t know how to create a JTable with data then post questions in a forum. Once you have a table created you create an Action. I posted the code for an example Action to delete a row from the table. I then gave you the 1 line of code needed to convert the text in a column to a button (the second line is optional). So all you have to do is copy/paste the code I gave you in this posting.

  6. Paul Humphrey said

    Excellent, Just what I needed
    Thanks!

  7. George Moralis said

    Using it with JXTable doesn’t seem to work. The event is never fired :(

  8. Michael B. said

    Hi, thanks for this neat article + code.
    I’m using ButtonColumn right now, however I don’t think I changed the button text right. At line 142, I changed the value inside renderButton.setText() to the text value that I want.

    I got the outcome that I wanted but you said the text would be stored in the TableModel.

    Sorry for asking such a question and thanks in advance!

  9. Sanya said

    Hey Rob,
    I tried using your code. I need buttons in the 2nd and 3rd column of my table. I passed 2 as a parameter for column in ButtonColumn. However an action is performed when i click on any column in that particular row. I need an action to be performed only when i click on the 2nd column. Could you help?

    Regards,
    Sanya

    • Rob Camick said

      Sorry I don’t see the behaviour you describe. I updated this posting with a Webstart demo that shows the behaviour when you add the ButtonColumn to the 2nd column. If you see different behaviour then you can create a simple demo and email the SSCCE using the “Contact Us” page.

      • Sanya said

        Hey Rob,
        I tried mailing you by copy pasting the code in the message field. Please let me know in case of any problem. Thanks for your time.

        Regards,
        Sanya

  10. Anabel said

    Hi thnks for you code. It help me a lot.
    Right now Im trying to make buttons to open pdf files, Is there a way to create an action for each button? And giving them the path of the pdf?
    I hope you can help me thanks!

    • Rob Camick said

      One way is to have a separate column in the table with the PDF path. Then the Action can just get the path from the column. Or if you don’t want a separate column then you can add a custom object to the model. The object would contain the text to display on the button as well as the path of the PDF file. Then you would need to override the toString() method of the Object to return the text. The Action could then access the path.

  11. Anonymous said

    Nice article sir.
    Thanks.

  12. Umer said

    Sir I got a problem here…
    The problem is when i put a cell to editable false then this api is not working ….

  13. Anonymous said

    Nice post & nice comments

  14. daskhatri said

    Dear tell how do i use your code in my program , I developed a JTable that is filling data from database, now I need to add Jbutton in my table with each record… Button is not added yet. How proceed further , Do i have to just access your class in my table program? or first i have to add a JButton in table then access your code?

    please give me just five mints

    • Rob Camick said

      Forget about getting data from the database. First you need to understand how to use the class. So create a simple example with 3 columns like I display from the image. Once you get that working then move on to getting data dynamically from a database.

      You add data to the TableModel just like you do for any other column of data. Normally the data is just displayed as text. In the image from the blog there are 3 columns of data, firstName, lastName and an untitled column. In all 3 cases you add a String to the TableModel. For the first row you add “Homer”, “Simpson”, “delete Homer”. Then you add a custom renderer and editor to the 3rd column. Again the blog show how to do this and even includes code for a simple Action.

  15. parvathi said

    Hi Rob,

    Nice article..It would be great if you could explain why do we need to add mouse listener to the editor button, when we are already adding action listener.

    • Rob Camick said

      I explained that using comments in the code. I didn’t think it was necessary to repeat in the blog since the blog iis for an overview of the functionality, not a detailed look at each line of code.

  16. This code is exactly what I have been looking for, but I am having 2 issues. the first issue is the code only works if i remove the override for the following 2 lines. Also no actions are being done when i try to set the action. Any help would be appreciated.

    public Component getTableCellEditorComponent(
    public Object getCellEditorValue(){

    • Rob Camick said

      If you comment out those lines you defeat the purpose of using the custom editor. The code should work as is if you use the example code I provided in the blog. If you have problems using the example code then create an SSCCE and send me the code using the Contact Us page.

  17. Gerard said

    Worked great for me …. except: On Mac OS X the “Aqua” look and feel doesn’t respect JButton colors, so clicking on the Button causes it to go all white. I modified the code in getTableCellRendererComponent as follows as a work around:

    if (isSelected)
    {
    	LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
    	if (!lookAndFeel.getID().equals("Aqua")) 
    	{
    		renderButton.setForeground(table.getSelectionForeground());
    		renderButton.setBackground(table.getSelectionBackground());
    	}
    }
    
  18. Faisal said

    I am new to JAVA. I just wanted to know how to run this piece of code. Does it work as a sub routine in a actionlistener.

  19. Jimmy said

    Dear sir
    I found your sourse code very helpful.However, i have problems
    My table have the 9th colum is button column and 8th column is interger.
    How can add header sort in the 8th column, and repaint table, still keep button in the 9th column.
    As far as i know, to sort column, table need to extend AbstractTable Model.
    I apply:
    ButtonColumn buttonColumn = new ButtonColumn(table, myAction, 9). My 9th column goes wrong.
    Help me , please
    I’m very appreciated

    • Rob Camick said

      The ButtonColumn class is a custom renderer and editor which should not affect sorting so I’m not sure what your problem might be. However, if you have 9 columns then you should should be specifiy “8″, when you create the ButtonColumn class since JTable uses 0 as the offset to reference columns. To add sorting to the table I just use table.setAutoCreateRowSorter( true ) and it works for me.

  20. Great code – thanks so much for sharing! I’m using it an it works great, so all I could find was a comment typo: Optionally spelled with only one ‘l’ at line 14.
    I’m only trying to contribute to your great work by helping edit for you. :) Thanks again!
    -Travis

  21. Could you send Demo’s source code?

    • Rob Camick said

      The demo code shows mostly how to create a GUI. The blog shows the important couple of lines of code to use this class. You need a couple of lines of code to create an simple Action. Then you need a single line of code to create the class and use this Action. This class can be added to any column that renders text in the column.

  22. Dear Rob,

    thanks for your code. The button shows in column and gets focus when clicked, but no event is fired.

    public class ScriptTable extends JTable {
    ...
    final Action split = new AbstractAction() 
    {
    	@Override
    	public void actionPerformed(ActionEvent e) 
    	{
    		System.out.println("Clicked!"); // not fired
    	}
    };
    	
    buttonColumn = new ButtonColumn(this, split, 3);
    

    Maybe you have an idea what is wrong

    Thanks and greetings,
    Oliver

    • Rob Camick said

      Is the column editable? I believe it needs to be editable in order for the mouse event to be passed to the editor. Also just try a simple test by just create a normal JTable, instead of extending JTable. Maybe something in your custom table is causing a problem.

  23. Sterling said

    Thanks very much for this code. I am using it in an application where I have extended JTable to give me control over column widths. I am also using a unicode down facing triangle (basically I am going to emulate a menu opening from a cell) Your code worked basically dropping it in except that when it was initially rendered the text icon was off center to the right. when clicked it went centered and then when another button was clicked it went offset again. What I ended up doing was simply replacing the line

    originalBorder = editButton.getBorder();

    in the constructor with

    originalBorder = new LineBorder(new Color(122, 138, 153), 1);

    and this centered the text. I have no idea why and I am not saying this is a fault of your code just thought you may be interested in that use case.

  24. Gal said

    I’ve been working on my school project and needed it. I was gonna try and make such class with examples i found on the internet but now i can use this awesome class. You saved me an hour(probably even more) at class.
    Thanks :D

  25. t0th said

    Hi,

    i have Exception in thread “AWT-EventQueue-0″ java.lang.ArrayIndexOutOfBoundsException: 1 >= 0

    in line fireEditingStopped();

    can you help me?

    thanks

  26. Jay said

    Awesome Awesome Awesome, thanks a bunch very easy to use. I am happy you did not provide the ‘main’ class. Could not agree more with you, the more you dig/practice/read the more you learn.

  27. resahaw27 said

    thank you so much.. this is a very big help in my school project.. more power to you!! :D

  28. resa said

    i dont know if you can help me but how do i add an actionListener to the button.. i mean what button should i add the actionListener since there 2 jbuttons declared in the code.. i need to open a new jframe when i click the button but i dont know how to do that.. i hope you can help me with that.. thank you so much. :))

    • Rob Camick said

      You don’t add an ActionListener to either of the JButtons defined in the ButtonColumn class. You add the ActionListener to the ButtonColumn class when you create an instance of the class. I gave a simple example. If you want to open a frame then you need to change the code in my example to create and show a frame.

  29. teofil said

    first of all, thank you for all your work!
    secondly, i want to use this in multiple columns, specifically in the two last columns of the table
    but when i run the project only the last column shows the button, the other one nothing!
    do you see any reason for this to happen?

    well maybe it has to do with the fact that the editor and renderer is in one class!
    i am looking at this now and i will post if it makes any difference

    • Rob Camick said

      It works fine for me. You need to create two ButonColumn classes and Actions:

      ButtonColumn buttonColumn1 = new ButtonColumn(table, action1, 3);
      ButtonColumn buttonColumn2 = new ButtonColumn(table, action2, 4);
      
      • teofil said

        sorry about the fuss but you’re right
        it works the way i want, i just didn’t made the right adjustments to my code for adding it

        btw, i am thinking of using in another column a combobox instead of a button, does this code gives the way it can be done?
        a combobox to use for a field that has multiple values
        i haven’t searched anything yet, just asking

        and again thanks for all your work, very helpful!

  30. Anonymous said

    Thanx so much, it’s exactly what I needed!

  31. Jim said

    this is a lifesaver! thanx a lot. i would have taken months to figure this out on my own!

  32. Anonymous said

    Hi Rob,

    Thank you for sharing. I have been trying for some time now to make buttons either invisible or disabled, so that I couldn’t click on a button depending on other variable in the same row.
    Could you point me in the right direction of how should I approach this problem?

    Thank you,
    Borys

    • Rob Camick said

      To prevent a cell from being edited you would override the isCellEditable(…) method of your table model. If you wanted to render the button as disabled, then you would also need to add code in the getTableCellRendererComponent(…) to make the button appear disabled.

  33. Anonymous said

    thank you Rob :) this article was very helpful for my project…i want ask a question…how to add an image in the button..

  34. Isuru said

    Hi! Thanks for this class. Just what I was looking for. I have a clarification. To set a text for the button, you have to fill up the renderButton.setText( “” ); in the getTableCellRendererComponent() method, am I right? Or is there any other property or something to accomplish this?

  35. Isuru said

    Wait! I think I got it. I added “Reserve” to the end of model.addRow(new Object[] {rs.getString(“title”), rs.getString(“author”), rs.getString(“isbn”), rs.getString(“publisher”), “Reserve”}); and everything’s good now. I must have somehow missed the line ‘You store text (or an Icon) in the TableModel’ in the article. Thanks.

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 )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 66 other followers

%d bloggers like this: