57 45 4c 4c 20 44 4f 4e 45 21
                   
Jan 2

Glazed Lists + SWT Tables == True

Posted on Friday, January 2, 2009 in Articles, Eclipse Articles, Programming.

If you haven’t heard about Glazed Lists until now, it’s about time you do, because it’s probably the last tables and grid sorting/filtering API you will ever need. It will also be the last time you rip your hair out when someone asks you for a multi-sort-multi-thread-asynchronously-updated-filtered-unique-table (which happens all the time, right?). From here on out you’ll just be saying “oh, sure, give me 30 minutes” when you need to implement something along those lines. Sounds too good to be true doesn’t it? It is! So, what are Glazed Lists?

Glazed Lists is an API built on top of java.util.List which adds a notification framework and allows you to “stack” or “chain” lists together. This in and by itself may not sound so exciting. What this gives you though is the ability to take a Sorted list, stack it with a Filtered list, stack it with a Unique list, stack it with a asynchronously updated Unique list (and keep stacking), and whenever you modify the source list, it automatically tells the other lists in the chain to update so that their lists are always up to date. Last but not least, the list reports back to you and tells you to update your view with a specific list of changes. So imagine this “chained list” is the input for your TableViewer and perhaps you’re starting to see the potential.

I’ve been using Glazed Lists continuously for the last year, and it’s no short of astounding how powerful it is. I’ve used them on JFace TableViewers, The Nebula Grid widget, and the great rising-star NatTable which deserves it’s own article down the road (the only table widget I’ve found that can handle huge amounts of data without choking). On each of those widgets it was only a matter of creating a couple of smaller classes, a few lines of code, and I had the most powerful sorting and filtering API at my fingertips, ready for anything upper management could throw at me in terms of features. So often I see posts on the Eclipse Newsgroups asking about multi column sorting, and usually few concrete replies. “Glazed Lists” would be my reply.  To give an idea of what kind of sorting/filtering you can do, here’s a snapshot of  some of the available list types:

Sorted List. Filtered List. Unique List. Transformed List. Range List. Threshold List. Collection List. Freezable List. Popularity List. Separator List. Sequence List. Transaction List. Observable Lists.. and the list goes on.

So instead of talking about how great they are in an entire post, how about some example implementations and actual code? Alright, let’s get to it!

To make this article “worth it” for everyone, I will cover implementing Glazed Lists on no less than 3 table/grid widgets. The standard JFace TableViewer (which is the least feature rich table component out there as it uses the SWT Table). The Nebula Grid widget (which is feature rich and very good, but has a big memory footprint on large tables) and the NatTable widget (as it will undoubtedly rise to fame soon with the next few versions (once some of the bigger bugs are ironed out)). Before you start copying and pasting code, all code is downloadable in each respective section and at the bottom of the article.

If you prefer to follow along or want to get a head start on downloading required jars, here are links to all the third party packages you might need:

Let’s start with the basics of Glazed Lists, as everything starts there.

Glazed Lists In a Nutshell

I could send you to the Glazed Lists Tutorials and tell you to follow those and come back, but I hate that kind of “teaching”, and the small “problem” with the tutorials is that they are all Java Swing based which is of little use to us (but by all means read them, they’re good). You might also want to check out the very good screen casts located here as they will give you a good idea of the different types of lists that can be used in Glazed Lists. In any case, everything in Glazed Lists starts with one thing, the root list. The root list contains all your items that you want to display before they are filtered or sorted. This list is probably in some random you-don’t-care order  which is perfectly fine. This list will serve as the input for all other chained lists. Think of it as layers, where the bottom layer is the raw list, and the higher up you go, the more refined and specific each layer is. So you have a sorting layer, a filter layer, etc. They can be active or not active, a bit like Photoshop. As we are using Glazed Lists, we need to take our root list and turn it into a Glazed Lists “EventList”, which is the Glazed Lists root-list equivalent. Here’s how that’s done:

List<?> rootList = .... // this comes from you
EventList<?> eventList = GlazedLists.eventList(rootList);

As you can see everything uses Generics, just like normal Lists in Java 5+.

