Community
Participate
Working Groups
There is currently no way to check if a TableItem (or a TreeItem) is in the visible area of its parent and how many item a widget can display. This would allow to clear items and dispose images when they are not visible, in order to reduce the memory and handle usage. My use case : I'm working on a photo sharing application in which i display a lot of different images (3000+) in a table and in a custom widget. These widgets are both using the SWT.VIRTUAL mode, but I don't want to have too many images in memory in the same time, so I have to dispose them when they are not used anymore. (see http://sharemedia.free.fr/features.php?lang=en) With the current API, I had to use a kind of cache with a limited size (about 40 images for the table and 200 for my custom widget). I catch the Paint event on each item and i add the image in the cache if it was not already in it. When the cache reaches its limit, the oldest image is diposed. This works great, but only when the number of visible item is lower than the cache capacity. In this last case, each image is disposed and created again when a paint event occurs : everything become far too slow. (The number of displayed items change with the screen resolution and the window / view size). As a workaround , I increased the cache size, but I often have 40+200 images in memory when only 20 are visible. The API enhancements that could help in the case are : - A way to get how many items a table can display in its curent size. - A method that check if an item is in the visible area of its parent. - maybe visible/invisible events which fire when an item's state changes.
Will this work for you: import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; public class CacheTable { static int cacheCount; static final int CACHE_SIZE = 32; static void checkCache (Table table) { if (cacheCount++ < CACHE_SIZE) return; cacheCount = 0; Rectangle clientRect = table.getClientArea (); int topIndex = table.getTopIndex (); int bottomIndex = topIndex + 1; while (bottomIndex < table.getItemCount ()) { Rectangle itemRect = table.getItem (bottomIndex).getBounds (); if (itemRect.y > clientRect.y + clientRect.height) { break; } bottomIndex++; } if (topIndex != 0) { System.out.println("top clear " + 0 + " " + (topIndex - 1)); table.clear (0, topIndex - 1); } if (bottomIndex != table.getItemCount ()) { System.out.println("bottom clear " + bottomIndex + " " + (table.getItemCount () - 1)); table.clear (bottomIndex, table.getItemCount () - 1); } } public static void main (String [] args) { Display display = new Display (); Shell shell = new Shell (display); shell.setLayout (new FillLayout ()); final Table table = new Table (shell, SWT.VIRTUAL); table.setItemCount (1000); table.addListener (SWT.SetData, new Listener () { public void handleEvent (Event e) { checkCache (table); TableItem item = (TableItem) e.item; int index = table.indexOf (item); item.setText ("Item " + index); } }); shell.setSize (200, 200); shell.open (); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); } display.dispose (); } }
I believe this should work, thanks (I didn't have time to try it yet.) Maybe adding a method like getBottomIndex() would make things easier. I don't know the internals of table, but if this value is known by the Table widget it would make things faster (no need to loop on visible items each time the slider is moved). What do you think of this ?
I'm not thrilled about adding it. What is bottom index? Is it the last fully visible index or a partially visible one? Note that since items in a table are currently all the same height, bottom index could be computed using getClientArea() and getItemHeight(). NOTE: CAR, this code needs to be turned into a snippet. Nicolas's case is reasonable and others may hit it.
WAIT! I spoke too soon. The code has yet to work for Nicolas.
getBottomIndex should work the same way as getTopIndex. If it only return fully visible items, we can easily keep an item before the first and after the last one. With this method, I only want to prevent calculation of visible item each time a new item appears. (With 100 items visible for example). Of course, this method would be useless if the table widget has to do the same calculation on each call, but I think that value is somehow calculated internaly by the table on redraw. As I told before, I didn't test the code yet, I only looked at the calculation part that should give me the info I need. I will work on this snippet as soon as I can. Another thing : my real problem is to handle Image creation and disposal in this table. With this method I still have to use an Image cache. Another way could be to listen for dispose events on TableItems to clear the corresponding Image. But afaik there is not event fired when an item is cleared and the table is in virtual mode...
How can I do the same with a Tree ?
In bug 146799 comment #3, Grant wrote: > SN, the issue here is that jface is calling Table.getTopIndex() from within the > SetData callback, and is not getting the expected answer. It uses this value > to compute the set of currently visible items, and from this queries the model > elements accordingly. Could you please look at bug 146799 again and tell us if calling getTopIndex() from a SetData callback is supported now? (Your snippet on this bug does just that - it calls getTopIndex() from the callback.)
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.