views:

513

answers:

2

Scenario:

you are using a JTable with a custom TableModel to view the contents of some collection located in a database or on the network or whatever.

The brute force way to make this work is to load the whole collection at once. Let's say that isn't practical because of the resources needed.

The simple way around that problem is to fetch rows on demand, one row at a time, as the JTable renders each row, and calls TableModel.getValueAt(); cache as necessary. This causes a lot of hits to the database, though.

Is there a way to listen to scroll/viewport events for a JTable, to figure out what rows it is going to display before it renders each cell? If so, I would like to intercept and cause my custom TableModel to prefetch one page at a time.

edit: just to clarify, the point here is to be able to fetch the contents of a group of visible table rows in one batch, rather than having to fetch the contents of each row by itself.

+1  A: 

In effect, that is exactly what JTable allows. afaik if the getRowCount() method reflects exactly how many records there are, then when the cells are painted, only the visible part is queried. I don't think prefetching by listening on the viewport would be any faster.

you could wait for all getvalue requests. record those, return "null" or the already cached value. then after a getvalue isn't called for say 20 ms do the actual request for all the recorded cells. and fire rowUpdated events on the model so JTable repaints again.

[edit]You could maintain a list of the last records queried on the model. your list doesn't need to be any longer than the amount of rows visible on the screen. after getValue() isn't queried for a few ms, you could perform this async bulk request to the back-end

The only catch here is the sorting/filtering algorithm. When you query the viewport and let the data depend on that, then there is a 1-1 relation between your data and the view. Something which JTable itself doesn't have. But i guess there is no way around that. I would enable the IDE debugger to dig through sun code. and then see how their rendering implementation finds out which rows to repaint. i don't know by heart.

Houtman
+1  A: 

Take a look at http://www.javaworld.com/javaworld/javatips/jw-javatip137.html article. In this article there is a custom TableModel that is able to retrieve "chunks" of rows from the database

Another solution to the scenario although is not exactly what you are looking for would be lazy load each row instead of prefetch. See my own post (search google for "JTable bound to a database with lazy loading") on how to do it. The idea is that when the tablemodel is asked for a row that is not cached/loaded it will return "wait..retrieving" string for each column (assuming that all columns are strings). and at the same time it will schedule a task in another thread (using an ExecutorService). Then the task will retrieve the data from the database and update the datamodel. In my post I actually used Beans bindings so instead of a custom tablemodel y used a custom list. But I'm sure you can extrapolate the idea.

ecerulm