Any “normal” table in the UI-world will undoubtedly have Sorting and Filtering. With the code above we’re currently no different from any other plain old table implementation as we haven’t done sorting/filtering yet. So lets create the sorting/filtering layers that will be on top of the event list. We should think about order when it comes to our layers, as if we create a sorted list on top of a filtered list that’s not the same as creating a filtered list on top of a sorted list. Logically, we sort first, then apply a filter. To create our new lists we continue the code:

List<?> rootList = .... // this comes from you
EventList<?> eventList = GlazedLists.eventList(rootList);
SortedList sortedList = new SortedList(eventList, null);
FilterList(sortedList, new OurFilterMatcher());

As you can see we keep using the last list as the input for the new list, as that’s our “chain”. The second parameter for the SortedList is the Comparator we want to use when sorting. I’m passing in null here to point out that it can be created when constructing the list (and not passing in null may actually throw an exception). Normally you don’t want the table sorted unless the user sorts it, so null makes sense. The OurFilterMatcher will be explained when we do the actual implementation, but just remember that it’s the “Matcher” that is used to filter a table (which is very much like a ViewerFilter).

There’s one more important aspect of Glazed Lists – locking. As lists can be updated on multiple threads (if you so wish) you need to tell the list when to “lock” and “unlock” so that only 1 thread is actively writing to the list at the same time. As such, it’s important we always do this when reading and writing to the list (and even if we don’t plan on multithread updates, it’s still good practice and takes little time to do). We could lock the lists when creating them even, but that’s a bit overkill, so keep en eye out for the locking code in the implementation part and in the framework code available for download. Glazed Lists even supports reading while writing, and their homepage has an example of an asynchronously updated list. Do check it out if you need advanced implementations. To give a quick example of locking/unlocking a list, here’s how it’s done:

_eventList.getReadWriteLock().writeLock().lock();
// ... modify list here ...
_eventList.getReadWriteLock().writeLock().unlock();

The Callbacks

The whole idea of Glazed Lists is that when you modify the event list (and this is important: you always modify the EventList!), it fires events to tell you what you need to change in your table implementation. Glazed has a lot of pre-built hooks for Swing, so there you don’t have to do much work, but as we use SWT we have to do pretty much all the work ourselves (great huh?). It’s not as bad as it sounds however. The callback interface that we care about here is ListEventListener which contains a method callback called public void listChanged(ListEvent<?> listChanges). This list of changes listChanges tells us, in the correct order, what indexes and objects to update, delete and insert. It’s as easy as looping through that list, checking what the change is, and performing it. Here’s a barebones example of how it would look implemented:

_filterList.addListEventListener(new ListEventListener<?>() {

	@Override
	public void listChanged(ListEvent<?> listChanges) {
		// get the list of changes (prior to looping, very important as it'll change as it's read)
		final List<?> changeList = listChanges.getSourceList();

		// go through all changes
		while (listChanges.next()) {
			// get the table index location of the change
			int sourceIndex = listChanges.getIndex();
			// get the change type
			int changeType = listChanges.getType();

			// update the table depending on the change type
			switch (changeType) {
				case ListEvent.DELETE:
					// delete row
					break;
				case ListEvent.INSERT:
					// insert row
					break;
				case ListEvent.UPDATE:
					// refresh row labels etc
					break;

			}
		}
	}

});

That’s actually the most complex code we’ll be adding to make all of this work, and we can re-use that section of code for all our table widget implementations.

You might ask “why is the listener on the filter list if we were told to only modify the event list?”, which is a good and valid question. The answer is that if you were to listen on the event list instead, only base-level adds and deletes would be reported to you. As we also care about when stuff is re-ordered or moved in the list (which is what happens when users sort and filter) we want any list-changes to notify us. As our filtered list is the “topmost” or “last” list in the chain, it will get all notifications from all previous lists in the chain. Remember, all lists in the chain tell the next list down the line what changed (think of it as one-way gossip). By listening on the Filtered list we get all events, regardless on what list they happened. With that information we’re well on our way to putting Glazed into real use.

SWT TableViewer

