How to "Pretty Up" Your JavaFX TableViews

One day you're a happy JavaFX developer, cranking out applications and blissfully providing your application's users with table after table of rich textual information. The next day it happens: your users approach you and ask if there's a way to include a thumbnail of each part in the inventory list. Or a small photo in the contact list/personnel roster. Or a snapshot/graph of the latest conditions for each monitored sensor or weather camera. So now what?

PropertyValueFactory, a convenience implementation of the Callback interface, is typically used to handle the work involved with populating all cells within a single TableColumn. As long as you provide the name of a valid property to the PropertyValueFactory constructor and set the TableColumn's CellValueFactory to the resulting PropertyValueFactory, the cell is populated, TableView adds an observer to the value, and life moves merrily along.

Adding a graphical element to a TableView isn't much harder, actually. The TableColumn's CellFactory handles rendering of the cell's contents, so if you want to place something other than textual content in the cell, you'll need to also set the TableColumn's CellFactory to one of your liking and override the updateItem() method. Let's take a look at a quick example.

I'd always intended to create some small-but-useful Twitter utilities and hadn't really had the opportunity, but a simple Twitter client provides a perfect demonstration of this capability. Here is an example of what a "feed" interface might look like:

For this TableView example, there are only two columns:

  • one for the user, showing the user's picture, name, and screen name
  • one for the tweet

The tweet's text is simply a string property of each MTweet object, but the user information comes from several properties of the MTweet object's associated MUser object. The MTweet's text is properly assigned to the cell's text property per the discussion above, but what about the user information? Per the JavaFX 2.2 docs,

Because by far the most common use case for cells is to show text to a user, this use case is specially optimized for within Cell. This is done by Cell extending from Labeled. This means that subclasses of Cell need only set the text property, rather than create a separate Label and set that within the Cell. However, for situations where something more than just plain text is called for, it is possible to place any Node in the Cell graphic property. Despite the term, a graphic can be any Node, and will be fully interactive. For example, a ListCell might be configured with a Button as its graphic. The Button text could then be bound to the cells item property. In this way, whenever the item in the Cell changes, the Button text is automatically updated.

To display the tweet's text in the "Text" column of our table, a couple lines of code does all that is necessary:

In order to bundle the user information and place it within a single cell, we set the "User Info" column's CellValueFactory in similar fashion to our text column above:

And then we set that column's CellFactory to something along the order of this:

For each cell in that TableColumn, updateItem is called with that cell's contents as the "item", the first parameter. Within our example above, we create a VBox, populate it with the user's photo (Image, via ImageView), name (String) and screen name (String), do a bit of formatting, and assign the VBox to the cell's graphic property. And with that, we're off and running. :-)

There is much more you can do, and this should get the ideas flowing. Here's to prettier apps (better optics?) and happier users!

All the best,

<<< UPDATE 1 >>>

Jonathan Giles, JavaFX team UI Controls tech lead, made a few suggestions for improving the efficiency of the code used above. The points he made were excellent, and I wanted to provide an update that shows revised code that incorporates them. I did leave the original code above, as I'm hoping it helps make a clearer path for those implementing similar code for the first time.

In order to override the TableCell constructor, we'll extend the particular TableCell<MTweet, MUser> class. Doing so allows us to create the VBox, Labels, and ImageView used in our composite user cell once per cell, rather than each time updateItem() is called. While we're at it, we'll also perform formatting/assignment duties in the constructor and avoid repeating those calls. Here is the new derivative class:

Creating the new UserTableCell class means we can update our setCellFactory() method call for our user info column like so:

Thanks to Jonathan Giles (@JonathanGiles) for the suggestions!

All the best,

<<< UPDATE 2 >>>

One more update! This time using an anonymous inner class for the column's cell factory. Same basic functionality, but this is perhaps the tidiest option.

Options are good, as they say...  :-)

All the best,


I would recommend instantiating the VBox, Label, and ImageView in the TableCell constructor and reusing one instance of these objects per cell, rather than recreating them all every time updateItem is called. Similarly, the calls to setFitWidth/setFitHeight, getChildren and setGraphic can all be done in the constructor also.

In short, it is very important to understand that updateItem is called A LOT, so it has to be as super efficient as possible.

Posted by Jonathan Giles on February 26, 2013 at 12:19 PM PST #


Ah, excellent points! I'll put together an update and post it in a bit. Thanks much for the advice, always welcome!


Thanks, glad you found it helpful!

All the best,

Posted by Mark Heckler on February 26, 2013 at 01:32 PM PST #

Could you please explain how to update the Image of User, just like we do it with editable TextFieldTableCell?
The expected behavior is that when I click on the image, it puts itself on editing mode and show a filechooser. After picking the file the edit is commited and data is saved.

Posted by Muhammad on July 24, 2013 at 10:02 AM PDT #

Great post. Can you please share the entire source code?
Thank you.

Posted by guest on December 19, 2013 at 01:47 AM PST #

Thanks, this is very helpful.

Posted by Elmar Klaus on June 07, 2014 at 06:00 AM PDT #

Thanks everyone for your kind words & comments. This was just a fun little "scratch" project, and now I can't seem to locate the source. It's entirely possible it didn't make the move with me to my new machine... :(

At some point, I need to recreate this (or similar) with lambdas. All I need is the time! In the interim, good luck with your projects, and please do share your discoveries with JavaFX!

Posted by Mark Heckler on June 09, 2014 at 06:59 AM PDT #

i just noticed that for each table cell the callback is executed twice (that means, for one and the same cell actually to cells are created, check the MUser updateItem, print out the the value of the item and the hash code of the cell). So if you load the image from external, make sure, you cache that or something like this.

Posted by Michael on October 19, 2014 at 11:42 AM PDT #

I use something like this

private static final Map<Integer, Image> images = new ConcurrentHashMap<>();
final Image image = images.computeIfAbsent(item, id -> {return new Image(String.format("%s/galleryPictures/%d.jpg", BASE_URL, id), 800, 600, true, true, true);});

given an id to identify the image

Posted by Michael on October 19, 2014 at 11:47 AM PDT #

If you please send me the complete source code in netbean project?

Posted by guest on October 27, 2014 at 03:20 PM PDT #

I'm not sure if I still have the source code for this, but I'll look...and if I can find it, I'll post it and let you know.

More soon (I hope)... :)

Posted by Mark Heckler on October 29, 2014 at 06:09 AM PDT #

Thanks for the tutorial. I've been having lots of trouble finding material about building custom looking cells—everything on the net assumes that you only want to display text in your cells and nothing else!

This has helped me a lot!

Posted by guest on December 28, 2014 at 02:53 PM PST #

Thank you! I really need to revisit and update this, especially since I can't locate my old code (sheepish grin). Glad you found it helpful!

All the best,

Posted by Mark Heckler on December 30, 2014 at 11:06 AM PST #

Hello I am having big trouble with this and your post is the best that I have seen on the internet.

is there any possibility that I sent you some code?

Posted by guest on May 29, 2015 at 09:32 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed

The Java Jungle addresses all things Java (of course!) and any other useful and interesting tools & platforms that help us GET IT DONE. "Artists ship," after all. :)

Your Java Jungle guide is Mark Heckler, a Software Architect/ Engineer and Oracle Developer Evangelist with development experience in numerous environments. Mark's current pursuits and passions all revolve around Java, the Cloud, & the IoT, and leave little time to blog or tweet - but somehow, he finds time to do both anyway.

Mark lives with his very understanding wife in the St. Louis, MO area.

Stay Connected


« November 2015