The "One Laptop Per Child" project has a great device ready to ship, but there's no Java on there. Let's think about working together to put Java on OLPC!
Replies:
20 -
Pages:
2
[
12
| Next
]
Threads:
[
Previous
|
Next
]
I was kind of surprised that JFace table sorting doesn't work both ways. I'm sure that there are reasons for this I don't see (I'm not a very experienced GUI programmer), but I thought it must be easy to provide a minimal "framework" for this, and here it is. Feel free to add any comments on how to improve this!
The first class represents an InvertableSorter; it extends the ViewerSorter class:
The second class is the class you have to extend when implementing your sorter. All you have to do is to overwrite the compare(Viewer viewer, Object e1, Object e2) method. I expect that in many cases it's best to extend this class with your own abstract class (see example below).
The last class, TableSortSelectionListener, does the actual work. It extends SelectionListener and takes care of event handling. It knows to which column of the table it belongs. Note that in the constructor you can select in which order the column is to be sorted initially, and if the last ordering is to be restored after another column had been selected.
publicclass TableSortSelectionListener implements SelectionListener {
privatefinal TableViewer viewer;
privatefinal TableColumn column;
privatefinal InvertableSorter sorter;
privatefinalboolean keepDirection;
private InvertableSorter currentSorter;
/**
* The constructor of this listener.
*
* @param viewer
* the tableviewer this listener belongs to
* @param column
* the column this listener is responsible for
* @param sorter
* the sorter this listener uses
* @param defaultDirection
* the default sorting direction of this Listener. Possible
* values are {@link SWT.UP} and {@link SWT.DOWN}
* @param keepDirection
* if true, the listener will remember the last sorting direction
* of the associated column and restore it when the column is
* reselected. If false, the listener will use the default soting
* direction
*/
public TableSortSelectionListener(TableViewer viewer, TableColumn column,
AbstractInvertableTableSorter sorter, int defaultDirection,
boolean keepDirection) {
this.viewer = viewer;
this.column = column;
this.keepDirection = keepDirection;
this.sorter = (defaultDirection == SWT.UP) ?
sorter : sorter.getInverseSorter();
this.currentSorter = this.sorter;
this.column.addSelectionListener(this);
}
/**
* Chooses the colum of this listener for sorting of the table. Mainly used
* when first initialising the table.
*/
publicvoid chooseColumnForSorting() {
viewer.getTable().setSortColumn(column);
viewer.getTable().setSortDirection(currentSorter.getSortDirection());
viewer.setSorter(currentSorter);
}
publicvoid widgetSelected(SelectionEvent e) {
InvertableSorter newSorter;
if (viewer.getTable().getSortColumn() == column) {
newSorter = ((InvertableSorter) viewer.getSorter())
.getInverseSorter();
} else {
if (keepDirection) {
newSorter = currentSorter;
} else {
newSorter = sorter;
}
}
currentSorter = newSorter;
chooseColumnForSorting();
}
publicvoid widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
}
Ok, and here is the example I promised at the beginning . There's not too much to say about it, I guess...
publicclass TableDemo {
private TableDemo() {
// create shell
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setLayout(new FillLayout());
shell.setText("TableDemo");
// set up table layout
TableViewer viewer = new TableViewer(shell);
TableLayout layout = new TableLayout();
layout.addColumnData(new ColumnWeightData(50, 100, true));
layout.addColumnData(new ColumnWeightData(50, 100, true));
viewer.getTable().setLayout(layout);
viewer.getTable().setLinesVisible(true);
viewer.getTable().setHeaderVisible(true);
// create columns. The 1st coumn will initially be the sorting column.
// It will be sorted SWT.DOWN, and it will remember its last sorting order.
// The 2nd column will initially be sorted SWT.UP, and it will reset to
// that initial sorting order when being reselected.
TableDemo.createTableColumn(viewer, "Column 1", "Column 1 tooltip",
new TextSorter(), SWT.DOWN, true).chooseColumnForSorting();
TableDemo.createTableColumn(viewer, "Column 2", "Column 2 tooltip",
new NumberSorter(), SWT.UP, false);
// set providers
viewer.setContentProvider(new TableDemoContentProvider());
viewer.setLabelProvider(new TableDemoLableProvider());
// create and set data of demo
Set<Data> set = new HashSet<Data>();
set.add(new Data("a", 1));
set.add(new Data("b", 2));
set.add(new Data("c", 3));
viewer.setInput(set);
// pack everything
viewer.getTable().pack();
shell.pack();
// open shell
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
// convenience method
publicstatic TableSortSelectionListener createTableColumn(
TableViewer viewer, String text, String tooltip,
AbstractInvertableTableSorter sorter, int initialDirection,
boolean keepDirection) {
TableColumn column = new TableColumn(viewer.getTable(), SWT.LEFT);
column.setText(text);
column.setToolTipText(tooltip);
returnnew TableSortSelectionListener(viewer, column, sorter,
initialDirection, keepDirection);
}
publicstaticvoid main(String[] args) {
new TableDemo();
}
privateclass Data {
String text;
int number;
private Data(String text, int number) {
this.text = text;
this.number = number;
}
}
privateclass TableDemoContentProvider implements
IStructuredContentProvider {
public Object[] getElements(Object inputElement) {
return ((Set) inputElement).toArray();
}
publicvoid dispose() {
}
publicvoid inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
privateclass TableDemoLableProvider implements ITableLabelProvider {
public Image getColumnImage(Object element, int columnIndex) {
returnnull;
}
public String getColumnText(Object element, int columnIndex) {
Data data = (Data) element;
String columnText;
switch (columnIndex) {
case 0:
columnText = data.text;
break;
case 1:
columnText = StringConverter.asString(data.number);
break;
default:
columnText = "not set";
}
return columnText;
}
publicvoid addListener(ILabelProviderListener listener) {
}
publicvoid dispose() {
}
publicboolean isLabelProperty(Object element, String property) {
returnfalse;
}
publicvoid removeListener(ILabelProviderListener listener) {
}
}
// convenience class which avoids casting in subclasses
privateabstractclass AbstractDemoSorter extends
AbstractInvertableTableSorter {
publicint compare(Viewer viewer, Object e1, Object e2) {
return compare((Data) e1, (Data) e2);
}
publicabstractint compare(Data d1, Data d2);
}
privateclass TextSorter extends AbstractDemoSorter {
publicint compare(Data d1, Data d2) {
return Collator.getInstance().compare(d1.text, d2.text);
}
}
privateclass NumberSorter extends AbstractDemoSorter {
publicint compare(Data d1, Data d2) {
return Util.compare(d1.number, d2.number);
}
}
}
As I said in the beginning: Feel free to add any comments on how to improve this! I'm really looking forward to learn...
Recent versions of Eclipse support moving columns around in a table. And of course you could always resize them. It's nice to be able to close a view (or all of Eclipse or your RCP app) and come back and have everything exactly the way you set it up before closing it.
ok, your request makes more sense in the context of RCP apps. My "framework" (does anybody have a better name for this?) is also usable in plain JFace applications.
Actually, I'm right now learning to build an RCP app (for which I don't have too much time, though, because I'm also working on my diploma thesis). So I don't think it's the right time to jump into such a kind of specialized topic...
But I totally agree that it would be nice to have something like this.
Cool stuff! I like your construction. I've got 2 comments on this:
1.) you can drastically improve the sorting speed by disabling the redraw in the tableViewer before sorting and reenabling it just afterwards:
public void chooseColumnForSorting() {
viewer.getTable().setSortColumn(column);
viewer.getTable().setSortDirection(currentSorter.getSortDirection());
viewer.getControl().setRedraw(false);
viewer.setSorter(currentSorter);
viewer.getControl().setRedraw(true);
}
2.) you use a model object specially for the table (Data with its properties). This might be usefull but could e a problem in an app that already has huge amount of data (like in a db-viewer). In this case it's better to use the original domain objects and interfaces/refletion to access the property of this domain-object thats displayed in the column.
Sorry, was not monitoring the threads for a while. To answer your questions:
1. how i update the swt 3.1 to 3.2 in eclipse 3.1?
i have to update the eclipse too?
>> You need to download eclipse version 3.2.
2. if i use the swt 3.2 instead of the 3.1 that i'm using now, should i have to do some changes im my code in order to support the 3.2?
>> You may need to change your code in 3.2, depending on what you have used. If you have used the published API, you maynot need to changed, but few things are deprecated. I would advise you to create a project using the standard template, and then have your views/editors/etc added. This should make life simple.
I also need to say sorry for the late response - Sanjay's mail was the reminder
> 1. how i update the swt 3.1 to 3.2 in eclipse 3.1?
> i have to update the eclipse too?
No, you don't, but you need to download it (or at least the current version of SWT), as Sanjay already pointed out.
If you run something within Eclipse as an SWT Application, Eclipse takes care of the SWT libraries needed in the classpath etc., but you can also manually add the to the classpath (and run as a normal Java Application).
Just grab the SWT libraries from a current Eclipse version (e.g. 3.2M5), copy them into a lib folder within your project and add them as libraries, and your project should compile fine.
To run your application, you also need to add the native libraries with Run.../Arguments/VM Arguments.
> 2. if i use the swt 3.2 instead of the 3.1 that i'm
> using now, should i have to do some changes im my
> code in order to support the 3.2?
Sorting a TableViewer's columns both ways
At 4:01 AM on Dec 12, 2005, Christian Soltenborn
wrote:
I was kind of surprised that JFace table sorting doesn't work both ways. I'm sure that there are reasons for this I don't see (I'm not a very experienced GUI programmer), but I thought it must be easy to provide a minimal "framework" for this, and here it is. Feel free to add any comments on how to improve this!
The first class represents an InvertableSorter; it extends the ViewerSorter class:
abstract class InvertableSorter extends ViewerSorter { public abstract int compare(Viewer viewer, Object e1, Object e2); abstract InvertableSorter getInverseSorter(); public abstract int getSortDirection(); }The second class is the class you have to extend when implementing your sorter. All you have to do is to overwrite the compare(Viewer viewer, Object e1, Object e2) method. I expect that in many cases it's best to extend this class with your own abstract class (see example below).
public abstract class AbstractInvertableTableSorter extends InvertableSorter { private final InvertableSorter inverse = new InvertableSorter() { public int compare(Viewer viewer, Object e1, Object e2) { return (-1)*AbstractInvertableTableSorter.this .compare(viewer, e1, e2); } InvertableSorter getInverseSorter() { return AbstractInvertableTableSorter.this; } public int getSortDirection() { return SWT.DOWN; } }; InvertableSorter getInverseSorter() { return inverse; } public int getSortDirection() { return SWT.UP; } }The last class, TableSortSelectionListener, does the actual work. It extends SelectionListener and takes care of event handling. It knows to which column of the table it belongs. Note that in the constructor you can select in which order the column is to be sorted initially, and if the last ordering is to be restored after another column had been selected.
public class TableSortSelectionListener implements SelectionListener { private final TableViewer viewer; private final TableColumn column; private final InvertableSorter sorter; private final boolean keepDirection; private InvertableSorter currentSorter; /** * The constructor of this listener. * * @param viewer * the tableviewer this listener belongs to * @param column * the column this listener is responsible for * @param sorter * the sorter this listener uses * @param defaultDirection * the default sorting direction of this Listener. Possible * values are {@link SWT.UP} and {@link SWT.DOWN} * @param keepDirection * if true, the listener will remember the last sorting direction * of the associated column and restore it when the column is * reselected. If false, the listener will use the default soting * direction */ public TableSortSelectionListener(TableViewer viewer, TableColumn column, AbstractInvertableTableSorter sorter, int defaultDirection, boolean keepDirection) { this.viewer = viewer; this.column = column; this.keepDirection = keepDirection; this.sorter = (defaultDirection == SWT.UP) ? sorter : sorter.getInverseSorter(); this.currentSorter = this.sorter; this.column.addSelectionListener(this); } /** * Chooses the colum of this listener for sorting of the table. Mainly used * when first initialising the table. */ public void chooseColumnForSorting() { viewer.getTable().setSortColumn(column); viewer.getTable().setSortDirection(currentSorter.getSortDirection()); viewer.setSorter(currentSorter); } public void widgetSelected(SelectionEvent e) { InvertableSorter newSorter; if (viewer.getTable().getSortColumn() == column) { newSorter = ((InvertableSorter) viewer.getSorter()) .getInverseSorter(); } else { if (keepDirection) { newSorter = currentSorter; } else { newSorter = sorter; } } currentSorter = newSorter; chooseColumnForSorting(); } public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } }Ok, and here is the example I promised at the beginning
public class TableDemo { private TableDemo() { // create shell Display display = new Display(); Shell shell = new Shell(display, SWT.SHELL_TRIM); shell.setLayout(new FillLayout()); shell.setText("TableDemo"); // set up table layout TableViewer viewer = new TableViewer(shell); TableLayout layout = new TableLayout(); layout.addColumnData(new ColumnWeightData(50, 100, true)); layout.addColumnData(new ColumnWeightData(50, 100, true)); viewer.getTable().setLayout(layout); viewer.getTable().setLinesVisible(true); viewer.getTable().setHeaderVisible(true); // create columns. The 1st coumn will initially be the sorting column. // It will be sorted SWT.DOWN, and it will remember its last sorting order. // The 2nd column will initially be sorted SWT.UP, and it will reset to // that initial sorting order when being reselected. TableDemo.createTableColumn(viewer, "Column 1", "Column 1 tooltip", new TextSorter(), SWT.DOWN, true).chooseColumnForSorting(); TableDemo.createTableColumn(viewer, "Column 2", "Column 2 tooltip", new NumberSorter(), SWT.UP, false); // set providers viewer.setContentProvider(new TableDemoContentProvider()); viewer.setLabelProvider(new TableDemoLableProvider()); // create and set data of demo Set<Data> set = new HashSet<Data>(); set.add(new Data("a", 1)); set.add(new Data("b", 2)); set.add(new Data("c", 3)); viewer.setInput(set); // pack everything viewer.getTable().pack(); shell.pack(); // open shell shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } // convenience method public static TableSortSelectionListener createTableColumn( TableViewer viewer, String text, String tooltip, AbstractInvertableTableSorter sorter, int initialDirection, boolean keepDirection) { TableColumn column = new TableColumn(viewer.getTable(), SWT.LEFT); column.setText(text); column.setToolTipText(tooltip); return new TableSortSelectionListener(viewer, column, sorter, initialDirection, keepDirection); } public static void main(String[] args) { new TableDemo(); } private class Data { String text; int number; private Data(String text, int number) { this.text = text; this.number = number; } } private class TableDemoContentProvider implements IStructuredContentProvider { public Object[] getElements(Object inputElement) { return ((Set) inputElement).toArray(); } public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } } private class TableDemoLableProvider implements ITableLabelProvider { public Image getColumnImage(Object element, int columnIndex) { return null; } public String getColumnText(Object element, int columnIndex) { Data data = (Data) element; String columnText; switch (columnIndex) { case 0: columnText = data.text; break; case 1: columnText = StringConverter.asString(data.number); break; default: columnText = "not set"; } return columnText; } public void addListener(ILabelProviderListener listener) { } public void dispose() { } public boolean isLabelProperty(Object element, String property) { return false; } public void removeListener(ILabelProviderListener listener) { } } // convenience class which avoids casting in subclasses private abstract class AbstractDemoSorter extends AbstractInvertableTableSorter { public int compare(Viewer viewer, Object e1, Object e2) { return compare((Data) e1, (Data) e2); } public abstract int compare(Data d1, Data d2); } private class TextSorter extends AbstractDemoSorter { public int compare(Data d1, Data d2) { return Collator.getInstance().compare(d1.text, d2.text); } } private class NumberSorter extends AbstractDemoSorter { public int compare(Data d1, Data d2) { return Util.compare(d1.number, d2.number); } } }As I said in the beginning: Feel free to add any comments on how to improve this! I'm really looking forward to learn...
Bye,
Christian
20 replies so far (
Post your own)
Re: Sorting a TableViewer's columns both ways
Thanks for the tip. Extra credit for some who adds persisting the sort order and column widths, and handling moving columns around.Author, Google Web Toolkit, Eclipse IDE Pocket Guide, Eclipse in Action
ZDNet blogger, Dev Connection; former Top Eclipse Ambassador.
Re: Sorting a TableViewer's columns both ways
Hi Christian,Nice work. Can you add the examples as attachments, or a zip containing them all? It's a lot easier than cut-n-paste.
Cheers,
Neil.
Re: Sorting a TableViewer's columns both ways
Hi Neil,thanks! I've attached a jar file containing the class and source files of the "framework" and the demo.
Bye,
Christian
Re: Sorting a TableViewer's columns both ways
Hi Ed,could you explain in more detail what you would like to have? I'm not sure what you mean... I'll definitely have a look at it then.
Thanks,
Christian
Re: Sorting a TableViewer's columns both ways
Recent versions of Eclipse support moving columns around in a table. And of course you could always resize them. It's nice to be able to close a view (or all of Eclipse or your RCP app) and come back and have everything exactly the way you set it up before closing it.Author, Google Web Toolkit, Eclipse IDE Pocket Guide, Eclipse in Action
ZDNet blogger, Dev Connection; former Top Eclipse Ambassador.
Re: Sorting a TableViewer's columns both ways
Hi again,ok, your request makes more sense in the context of RCP apps. My "framework" (does anybody have a better name for this?) is also usable in plain JFace applications.
Actually, I'm right now learning to build an RCP app (for which I don't have too much time, though, because I'm also working on my diploma thesis). So I don't think it's the right time to jump into such a kind of specialized topic...
But I totally agree that it would be nice to have something like this.
Bye,
Christian
Re: Sorting a TableViewer's columns both ways
what is your jface or swt version? could be the versions?because i have some error in:
//line 104 and 114
if (viewer.getTable().getSortColumn().equals(column)) {
//The method getSortColumn() is undefined for the type Table
//line 105 viewer.getTable().setSortDirection(currentSorter.getSortDirection());
//The method setSortDirection(int) is undefined for the //type Table
thanks
Marco
Re: Sorting a TableViewer's columns both ways
ahh, i forgot..the file is TableSortSelectionListener.javaRe: Sorting a TableViewer's columns both ways
If I have not mistaken, these 2 methodsgetSortColumn(),
setSortDirection(int)
got introduced in 3.2
I am not sure about 3.2M1 and 3,2M2, but if you use 3.2M3 and above, you will not get any errors
Re: Sorting a TableViewer's columns both ways
ok.i'm using eclipse 3.1
Re: Sorting a TableViewer's columns both ways
1. how i update the swt 3.1 to 3.2 in eclipse 3.1?i have to update the eclipse too?
2. if i use the swt 3.2 instead of the 3.1 that i'm using now, should i have to do some changes im my code in order to support the 3.2?
thanks.
Marco
Re: Sorting a TableViewer's columns both ways
Hi ChristianCool stuff! I like your construction. I've got 2 comments on this:
1.) you can drastically improve the sorting speed by disabling the redraw in the tableViewer before sorting and reenabling it just afterwards:
2.) you use a model object specially for the table (Data with its properties). This might be usefull but could e a problem in an app that already has huge amount of data (like in a db-viewer). In this case it's better to use the original domain objects and interfaces/refletion to access the property of this domain-object thats displayed in the column.
Re: Sorting a TableViewer's columns both ways
Sorry, was not monitoring the threads for a while. To answer your questions:1. how i update the swt 3.1 to 3.2 in eclipse 3.1?
i have to update the eclipse too?
>> You need to download eclipse version 3.2.
2. if i use the swt 3.2 instead of the 3.1 that i'm using now, should i have to do some changes im my code in order to support the 3.2?
>> You may need to change your code in 3.2, depending on what you have used. If you have used the published API, you maynot need to changed, but few things are deprecated. I would advise you to create a project using the standard template, and then have your views/editors/etc added. This should make life simple.
Thanks
Sanjay
Re: Sorting a TableViewer's columns both ways
Hi,I also need to say sorry for the late response - Sanjay's mail was the reminder
> 1. how i update the swt 3.1 to 3.2 in eclipse 3.1?
> i have to update the eclipse too?
No, you don't, but you need to download it (or at least the current version of SWT), as Sanjay already pointed out.
If you run something within Eclipse as an SWT Application, Eclipse takes care of the SWT libraries needed in the classpath etc., but you can also manually add the to the classpath (and run as a normal Java Application).
Just grab the SWT libraries from a current Eclipse version (e.g. 3.2M5), copy them into a lib folder within your project and add them as libraries, and your project should compile fine.
To run your application, you also need to add the native libraries with Run.../Arguments/VM Arguments.
> 2. if i use the swt 3.2 instead of the 3.1 that i'm
> using now, should i have to do some changes im my
> code in order to support the 3.2?
I don't think so...
Bye,
Christian