Personally I was never a big fan of the SWT Table. A good thing about it is that it renders column headers natively, but it can be quite slow, sometimes buggy (first-column image support) and not very intuitive. It doesn’t support much customization and the second you need a table that can do a little more than a plain x/y grid, you soon hit those limitations head on. Owner Draw does help, but there’s still a lot of customization that is not possible. That said, as a “basic table” it does just fine and it’s getting better for each new SWT version. And of course, it’s native.

Normally when someone asks “can I sort a SWT.VIRTUAL table?” the answer is no or “not really”. The reason is that a virtual table only really knows what it shows in the current viewport (the visual area of the table), and how many items it has. Anything that you can’t see is not really “there”, except in memory. This obviously makes such a useful feature as SWT.VIRTUAL fairly useless in a sort scenario. The workaround in that case is to custom implement a sorter and replace the entire table content whenever the user sorts or filters. As we use Glazed Lists we don’t really care about this limitation, we’re working around it as we update the table with our changes whenever they occur thanks to the callback from Glazed Lists.

There’s a few special things we need apart from a “normal” Virtual TableViewer implementation. First, we’ll be using the IStructuredContentProvider for the Content provider. The ILazyContentProvider exists as well, but I had some odd issues with it in testing. If you want an example on how to create a virtual TableViewer, there’s a good snippet here: Snippet029VirtualTableViewer. In the IStructuredContentProvider we simply return the topmost layer (which is the FilterList) as follows;

class GlazedContentProvider implements IStructuredContentProvider {

	@Override
	public Object[] getElements(Object inputElement) {
		return _filterList.toArray();
	}

	@Override
	public void dispose() {
	}

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
	}

}

We also need to implement a Comparator which will be used by the SortedList, as well as a Matcher for the FilterList. The Comparator is a normal java Comparator whereas the Matcher is a Glazed Lists implementation. However, these are immutable so they need to be new every time they are set on the respective lists. For the sake of simplicity, lets create an object called RowObject that represents one row in our table. All it does is keep track of the row number and it has a getColumnText method.

class RowObject {
	private int	_row;

	public RowObject(int row) {
		_row = row;
	}

	public int getRow() {
		return _row;
	}

	public String getColumnText(int col) {
		return "" + (_row + col);
	}
}

With this all set up, we can now create the Comparator and Matcher. Lets start with the Comparator. As we’re basically returning an integer as display value for each cell in getColumnText we’ll use this as the basis for our comparison. Thus, our Comparator looks as follows;

class GlazedSortComparator implements Comparator<RowObject> {

	private int	_col;
	private int	_direction;

	public GlazedSortComparator(int col, int direction) {
		_col = col;
		_direction = direction;
	}

	@Override
	public int compare(RowObject o1, RowObject o2) {
		int ret = Integer.valueOf(o1.getColumnText(_col)).compareTo(Integer.valueOf(o2.getColumnText(_col)));

		if (_direction == SWT.DOWN)
			ret = -ret;

		return ret;
	}

}

And now we create the Matcher which is used by the FilterList. The Matcher implementation in Glazed Lists asks us if a row object “matches” and not much more. This may seem confusing at first, but it’s quite similar to the ViewerFilter. In our code we will have a textbox and a button that represents a “search” box. When the user presses the button we set a String field called “_filterText” to whatever the user entered, and then we set a new matcher on the FilterList. As such, our code implementation looks like this:

class GlazedMatcher implements Matcher<RowObject> {
	@Override
	public boolean matches(RowObject row) {
		for (int i = 0; i < _table.getColumnCount(); i++) {
			if (row.getColumnText(i).indexOf(_filterText) > -1)
				return true;
		}

		return false;
	}
}

Now we can add two methods that actually do the updating when we filter and when we sort. Like this:

// update the table filter
private void updateFilter() {
	// if the search text is blank, remove the matcher
	if (_filterText == null || _filterText.length() == 0) {
		_filterList.setMatcher(null);
	}
	else {
		_filterList.setMatcher(new GlazedMatcher());
	}
}

// sorts a table on the given column
private void sortColumn(int col) {
	// do some normal UP/DOWN checking and updating
	int dir = SWT.UP;
	int current = _table.getSortDirection();


	TableColumn tc = _table.getColumn(col);
	if (_table.getSortColumn() == tc) {
		dir = (current == SWT.UP ? SWT.DOWN : SWT.UP);
	}

	_table.setSortColumn(tc);
	_table.setSortDirection(dir);

	// now tell the sorted list we've updated
	_sortedList.setComparator(new GlazedSortComparator(col, dir));
}

