In Java FX 2.x TableView is one of the controls you can't set a tooltip directly. You must set tooltips for TableCell or TableRow instead. The technique used in this turorial is very similar for both controls. Let's take a look!

Tooltips on TableCell

myTableColumn.setCellFactory(new Callback<TableColumn<DataModel, Object>, TableCell<DataModel, Object>>() {
	@Override
	public TableCell<DataModel, Object> call(TableColumn<DataModel, Object> p) {
		return new TableCell<DataModel, Object>() {
			@Override
			public void updateItem(Object t, boolean empty) {
				super.updateItem(t, empty);
				if (t == null) {
					setTooltip(null);
					setText(null);
				} else {
					Tooltip tooltip = new Tooltip();
					DataModel myModel = getTableView().getItems().get(getTableRow().getIndex());
					tooltip.setText(myModel.getTip());
					setTooltip(tooltip);
					setText(t.toString());
				}
			}
		};
	}
});

To add tooltips to column cells we have to set a custom cell factory for the target column. In our example DataModel is just the TableView's data model, change that to your model's name. Also this example's model returns Object so that's one more thing you will probably need to change over the casts. The getTip() method is there to also show you how to get the TableRow Data Item.

Tooltips on TableRow

myTable.setRowFactory(new Callback<TableView, TableRow>() {
	@Override
	public TableRow call(final TableView p) {
		return new TableRow() {
			@Override
			public void updateItem(DataModel item, boolean empty) {
				super.updateItem(item, empty);
				if (item == null) {
					setTooltip(null);
				} else {
					Tooltip tooltip = new Tooltip();
					tooltip.setText(getItem().getTip());
					setTooltip(tooltip);
				}
			}
		};
	}
});

Notice that for rows we need to set our custom row factory to the target table not column! Also it's much simpler to get the DataModel when working on rows, you only need to call getItem() method. 

Recently i started working on a JavaFX 2.x project and i needed a lot of TableViews for one of my stages. The most common and best practice to do this, is to implement a class that defines the data model and provides methods and fields to further work with the table. In my case defining 8++ Data Models seemed a little tedious so i started looking for a dynamic way to populate TableViews. I came accross this solution but that too seemed complicated. 

My solution is to create a generic Data Model which can by extended to add as many columns as you want, so not 100% dynamic then. The constructor works with a variant number of parameters so you don't have to create as many constructors as your fields, but you have to create as many getters as your fields. The second part, can be avoided but as long as you can auto generate them in any decent IDE there is no reason to go mad with reflections.

import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;

public class TableRow {

    private Object one;
    private Object two;
    private Object three;
    private Object four;
    private Object five;
    private Object six;

    public TableRow(Object... args) {
        Field[] fields = getClass().getDeclaredFields();
        int i = 0;
        for (Object arg : args) {
            try {
                fields[i++].set(this, arg);
            } catch (IllegalArgumentException | IllegalAccessException ex) {
                Logger.getLogger(TableRow.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * @return the one
     */
    public Object getOne() {
        return one;
    }

    /**
     * @return the two
     */
    public Object getTwo() {
        return two;
    }

    /**
     * @return the three
     */
    public Object getThree() {
        return three;
    }

    /**
     * @return the four
     */
    public Object getFour() {
        return four;
    }

    /**
     * @return the five
     */
    public Object getFive() {
        return five;
    }

    /**
     * @return the six
     */
    public Object getSix() {
        return six;
    }
}

Then use the model just like in every other tutorial arround the web and the Oracled Docs. In my case it was something like this. Simple, generic and not overly complicated.

private TableView<TableRow> myTable;
@FXML
private TableColumn<TableRow, Object> myTableColumnOne;
@FXML
private TableColumn<TableRow, Object> myTableColumnTwo;

public void populateMyTable()
{
	myTableColumnOne.setCellValueFactory(new PropertyValueFactory<TableRow, Object>("one"));
	myTableColumnTwo.setCellValueFactory(new PropertyValueFactory<TableRow, Object>("two"));

	ObservableList data = FXCollections.observableArrayList();
	for(Map.Entry<String, Integer> entry: myHashMap.entrySet())
	{
		data.add(new TableRow(entry.getKey(), entry.getValue()));
	}
	myTable.getItems().setAll(data);
}

I hope, you will benefit from this solution, leave a comment if you have an idea on how to improve it even further.

javaFXTableViews.png

Edit: 4/25/20013
--------------------------------------------------

I took it on step further to remove the reflection in the constructor.


import java.util.ArrayList;
import java.util.Arrays;

/**
 * Generic data model is a wrapper for ArrayList to easily populate tableViews
 * and other javafx controls. This class would be perfect if java reflection
 * supported magic getters and setters like php or if there was a nice way to
 * dynamically add them during runtime.
 */
public class GenericModel {

    /**
     * The indexed list of objects
     */
    private ArrayList data;

    /**
     * Public constructor with variable number of parameters.
     *
     * @param args
     */
    public GenericModel(Object... args) {
        data = new ArrayList<>(Arrays.asList(args));
    }

    public Object get0() {
        return data.get(0);
    }

    public Object get1() {
        return data.get(1);
    }

    public Object get2() {
        return data.get(2);
    }

    public Object get3() {
        return data.get(3);
    }

    public Object get4() {
        return data.get(4);
    }

    public Object get5() {
        return data.get(5);
    }
}

I 've been to alot of interviews lately and i always promote myself as a php programmer. The truth is i don't like people who fill their resume with a huge list of programming languages just because they happened to use them briefly at some point in their life either as a hobby or as part of their studies. Apparently and as pointed by friends, i am stupid i don't show all aspects of my skills. So here is the very first application i have build which isn't written in php.

Cakebox is an archives manager for optical media. I am a hoarder when it comes to tv series, animes and movies, i don't like to delete stuff and since hdds used (???) to be super expensive i wrote a simple application to easily find cd's/dvd's in mountains of cakeboxes. The application started its life as a Java desktop application named `CakeBox Collector` after the movie `Bone Collector`. Basically it's a database application with categories and entries with title and files list, with search and all the basic crud forms. It used the excellent H2 database and was build upon the swing framework. 

Last year and after 4 years i first started Cakebox i decided to port the application to C# for various reasons. Netbeans dropped support for the swign framework, i was really bored and because i thought the whole task would later help me with mobile applications. So after a slight name change and only about a week later Cavebox was born. I used the very cool alternative to Visual Studio, SharpDevelop and for database i used SQLite and the ADO.Net adapter. I tried to change as little as possible in the UI because i thought it would be cool to see them side by side and i really liked the original compact design. Below there are two animated gifs showing both applications can you spot the differences ;)

cavebox.gif cakebox.gif

I don't want to get into the fight which is better but still I was impressed with the low memory footprint and startup times. Of course there were a few things C# doesn't have and i missed them during the port procedure but there were also a lot of things that made C# much easier to live with. Overall i think both languages have their merits and despite the recent hatred toward Java and Oracle nobody can dispute the fact that pretty much everyone has used or is using with or without their knowledge a device/application working with Java.

Cakebox and Cavebox will find their way into github pretty soon...