At this point we’re basically there. All that’s missing is a proper listChanged that reflects how we update a TableViewer. So with a few modifications to the code I posted in the nutshell section, we get code that looks like this:

_filterList.addListEventListener(new ListEventListener<RowObject>() {

	@Override
	public void listChanged(ListEvent<RowObject> listChanges) {
		try {
			_table.setRedraw(false);

			// get the list PRIOR to looping, otherwise it won't be the same list as it's modified continuously
			final List<RowObject> changeList = listChanges.getSourceList();

			while (listChanges.next()) {
				int sourceIndex = listChanges.getIndex();
				int changeType = listChanges.getType();

				switch (changeType) {
					case ListEvent.DELETE:
						// note the remove of the object fetched from the event list here, we need to remove by index which the viewer does not support
						// and we're removing the object index location from the event list, not the filtered list
						_viewer.remove(_eventList.get(sourceIndex));
						break;
					case ListEvent.INSERT:
						final RowObject obj = changeList.get(sourceIndex);
						_viewer.insert(obj, sourceIndex);
						_viewer.replace(_filterList.get(sourceIndex), sourceIndex);
						break;
					case ListEvent.UPDATE:
						_viewer.replace(_filterList.get(sourceIndex), sourceIndex);
						break;
				}
			}

			// most important, we update the table size after the update
			_viewer.setItemCount(_filterList.size());
		}
		catch (Exception err) {
			err.printStackTrace();
		}
		finally {
			_table.setRedraw(true);
		}
	}

});

The result, when combined with the rest of the necessary boilerplate code, looks like this:

tv_glazed

Download Code

TableViewerGlazedExample.java

Nebula Grid

Whereas the normal SWT table only supports single column sort (unless you owner draw) the Nebula grid can do more. It can do multiple column sorting (visually), grouped columns, and other custom features not available in the default grid. The Nebula Grid has a Viewer implementation, but unfortunately at the time of writing this article, it does not support SWT.VIRTUAL mode. As Nebula sticks very much to the SWT API in terms of naming conventions and implementation, it should be little trouble to convert it over when it does.

Depending on how you look at it, you are about to get quite lucky. For my job I wrote an entire framework implementation wrapping Glazed Lists in a Nebula Grid. It’s much more generically implemented (with interfaces etc) than our TableViewer example which was written purely for this article. Because of this I don’t feel like actually ripping it apart into something smaller, so I will use this Framework as the basis for the examples. Thus, this implementation comes with the option to use both the GridViewer implementation (which might be good if you are doing smaller tables that don’t need Virtual mode) or the grid in SWT.VIRTUAL mode.

One of the bigger differences when we’re not in viewer mode, is that on the DELETE, INSERT and UPDATE we need to create GridItems instead of just telling the viewer that it’s changed. It’s a bit more clunky and object-heavy of course, but it’s not as bad as it sounds. The switch statement that we used in the previous example becomes this:

switch (changeType) {
    case ListEvent.DELETE:
        removeItem(sourceIndex);
        break;
    case ListEvent.INSERT:
        final IDataObject insert = list.get(sourceIndex);
        addItem(insert, sourceIndex);
        break;
    case ListEvent.UPDATE:
        final IDataObject update = list.get(sourceIndex);
        removeItem(sourceIndex);
        addItem(update, sourceIndex);
        break;
}

As you can see each one calls a sub-method of the class, and those methods look like this:

private void removeItem(int index) {
	_parent.getTableViewer().remove(_parent.getTableViewer().getElementAt(index));
}

private void addItem(IDataObject msg, int index) {
	GridItem gi = new GridItem(_parent.getGrid(), SWT.NONE, index);
	gi.setData(msg);

	try {
		for (int i = 0; i < _parent.getGrid().getColumnCount(); i++) {
			Color fg = msg.getForeground(i, index % 2 == 0);
			Color bg = msg.getBackground(i, index % 2 == 0);
			Font f = msg.getFont(i);
			String txt = msg.getColumnText(i);
			Image image = msg.getColumnImage(i);

			if (fg != null) {
				gi.setForeground(i, fg);
			}
			if (bg != null) {
				gi.setBackground(i, bg);
			}
			if (f != null) {
				gi.setFont(i, f);
			}
			if (txt != null) {
				gi.setText(i, txt);
			}
			if (image != null) {
				gi.setImage(i, image);
			}
		}
	}
	catch (Exception err) {
		err.printStackTrace();
	}
}

In this code we use an interface IDataObject that is basically our RowObject code from before. This object has various getter methods for returning column texts, images, fonts and so on.

So how do we go about creating a Nebula Grid based grid with this framework? Mostly it’s the same way it’s done with pretty much any SWT widget, along the lines of:

GlazedGridViewer viewer = new GlazedGridViewer(shell, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.VIRTUAL, this, true, null, null, false);
viewer.setAllowMultiColumnSort(true);
viewer.getGrid().setCellSelectionEnabled(true);

Some pointers: The this parameter is an interface implementation of IGenericGridTable which forces the implementor of the code to include methods for returning a Comparator and a Matcher, like we created before in the previous example. true is the option to create the grid as a plain grid, or to false to create a viewer. The last 3 parameters are a String id used for saving/loading the table state (column order, sizes etc), an IPreferenceStore where it would be saved on, and lastly a true/false whether the table should be saving the state at all.

The framework comes with a default implementation of a Label provider and a Content provider which hooks into the IDataObject. They are created automatically depending on the table type you picked. Column creation is also handled by the framework as the column wrapping implementation allows for individual setting of if a column is sortable, movable, hide-able etc. The API looks like:

public GridViewerColumn(IGlazedGridViewer parentTable, String name, boolean frozen, boolean moveable, boolean sortable, boolean hideable) {
     ...
}

But when you create a column you do it via the framework as:

GridViewerColumn col = viewer.addColumn(str, false, true, true, true);
col.getGridColumn().setWidth(100);

And finally, to add objects and set the table input, it’s again much like the TableViewer, for example:

List<IDataObject> input = new ArrayList<IDataObject>();
for (int i = 0; i < 1000; i++) {
	input.add(new OurIDataObjectClass(i));
}
viewer.setInput(input);

I don’t think much more needs to be said about the framework. It has a lot of API in it already and a test class as well. I suggest you download it if you want to give it a go.

Important: as I currently am not using the framework due to the fact that the Nebula Grid was too slow and memory hungry for what we needed it for (40,000+ rows) I converted the entire framework over to use a NatTable and kept the work going from there. It should be fine, but there may be some minor issues here and there as it was never fully tested. If you find problems and fix them, do send me the code so that everyone can benefit. For the NatTable implementation of the framework, that’s the next section of this article.

All put together, the test code looks like this when run (with shameless self-promo selection):

tv_nebula

No filter box in this example, but I think the TableViewer one shows how it works so it’s not necessary. A point worth making though is that all filters are DataFilter based (framework class). That class extends ViewerFilter so that if you need more than one table implementation, you can re-use your filters should you so wish. That filter also comes with “whole word”, “regular expression” and “case sensitive” filter/search options in the filter itself.

Download Code

Glazed Lists – Nebula Grid Framework

Nat Table

The NatTable Widget (Nat stands for Natalie, the girlfriend of the original widget author) is a fairly new Grid widget and one that I personally was quite impressed with after having researched pretty much all SWT grid widgets out there. It’s still in active development, and not everything is working 100% yet (grouped columns are problematic, some random drawing issues, frozen columns behave oddly, listeners are quite messy), but overall it’s in a good enough shape that we decided to use it in production. The reason I decided we should use it was simple; We needed a table that could deal with 40,000+ rows in 20+ columns without any lag or any drawing slowdowns whatsoever. It needed to be customizable and I wanted Glazed Lists on it. NatTable is inherently virtual, so you don’t tell it that it’s virtual, it just is. It only draws what you see in the viewport which makes redraws near instant and the overall feel is “snappy”.

The NatTable API is also quite different from most SWT widgets. Pretty much every part of the table can be extended or implemented in a custom way, and there’s a lot of classes and places to do this in. At the same time, the API feels sometimes half-finished as simple methods such as selectAll() are nowhere to be found, and trying to figure out how to do it can be a bit of a head-scratcher. So, It takes a while to wrap your head around the API, but with help from a few examples on their homepage it shouldn’t be too much of a deal (and most of those kinds of methods are in the framework). The table is model driven, which I suppose is the third type of table model I see used in tables (first being no model and row-item based, second being a viewer on top of a row-item based grid).

All that said, I truly hope the current development team keeps this widget going (and from the looks of it it’s very active), because it just might be the best SWT grid-table currently out there. The Nebula Grid had huge potential, but development on it is slow going. I know Tom Shindl is doing work on it, but I don’t know what the roadmap is.

Ok, lets get going with the framework I’ve built for NatTable. It’s not complete, just like the Nebula Grid framework which it is based on, but it will get you a very long way. As this framework has gotten further it has more utility methods and automation than it’s predecessor. It will even mimic the Windows column headers through a custom header drawer if so desired. It also has full color-customization support via interfaces and so on. It would be a long list if I wrote it all here, so I suggest you check out the API.

To create a table using the framework, you can use various constructors, of which the biggest is:

public GlazedNatGridViewer(Composite parent, int style, IGenericNatGridTable generic, String tableId, IPreferenceStore store, boolean allowStateSaving, AbstractGlazedNatVisualConfig config) {
       ...
}

You will notice the IGenericNatGridTable is the same interface as in the Nebula Grid framework and works the same way (just different name). The last parameter, AbstractGlazedNatVisualConfig is if you want to pass in custom settings for colors, fonts, widths, heights etc. A whole load of things can be customized, or you can stick to the defaults (DefaultGlazedNatVisualConfig).

In our test class we will do the same as we’ve done in the previous examples, we’ll create some columns, some row data and do a sort. Using the framework we create a new table as follows:

GlazedNatGridViewer viewer = new GlazedNatGridViewer(shell, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.FULL_SELECTION, this, new DefaultGlazedNatVisualConfig());
viewer.setAllowMultiColumnSort(true);

for (int i = 0; i < 10; i++) {
	NatGridViewerColumn col = viewer.addColumn("Column "+i, false, true, true, true);
	col.setDefaultWidth(100);
}

List<OneRow> input = new ArrayList<OneRow>();
for (int i = 0; i < 1000; i++) {
	input.add(new OneRow(i));
}

viewer.setInput(input);

Our OneRow class implements IDataObject which contains getters for all things table related (column text etc). It also contains a getter specifically for returning a value that should be used when comparing column data when sorting. By default we simply return the same column text as the visible-to-user text:

class OneRow implements IDataObject {
		
	private int _row;

	public OneRow(int row) {
		_row = row;
	}

	@Override
	public String getColumnText(int column) {
		return ""+(_row+column);
	}

	@Override
	public String getSearchMatchText(int column) {
		return getColumnText(column);
	}
	
	...	
}

The multi column sort feature is already built in, and uses Glazed Lists ability to chain comparators. So whenever you sort more than one column, it will ask for a Comparator for each sorted column, and combine them in the order that you sorted the columns. You multi-sort by holding down the shift key to add more columns, and I’ve also added so it draws a number on the column header for displaying which order it was sorted in. The sort happens as soon as you let go of the shift key (and you can modify the columns by pressing the shift key again before clicking the column header).

Running the test class we get a table that looks like this:

Glazed Nat Table Viewer

That pretty much sums it up for the Nat Table. Regardless of what table implementation you are going with or decide to go with, I’m sure you will agree that the power and simplicity of Glazed Lists is amazing. And we’ve only scratched the surface on it here. For much more information and examples with deeper complexity I suggest visiting the homepage and checking the Glazed Lists API. They have some built-in support for SWT as well (such as putting your updates on the UI thread), so they’re not 100% Swing-based even though most of their pre-implemented table-realted items are for Swing components.

Download Code

Glazed Lists – Nat Table Framework

Closing words

This was a long article. It took me 2 full days to write and much longer if you count the hours put into creating both frameworks. My hopes is that you will find the article and Glazed Lists useful in your future table and grid implementations, and that this wonderful package becomes as part of your projects as MigLayout or other “must have” API’s that make our lives coding UI’s much easier. Personally I cannot live without Glazed Lists, and I only wish I had found out about them sooner.

And again, I highly recommend the screen casts for more information on each type of list you can create.

Do let me know if you spot errors in the article, it’s hard to cover everything on the first try. I will put these files + a link to this post into the Projects section later as well.

All Code

Here are download links to all code referenced in this article:

  1. MenuManagers and You If you’re using Eclipse RCP (or even standalone SWT with...
  2. RCP Workspaces An “Eclipse workspace” is basically a directory where all your...
  3. The Secondary ID In many RCP applications your views (ViewParts) will not be...
  4. Printing SWT Tables with PaperClips In this article I will explain how to print a...
  5. Creating a Notification Popup Widget In this article I will explain how to create a...

25 Responses to “Glazed Lists + SWT Tables == True”

  1. Peter - January 3rd, 2009

    Hi Emil.

    Thx for this great article. Looks intersting and could be very helpful.

    Regards.

    Peter

  2. Boris Bokowski - January 5th, 2009

    Emil,

    Thanks for the interesting post, it is very important that people like you write about their practical experience with all the different libraries and frameworks that are available.

    Glazed Lists is definitely a very interesting and useful library. I am not sure if you are aware that some parts of Eclipse’s data binding framework are conceptually very close to Glazed Lists. I just wish we had more of the useful list abstractions (sorted list, filtered list, range list, …) in the data binding framework but I am still waiting for someone to contribute that code… ;-)

  3. Jesse - January 6th, 2009

    Sweeeet

  4. Seweryn Niemiec - January 6th, 2009

    Hi Emil,

    Great article. Thx for taking pains to write such exhaustive and interesting tutorial. It’s very helpful for me.

  5. Rob - January 12th, 2009

    Thanks much for documenting your experience here. I am currently struggling with a Virtual SWT Table, and hadn’t heard of Nat Table.

    My problem is needing to support hundreds of thousands of rows. The model is caching database results but there is latency…so I’m trying to figure out how to deal with filling in the table (when? how much?) when there isn’t data available @ time of SetData event. Any ideas? :)

  6. Emil - January 12th, 2009

    Well, there’s definitely one or two things you could do for “massive” tables of the size you mention. I would suggest giving NatTable a try because it’s very fast on very large numbers (and although I have not tested 100.000′s of rows, I don’t see why it would have an issue). With Glazed Lists you can probably do delayed updates as it has such a massive support for customizing your lists. You probably want to take a look at the concurrency section, which can be found in their tutorials as well, as that seems to be the “area” that mostly fits with doing delayed updates due to latency. And from what I recall off-hand, the sample that runs via Java Webstart also show a delayed-update table as it loads a list of table entries from the web.

  7. Rob - January 13th, 2009

    Thanks for responding to my question! I really appreciate your specific advice…this is very helpful to me. Cheers.

  8. Neil Bartlett - January 14th, 2009

    Extremely useful, thanks!

    One small comment on the code… you’ve used @Override annotations on methods that implement interface methods rather than override superclass methods. That’s only valid on Java 6, so your code won’t compile under Java 5. If you want to be compatible with Java 5 then it might be useful to remove those annotations.

    Thanks again,
    Neil

  9. rob - January 22nd, 2009

    Any reason you didn’t consider the Nebula CompositeTable? (Besides the song in the screencast) :)

  10. Andy - January 28th, 2009

    Recently I observed that 3.4 swt virtual table is improved in a big way. They spent time to tune up the scrolling and redraw machinism. If you have performance issues while using the SWT implementation and customization is not required in your situation, you definitely should try the latest swt version as well.

  11. Jay Norwood - February 13th, 2009

    In your examples, you get changeList, and your stated reason is that “prior to looping, very important as it’ll change as it’s read”. However, then in the loop you continue to use listChanges, which I presume is the list that continues updating. Should the loop have been using changeList instead?

  12. Emil - February 13th, 2009

    Hi Jay.

    The code is correct, the only place it is used again is for getting the index and the type, which is fine. The comment is trying to say that we don’t want to re-fetch the list of changes inside the loop, as when we do (listChanges.next()) it actually modifies the list (which is different from for example iterating over a normal java list), which would make any subsequent call return a bad list and cause all kinds of issues. Perhaps the comment needs rewording but the code should be correct.

  13. Jay Norwood - February 14th, 2009

    Let me be more specific. In The Callbacks code above, you make a point about the list changing, and so you get the stable listChanges, but then you never use it again. Instead you iterate through changeList, which I presume can still be changing. So what was your point in getting listChanges in that example?

    @Override public void listChanged(ListEvent listChanges) { // get the list of changes (prior to looping, very important as it’ll change as it’s read) final List changeList = listChanges.getSourceList(); // go through all changes while (listChanges.next()) {

  14. Jay Norwood - February 14th, 2009

    Sorry, I got that backwards.

    You get the stable changeList, but you iterate through the changing listChanges. So what is the point of getting the stable local copy into changeList?

  15. Jay Norwood - February 21st, 2009

    I noticed that there are some references to KTable in the glazed lists documentation. I downloaded and ran the KTable examples and found the large table handling to be pretty fast.

    http://sourceforge.net/projects/ktable

    I was interested in getting beyond the int range in rows. I found that Ktable couldn’t do that. The scroll range goes to 2G, but their were limitations before then.

    I went through the code changing ints to longs everywhere, plus created a LongPoint and LongRectangle, and made some scaling of the scrollbar values, and now I have something working that I’ve tested with 8G rows.

    I wonder what portions of glazed lists would be useful in an application with 8G rows. Does it become a memory hog with all its intermediate lists?

  16. Deepak - April 1st, 2009

    thank you, very informative .. we use glazed lists a lot and you’re right.. it rocks!

  17. Brian - May 8th, 2009

    I went with the nebula grid along with your glazed list viewer and really liked it…on the Windows machine. The moment I took this application to the SolarisGTK world, the flickering from the updates I require was just insane. I tried the redraw on/off trick to no avail. Anyone else have this issue or know a way to correct it?

  18. Emil - May 8th, 2009

    Hi Brian,

    If you’re having problems that are related to the widgets themselves, I suggest you ask on the various widget-related boards. For the Nebula Grid, ask your question on the Nebula newsgroup as there you will certainly have a higher chance of getting a reply. You can find more info on the Eclipse newsgroups and how to connect etc here: http://www.eclipse.org/newsgroups/. Do provide a snippet of code as well when you ask your question on the boards as it helps solving the issue quicker. Thanks!

    Emil

  19. philk - July 15th, 2009

    Emil, is there a reason why you do not use GlazedLists own implementation of EventTableViewer? It can be virtual too. Of course using the JFace TableViewers can give you all kind of advantages like custom draw cell renderes etc.

  20. Talkwards » Blog Archive » links for 2009-09-09 - September 9th, 2009

    [...] Glazed Lists + SWT Tables == True | Hexapixel "If you haven’t heard about Glazed Lists until now, it’s about time you do, because it’s probably the last tables and grid sorting/filtering API you will ever need." (tags: eclipse java List glazed) [...]

  21. Aymen - December 12th, 2009

    Hi,
    I’m using SWT table without JFace TableViewer because I can’t use JFace under my IDE (NetBeans).
    How I can use the GlazedLists API in raw SWT Table without calling any JFace class in order to implement table filtering?
    Can I have a code example please ?
    Cordially.

  22. Aymen - December 14th, 2009

    Hi,

    Sorry for the disturb;

    Is there any method to use GlazedLists API without any JFace component in order to implement table filtering ?

    In other words, how to implement table filtering using only an SWT text widget and a simple SWT table ?

    Thanks in advance.

  23. Mr Cube - February 24th, 2010

    Wow, that article was awesome! I have recently saw/read about GlazedLists, and yes, u are ABSOLUTELY wright : the examples on their website are all swing based, which almost made me give up the idea :-) . So, a clear and plain SWT implementation is golden and very much appreciated. I look forward to see those lists in action! Cheers.

  24. Evvo - December 1st, 2010

    It’s a wonderful example!
    How does one apply color to the text in the cells?