Info | Location |
---|---|
0. SWT Tutorial | vogella.com |
1. SWT is made up of widgets, which are listed | SWT Widget Pics SWT Code Snippets Larger examples of SWT Widgets |
2. Google Window builder is a tool for building SWT UI. | Google Window Builder documentation |
3. Using SWT Layouts | Using Layouts |
4. Creating own SWT Widgets | Own SWT Widgets |
5. JFace framework provides higher level Widgets | vogella.com |
6. RCP Widgets like analogue clock | http://www.richclientgui.com |
7. Forms API like sections and expandables | https://eclipse.org/articles/Article-Forms/article.html |
What | Location |
---|---|
The Eclipse Nebula Project provides custom SWT widgets | Nebula |
The google code Opal Project provides many widget too | Opal |
JFace Widgets extens SWT, simplify the Widgets usage but do not hide the native SWT API (Git and CVS unfortunately offline :( ) | JFace Snippets |
What | Location |
---|---|
Window Builder is a WYSIWYG GUI Editor | Window Builder Tutorials |
Describtion | Link |
---|---|
The Snippet to insert Widgets into the table | http://www.java2s.com |
Configure Exlipse to import SWT-Widgets instead AWT-Widgets on STRG+SHIFT+O
by excluding the awt package from autoimports.
Display display = new Display(); Shell shell = new Shell(display); shell.open(); // Create and check the event loop while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose();
dispose()
. Only after that they will be garbage collected.
Shell calls dispose() on its widgets automagically
new Button(shell, SWT.PUSH); //pushbutton new Button(shell, SWT.CHECK); //checkbutton
Shell can be created with different parameters:
new Shell(); new Shell(Shell parent, SWT.NONE|SWT.APLICATION_MODAL...);
Windows created by shells can behave differently. E.g. depend on other windows - be always on top of others.
new Shell() | Ein eigenständiges Window mit der Repräsentation in der Toolbar. |
new Shell(Shell parent, …); | Gibt man einen Parent an - wird das neue Fenster zum Unterfenster des parents. ACHTUNG: Child-Shell is always “on top” of it's parent. Child Shell minimizes together with it's parent |
new Shell(Shell parent, SWT.NONE); | Erstellt ein Fenster ohne Deko, siehe Bild oben |
new Shell(Shell parent, SWT.MODAL_APPLICATION); | Erstellt ein Dialogfenster. Es ist immer on Top und lässt sich nicht schließen. |
The Table in SWT
The structure of a table is complicated:
Tabe TableItem TableItem TableItem TableColumn
Tables are not suitable to display different cell editors per row.
It is possible, but since the API is not type safe (operates on Objects) it is hard to handle all the special cases.
Editors sometimes operate on indexes and so the modify() methods will receive indexes instead of values.
Is dine via a PaintListener, which overrides the whole cell with the background
table.addListener(SWT.EraseItem, new Listener() { @Override public void handleEvent(Event event) { // use the bg color here to hide the vertical lines event.gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); event.gc.fillRectangle(event.getBounds()); } });
A table cell in SWT may contain
Data may be added to the table with differnt methods.
Setting the size of Table Items works only via a paint listener:
// resize the row height using a MeasureItem listener table.addListener(SWT.MeasureItem, new Listener() { public void handleEvent(Event event) { // height cannot be per row so simply set event.height = 100; event.width = 300; } });
Setting the size of Table Items works only via a paint listener:
table = new Table(this, SWT.BORDER | SWT.FULL_SELECTION); TableColumn col1 = new TableColumn(table, SWT.NONE); col1.setWidth(100); col1.setText("Column1"); TableColumn col2 = new TableColumn(table, SWT.RIGHT); col2.setWidth(100); col2.setText("Column2"); TableItem tableItem = new TableItem(table, SWT.NONE); tableItem.setText(0, "InColumn1"); tableItem.setText(1, "InColumn2");
The most simple way to add data to tables is to use TableItems.
Achtung: The TableItems may be mixed up with TableViewer api. If they are mixed up - the tableitems appear at the bottom of the entries from viewer models.
TreeItem trtmNewTreeitem_1 = new TreeItem(tree, SWT.NONE); trtmNewTreeitem_1.setText(new String[] {"from TableItem1", "from TableItem2"}); TreeItem trtmNewTreeitem = new TreeItem(tree, SWT.NONE); trtmNewTreeitem.setText(new String[] {"from TableItem3", "from TableItem4"});
Viewer Fascades may be used to set data via models. Read about JFace bindings for more.
Editors may be integrated in table cells.
import org.eclipse.swt.SWT; import org.eclipse.swt.custom.TreeEditor; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; public class EditorsInCells extends Shell { /** * Launch the application. * @param args */ public static void main(String args[]) { try { Display display = Display.getDefault(); EditorsInCells shell = new EditorsInCells(display); shell.open(); shell.layout(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } catch (Exception e) { e.printStackTrace(); } } public EditorsInCells(Display display) { super(display, SWT.SHELL_TRIM); setLayout(new FillLayout(SWT.HORIZONTAL)); Tree tree = new Tree(this, SWT.BORDER); TreeColumn trclmnNewColumn = new TreeColumn(tree, SWT.NONE); trclmnNewColumn.setWidth(200); trclmnNewColumn.setText("New Column"); TreeColumn trclmnNewColumn_1 = new TreeColumn(tree, SWT.NONE); trclmnNewColumn_1.setWidth(100); trclmnNewColumn_1.setText("New Column"); TreeItem trtmNewTreeitem = new TreeItem(tree, SWT.NONE); trtmNewTreeitem.setText(new String[] {"New TreeItem", "col2", "col3"}); Link l = new Link(tree, SWT.NONE); l.setText("<a>Link</a>"); /** * ACHTUNG : Windowsbuilder does not display the widget in cell correctly */ // TreeEditor IS THE IMPORTANT PART final TreeEditor treeEditor = new TreeEditor(tree); // make it fill the cell of set the width / height treeEditor.grabHorizontal=true; treeEditor.grabVertical=true; // assign the editor to the cell treeEditor.setEditor(l, trtmNewTreeitem, 1); } @Override protected void checkSubclass() { // Disable the check that prevents subclassing of SWT components } }
The hotkeys may be represented in platform's special way and in platform's language as following:
IKeyFormatter formatter = SWTKeySupport.getKeyFormatterForPlatform(); formatter.format(SWT.CTRL); // Ctrl
It is possible to display hotkeys inside of the SWT Menu.
To do so use the \t
String ctrl = SWTKeySupport.getKeyFormatterForPlatform().format(SWT.CTRL); MenuItem sortMenuItemNo = new MenuItem(sortMenuGroup, SWT.PUSH); sortMenuItemNo.setText("Search\t"+ctrl+"F");
More about Menus and mnemonics http://stackoverflow.com/questions/12219537/swt-issues-with-cascaded-menuitem-accelerators
For some reason acceleratos does not work on Windows7 More about Menus ans accelerators: http://book.javanb.com/swt-the-standard-widget-toolkit/ch02lev1sec4.html
This one shows hierarchical data. In the first column there is a tree, the other columns are expandable
Listen for expansion:
private Listener expansionListener2 = new Listener() { @Override public void handleEvent(Event event) { // IMPORTANT: the handler MUST be executed in a asyncExec Block - layout wont be done Display.getDefault().asyncExec(new Runnable() { @Override public void run() { CompositeCardContainer.this.getShell().layout(true, true); CompositeCardContainer.this.getShell().redraw(); } }); }; }; treeGroupReceipts.addListener(SWT.Expand, expansionListener2); treeGroupReceipts.addListener(SWT.Collapse, expansionListener2);
SWT.NO_BACKGROUND sets a single child to inherit the BG from the parent.
Composite composite_1 = new Composite(composite, SWT.NO_BACKGROUND);
SWT.INHERIT_FORCE, SWT.INHERIT_DEFAULT is set on the parent and forces all children to have parent's BG.
Composite parent = new Composite(this, SWT.NONE); parent.setBackgroundMode(SWT.INHERIT_FORCE); parent.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE)); Composite childWithBg = new Composite(parent, SWT.NONE); // parent will override this chailds BG, because of INHERIT_FORCE childWithBg1.setBackground(SWTResourceManager.getColor(SWT.COLOR_CYAN)); Composite childWithoutBg = new Composite(parent, SWT.NONE);
Children may override the BG even if the parent defined the INHERIT_FORCE mode.
So SWT.INHERIT_FORCE, SWT.INHERIT_DEFAULT seem to have the same effect - the parent BG is inherited as default.
Even if the next child in chain defines SWT.INHERIT_NONE the BG of parent is still inherited, but may be overridden by any parent.
The FillLayout, RowLayout, GridLayout, FormLayout are described here
RowLayout | simple alignement in a row, without expanding, without filling |
FormLayout | supports most flexible alignement, relative to borders or other widgets |
GridLayout | suports horizontal space fill by items |
The Layouts are controlled though the matching Composites. There are several methods inside of the composites, which control their layout.
Composite parent = new Composite(shell, SWT.DEFAULT); Composite child = new Composite(parent, SWT.DEFAULT); Button button = new Button(child, SWT.DEFAULT); button.setText("Hello"); parent.setLayout(new FillLayout()); // passes the measuring to the FillLayout. // FIllLayout measures the child, but does not modify it's size. parent.pack(); child.getSize(); // 0,0 since the child was not layed out yet and pack does no changes to the size
Can make a row “GONE” by setting an Element to exclude=true.
This Element then will disapear and will not take any space anymore.
Achtung:
A GridLayout is filled row by row, by adding widgets to rows in order: add widgets to row1 until row1 is full, gow on with row2, row3…
excluding a column in multicolumn-layout makes a cell from the next row jump one row higher.
Here the label with y is excluded. Warning jumps 1 row higher.
Every Composite:
//redraw whe whole Composite hierarchy immediately: composite.getShell().layout(true, true); composite.getShell().redraw(); composite.getShell().update();
Howt create own widgets is described here
To capture Keypresses add a Filter to the Display. The possible Color Codes are stored in the SWT class
// SWT.CR Enter Button // SWT.KEYPAD_CR Enter Button near numpad final Listener enterListener = new Listener() { @Override public void handleEvent(Event event) { System.out.println("key down."); if (event.keyCode == SWT.CR || event.keyCode == SWT.KEYPAD_CR) { pageManagerService.reloadActivePart(); } } }; composite.getDisplay().addFilter(SWT.Traverse, enterListener );
Die Widgets werden entsorg, wenn deren Parent entsorgt wurde.
Die Widgets sind im Zustand “Dsiposed” wenn sie entsorgt wurden.
Sehr oft bleiben Listener übrig, welche versuchen die Widgets im Disposed Zustand zu nutzen. Das provoziert eine SWTException. Da ein Widget jederzeit “Disposed” werden kann - sollte dieser Fehler innerhalb der Listener mit try-catch abgefangen werden.
Dieser Exceptin ist ein gutes merkmal, um einen Listenr zu deregestrieren.
final Listener enterListener = new Listener() { @Override public void handleEvent(Event event) { try { System.out.println("key down."); } catch (SWTException e) { display.removeFilter(SWT.KeyDown, this); } } };
There are animations available in SWT.
Update-Site: | http://download.eclipse.org/technology/nebula/snapshot/ |
Plugin: | org.eclipse.nebula.widgets.gallery org.eclipse.nebula.widgets.gallery.example org.eclipse.nebula.widgets.gallery.example.source org.eclipse.nebula.widgets.gallery.source org.eclipse.nebula.widgets.pshelf |
Package: | org.eclipse.nebula.animation |
The mouse position is retrieved relative to the Shell (Window) There are some Fallpits:
private Point getDisplayPos(Control control) { /* * If the control has no parent - the coordinates are already relative to the Display! * converting them to display would mean, that the Display realative coords will be treated * as composite local coords, which is wrong! * * The shell coordinates are relative to the display too! **/ if (control instanceof Shell || control.getParent() == null) { Point r = ((Shell) control).getLocation(); return new Point(r.x, r.y); /* * If there control has a parent and is not a shell - the coordinates are relative to * the parent! */ } else { return control.getParent().toDisplay(control.getLocation()); } }
/* The size and position of the clientarea is indeed always returned relative to the parent. * So toDisplay() can be safely used here. */ Rectangle clientArea = parent.getClientArea(); Point pos = parent.toDisplay(clientArea.x, clientArea.y);
Eclipse JFace is based upon the user interface toolkit SWT. JFace provides classes and frameworks which simplify common SWT use cases. JFace does not hide the SWT API; therefore SWT knowledge is still required.
The JFace Snippets are listed here.
All the bindings are executed within a context called Realm (Kingdom) as stated here: https://wiki.eclipse.org/JFace_Data_Binding/Realm
So the realm must have been initialized. This is done by eclipse automaticall or may be doneas following, when not using the Eclipse platform:
public static void main(String[] args) { Display display = new Display(); Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() { @Override public void run() { // code that uses bindings } }); }
TopLevelContainers | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
TopLevel classes: The top-level JFace containers are Window, ApplicationWindow and Tooltip. They are described here. |
||||||||||||
More concrete classes:
|
||||||||||||
The concrete classes: The containers below are lister here: http://sureshkrishna.wordpress.com/ |
All viewers can:
Viewer | Describtion | Pic |
---|---|---|
TableViewer | Can display Data in a table. Is capable to sort columns | ![]() |
TreeViewer | Can display hierarchical data. Is capable to have columns. Some columns can display hierarchical content, some can display non hierarchical content. | ![]() |
JFace Viewers use the Model-View-Controller metapher.
MVC | Class | Explanation |
---|---|---|
View | Viewer The Viewer list is available here , or inside of the Window Builder Pro | The Viewers are instantiated like normal Composites |
Model | Input Viewer#setContentProvider() | The Model is an Objectstrucure, which you whant to display inside of your Viewer. E.g. an Array of Persons. |
Controler | ContentProvider Viewer#setContentProvider() | The ContenProvider is the class, which will understand the Model and build an Inheritance structure. |
Controler2 | LabelProvider Viewer#setLabelProvider() | The ContenProvider is the class, which will understand the Model to set Labels for each Cell. |
ContentProvider is supported by the IAdapter Pattern in Eclipse RCP.
PatternConcept | Explanation |
---|---|
ContentProvider | is a Controller for a Viewer. A concrete inherent of IContentProvider will be used by the viewer to understand Objects, which should be displayed in the viewer. ContentProvider converts the given Model objects into a Generic Interface IWorkbenchAdapter using a IAdapterFactory and uses this Generic Interface to retrieve strucutral Data (Parents, Children). Example: TODO |
LabelProvider | The same as ContentProvider, but retrieves Labels instead of structural data. Sometimes it may be useful to implement LabelProvider as inner classes, because you only can deside which label should be displayed in a column, depending on the sematic of this column. LabelProvider can be added to:
|
IAdapterFactory | Inherent of the IAdapterFactory can produce Adapters for every class, which will be understood by ContentProviders and LabelProviders. Factory is given a Class, and it is asked for an Adapter for this class. Factory returns an Adapter, depending on the given class, so that every Object can be handled through the same interface. TODO |
Example of instantiating a Viewer
// 1. create Viewer viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); final Table table = viewer.getTable(); table.setHeaderVisible(true); table.setLinesVisible(true); // 2. create columns, before setting the input createColumns(parent); // 3. set content provider which understands IWorkbenchAdapter. Happens after creating content. Inside there will be a request to a Platfortm, to give you a IWorkbenchAdapter for the given Object. The iFacotry is retrieved through a Singleton viewer.setContentProvider(new ITreeContentProvider()); // ArrayContentProvider works for // 4. Set a LabelProvider to it, which understands IWorkbenchAdapter. Ask an IFactory to give you a IWorkbenchAdapter //First way to add a LableProvider. The second is adding it to the viewer's columns. When viewer has a LabelProvider - column's LabelProviders are not triggered. viewer.setLabelProvider(new ILabelProvider()); // 5. Set some Input to the Viewer. At the end there should be a factory, which can turn this Input into a IWorkbenchAdapter model = getBundles(); viewer.setInput(model); // 6. sort, after input comparator.setColumn(1); viewer.setComparator(comparator); viewer.getTable().setSortColumn(sortByColumn); viewer.refresh(); //7. Now implement a Factory to convert a Person into a IWorkbenchAdapter and register it through a Singleton: Platform.getAdapterManager().registerAdapters(new PersonFactory(), Person.class); private void createColumns(final Composite parent) { String[] titles = { "Module", "Widget" }; int[] bounds = { 200, 100 }; TreeViewerColumn col; col = createViewerColumn(titles[0], bounds[0], 0); //Second way to add a LableProvider. The first is adding it to the viewer itself. When viewer has a LabelProvider - column's LabelProviders are not triggered. col.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { return ((Module) element).getId(); } @Override public Image getImage(Object element) { return (Module) element).getImage();; } }); col = createViewerColumn(titles[1], bounds[1], 1); //Second way to add a LableProvider. The first is adding it to the viewer itself. When viewer has a LabelProvider - column's LabelProviders are not triggered. col.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { return ((Module) element).getName(); } }); }
Example of creating a ContentProvider
/** * Can use {@link IWorkbenchAdapter} instances, e.g. to provide data for a @link {@link TreeViewer}. */ public class TreeContentProvider4IWorkbenchAdapter implements ITreeContentProvider { private IWorkbenchAdapter model; @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { model = getAdapter(newInput); } @Override public Object[] getElements(Object inputElement) { return model.getChildren(inputElement); } @Override public Object[] getChildren(Object parentElement) { IWorkbenchAdapter adapter = getAdapter(parentElement); if (adapter != null) { return adapter.getChildren(parentElement); } return new Object[0]; } @Override public Object getParent(Object element) { return model.getParent(element); } @Override public boolean hasChildren(Object element) { return getChildren(element).length > 0; } /** * Returns the implementation of IWorkbenchAdapter for the given * object. Returns null if the adapter is not defined or the * object is not adaptable. * <p> * </p> * * @param element * the element * @return the corresponding workbench adapter object */ protected IWorkbenchAdapter getAdapter(Object element) { if (element == null) { return null; } IWorkbenchAdapter adapter = (IWorkbenchAdapter) Platform.getAdapterManager().getAdapter(element, IWorkbenchAdapter.class); return adapter; } }
Example of creating a LabelProvider
/** * Can use {@link IAdapter} instances, e.g. to provide labels for a @link {@link TreeViewer}. * If this Label is used - the Label and Image will be provided only for the first column. * Use {@link TreeContentProvider4IWorkbenchAdapter} to provide separate labels for all columns. */ public class LabelProvider4IWorkbenchAdapter extends LabelProvider { @Override public Image getImage(Object element) { Object adapterObject = Platform.getAdapterManager().getAdapter(element, IWorkbenchAdapter.class); IWorkbenchAdapter adapter = (IWorkbenchAdapter) adapterObject; return adapter.getImageDescriptor(element).createImage(); } @Override public String getText(Object element) { Object adapterObject = Platform.getAdapterManager().getAdapter(element, IWorkbenchAdapter.class); IWorkbenchAdapter adapter = (IWorkbenchAdapter) adapterObject; return adapter.getLabel(element); } }
Example of creating an AdapterFactory
package de.ivu.fare.rcp.gui.parts; import org.eclipse.core.runtime.IAdapterFactory; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.ui.model.IWorkbenchAdapter; import de.ivu.fare.rcp.spi.Module; import de.ivu.fare.rcp.spi.Submodule; import de.ivu.fare.rcp.util.ResourceUtil; /** * A factory, which will be registered to the {@link Platform}, so that JFace Viewer's * ContentProviders are able to convert Objects to an Interface {@link IWorkbenchAdapter}, which * they can handle. * */ public class FactoryModule2IWorkbenchAdapter implements IAdapterFactory { private static final String MODULE_TREE_NODE_ICON_PATH = "images/icons/modul.png"; private IWorkbenchAdapter moduleAdapter = new IWorkbenchAdapter() { @Override public Object getParent(Object o) { return null; } @Override public String getLabel(Object o) { Module m = (Module) o; return m.getName(); } @Override public ImageDescriptor getImageDescriptor(Object o) { return ResourceUtil.getImageDescriptor(MODULE_TREE_NODE_ICON_PATH); } @Override public Object[] getChildren(Object o) { Module m = (Module) o; return m.getSubmodules().toArray(); } }; private IWorkbenchAdapter submoduleAdapter = new IWorkbenchAdapter() { @Override public Object getParent(Object o) { Submodule m = (Submodule) o; return m.getParentModule(); } @Override public String getLabel(Object o) { Submodule m = (Submodule) o; return m.getName(); } @Override public ImageDescriptor getImageDescriptor(Object o) { return ResourceUtil.getImageDescriptor(MODULE_TREE_NODE_ICON_PATH); } @Override public Object[] getChildren(Object o) { Submodule m = (Submodule) o; return m.getSubmodules().toArray(); } }; @Override public IWorkbenchAdapter getAdapter(Object adaptableObject, Class adapterType) { if (adapterType == IWorkbenchAdapter.class && adaptableObject instanceof Module) { return this.moduleAdapter; } else if (adapterType == IWorkbenchAdapter.class && adaptableObject instanceof Submodule) { return this.submoduleAdapter; } return null; } @Override public Class[] getAdapterList() { return new Class[] { IWorkbenchAdapter.class }; } }
The ContentProvider will get a Person.class,
ask the IFactory for an Adapter and retrieve a concrete IWorkbenchAdapter,
use the IWorkbenchAdapter to display retireve Parents and Children.
The LabelProvider will do the same to retrieve Labels.
If we want to pass some other Objects to the Viewer - just implement a new Factory and reegister it, so that it can convert the new Object to a IWorkbenchAdapter - it allready can be handled by the ContentProvider.
The Model is a list of restauraunt tables. A restauraunt table may have a list of neighbours
package de.example.jface.viewer.mvc; import java.util.ArrayList; import java.util.List; import de.e4.annotations.AbstractBindableModel; public class Model extends AbstractBindableModel { public List<Restauranttable> tables = new ArrayList<Restauranttable>(); { tables.add(new Restauranttable(1, true)); tables.add(new Restauranttable(2, true)); tables.add(new Restauranttable(3, true)); tables.add(new Restauranttable(4, false)); tables.add(new Restauranttable(5, false)); tables.get(1).setNeighbour(tables.get(2)); tables.get(3).setNeighbour(tables.get(4)); } public List<Restauranttable> getTables() { return tables; } public void setTables(List<Restauranttable> tables) { firePropertyChange("tables", this.tables, this.tables = tables); } public static class Restauranttable{ int number; boolean booked; List<Restauranttable> neighbours = new ArrayList<Model.Restauranttable>(); Restauranttable parent; @Override public String toString() { return "Table "+number; } public Restauranttable(int num, boolean booked) { this.booked = booked; this.number = num; } public void setNeighbour(Restauranttable... table){ for(Restauranttable t : table){ this.neighbours.add(t); t.parent = this; } } public List<Restauranttable> getNeighbours() { return neighbours; } public Restauranttable getParent() { return parent; } } }
The TableViewer displays the list of restauraunt tables in two columns:
Table number | booked |
package de.example.jface.viewer.mvc; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Table; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.jface.viewers.TreeViewerColumn; import de.example.jface.viewer.mvc.Model.Restauranttable; public class MainShell extends Shell { /** * Launch the application. * @param args */ public static void main(String args[]) { try { Display display = Display.getDefault(); MainShell shell = new MainShell(display); shell.open(); shell.layout(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } catch (Exception e) { e.printStackTrace(); } } /** * Create the shell. * @param display */ public MainShell(Display display) { super(display, SWT.SHELL_TRIM); setLayout(new FillLayout(SWT.HORIZONTAL)); TreeViewer treeViewer = new TreeViewer(this, SWT.BORDER); Tree tree = treeViewer.getTree(); TreeViewerColumn treeViewerColumn1 = new TreeViewerColumn(treeViewer, SWT.NONE); TreeColumn treeColumn1 = treeViewerColumn1.getColumn(); treeColumn1.setWidth(100); treeColumn1.setText("New Column"); TreeViewerColumn treeViewerColumn2 = new TreeViewerColumn(treeViewer, SWT.NONE); TreeColumn treeColumn2 = treeViewerColumn2.getColumn(); treeColumn2.setWidth(100); treeColumn2.setText("New Column"); createContents(); setupMvc(treeViewer, treeViewerColumn1, treeViewerColumn2); } public void setupMvc(TreeViewer treeViewer, TreeViewerColumn treeViewerColumn1, TreeViewerColumn treeViewerColumn2){ // Model Model model = new Model(); // tell the viewer how to read the model treeViewer.setContentProvider(new ITreeContentProvider() { @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // ? // this method would be used, if the model would be observable. // here we would register to track changes on model } @Override public void dispose() { } @Override public boolean hasChildren(Object element) { Restauranttable r = (Restauranttable) element; return r.getNeighbours() != null && !r.getNeighbours().isEmpty(); } @Override public Object getParent(Object element) { // single model element here Restauranttable r = (Restauranttable) element; return r.getParent(); } @Override public Object[] getElements(Object inputElement) { // retrieve the element from the Model (input = Model) Model model = (Model) inputElement; return model.tables.toArray(); } @Override public Object[] getChildren(Object parentElement) { Restauranttable r = (Restauranttable) parentElement; return r.neighbours.toArray(); } }); // setup Label provider on columns. FOr each column an own Label provider // col 1 treeViewerColumn1.setLabelProvider(new CellLabelProvider() { @Override public void update(ViewerCell cell) { // retrieve the element in the cell, Must be the element in my model Restauranttable table = (Restauranttable) cell.getElement(); // set the text in the cell cell.setText(table.toString()); // cell.setImage(image) // cell.setForeground(color) // cell.setBackground(background) } }); // col 2 treeViewerColumn2.setLabelProvider(new CellLabelProvider() { @Override public void update(ViewerCell cell) { // retrieve the element in the cell, Must be the element in my model Restauranttable table = (Restauranttable) cell.getElement(); // set the text in the cell cell.setText(""+table.booked); // cell.setImage(image) } }); // add the data to the viewer treeViewer.setInput(model); } /** * Create contents of the shell. */ protected void createContents() { setText("SWT Application"); setSize(450, 300); } @Override protected void checkSubclass() { // Disable the check that prevents subclassing of SWT components } }
ACHTUNG:
Button buttonRadio = new Button(parent, SWT.Radio); buttonRadion.setSelection(true); buttonRadio.notifyListeners(SWT.Selection, new Event());
A good tutorial: http://www.vogella.com/articles/EclipseDataBinding/article.html Use WindowBuilder to establish bindings.
The Widgets are bound to the model:
// A Model may be any POJO public class MyPojoModel{ private String label = "label"; private boolean isEnabled = true; public boolean isEnabled() { return isEnabled; } public void setEnabled(boolean isEnabled) { this.isEnabled = isEnabled; } public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } } public static void main{ ... protected DataBindingContext initDataBindings() { DataBindingContext bindingContext = new DataBindingContext(); // JFace bindings can observe properties in POJOs. Here obseving property "enabled" in Object model // Factory PojoProperties observes Pojos IObservableValue enabledModelObserveValue = PojoProperties.value("enabled").observe(model); // on change different filters and converters may be applied. They are combined to a stragegy UpdateValueStrategy strategy = new UpdateValueStrategy(); strategy.setConverter(new MyBoolInverterConverter()); // a Factory WidgetProperties observers widgets IObservableValue observeEnabledBtnNewButton = WidgetProperties.enabled().observe(button); // bind POJO and Widget together bindingContext.bindValue(observeEnabledBtnNewButton, enabledModelObserveValue, null, strategy); return bindingContext; } // when changing the Widgets - changes are directly propagated to the Model // when changing the Model - the changes are NOT directly propagated to the bound Widgets. call binding to do so SelectionAdapter sa = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { model.setEnabled(!model.isEnabled()); //model changed. propagate changes. initDataBindings(); } }; button.addSelectionListener(sa);
// Properties of Person "name" and "firstName" IBeanValueProperty propName = BeanProperties.value(Person.class, "name"); IBeanValueProperty propFirstname = BeanProperties.value( Person.class, "firstName"); // IObservable Set of Persons WritableSet writableSet = new WritableSet(this.viewModel.getPeople(), Person.class); /* Splits the Beans in two maps, by properties * Set of Beans Person: Dave Orme Gili Mendel Joe Winchester Boris Bokowski Brad Reynolds Matthew Hall into [ Winchester, Mendel, Hall, Bokowski, Reynolds, Orme ] and [ Joe, Gili, Matthew, Boris, Brad, Dave] */ IObservableMap[] result = Properties.observeEach(writableSet, new IBeanValueProperty[] { propName, propFirstname }); // make the column understand it's data source by setting a Label provider columnName.setLabelProvider(new ObservableMapCellLabelProvider( result[0])); columnFirstName.setLabelProvider(new ObservableMapCellLabelProvider(result[1])); // feed the list with Persons to the viewer as datasource peopleViewer.setInput(new WritableList(viewModel.getPeople(), Person.class));
IObservableList | may be observed by the JFace bindings IObservableList sourceObservableList = new WritableList(); |
bindingContext | Main class which stores all the bindings. bindingContext.bindValue( SWTObservables.observeText(selectedCommitterName), BeansObservables.observeDetailValue(selection, "name", String.class)); |
SWTObservables | creates a bindable ISWTObservableValue from widget properties SWTObservables.observeTooltipText(label) observeDelayedValue(int, ISWTObservableValue) observeEnabled(Widget) observeEnabled(Control) observeVisible(Control) observeTooltipText(Widget) observeTooltipText(Control) observeSelection(Widget) observeSelection(Control) observeMin(Control) observeMax(Control) observeText(Control, int[]) observeText(Control, int) observeText(Widget) observeText(Control) observeMessage(Widget) observeImage(Widget) observeItems(Control) observeSingleSelectionIndex(Control) observeForeground(Control) observeBackground(Control) observeFont(Control) observeSize(Control) observeLocation(Control) observeFocus(Control) observeBounds(Control) observeEditable(Control) |
WidgetProperties | Used to observe Widget's properties. WidgetProperties.items().observe(combo); background() bounds() editable() enabled() focused() font() foreground() image() items() location() maximum() message() minimum() selection() singleSelectionIndex() size() text() text(int) text(int[]) tooltipText() visible() |
BeansObservables | Factory to observe Beans' properties observeValue(Object, String) observeValue(Realm, Object, String) observeMap(IObservableSet, String) observeMap(IObservableSet, Class, String) observeMap(Realm, Object, String) observeMap(Realm, Object, String, Class, Class) observeMap(Object, String) observeMap(Object, String, Class, Class) observeMaps(IObservableSet, String[]) observeMaps(IObservableSet, Class, String[]) observeList(Realm, Object, String) observeList(Object, String) observeList(Realm, Object, String, Class) observeList(Object, String, Class) observeSet(Realm, Object, String) observeSet(Object, String) valueFactory(Realm, String) valueFactory(String) listFactory(Realm, String, Class) listFactory(String, Class) setFactory(Realm, String) setFactory(String) observeDetailValue(Realm, IObservableValue, String, Class) observeDetailValue(IObservableValue, String, Class) observeDetailValue(Realm, IObservableValue, Class, String, Class) observeDetailValue(IObservableValue, Class, String, Class) observeDetailList(Realm, IObservableValue, String, Class) observeDetailList(IObservableValue, String, Class) observeDetailSet(Realm, IObservableValue, String, Class) observeDetailSet(IObservableValue, String, Class) observeDetailMap(Realm, IObservableValue, String) observeDetailMap(IObservableValue, String) observeSet(Realm, Object, String, Class) observeSet(Object, String, Class) setFactory(Realm, String, Class) setFactory(String, Class) setToMapFactory(Class, String) mapPropertyFactory(Realm, String) mapPropertyFactory(String) |
BeanProperties | ceates bindable IBeanValueProperty IBeanValueProperty propName = BeanProperties.value(Person.class, "name"); value(String) value(String, Class) value(Class, String) value(Class, String, Class) values(Class, String[]) values(String[]) set(String) set(String, Class) set(Class, String) set(Class, String, Class) list(String) list(String, Class) list(Class, String) list(Class, String, Class) map(String) map(String, Class, Class) map(Class, String) map(Class, String, Class, Class) |
It is possible to decorate the Controls like Forms or Labels using SWT.
Here is an example with FieldDecorationRegistry.DEC_WARNING
ControlDecoration controlDecoration = new ControlDecoration(lblNewLabel, SWT.LEFT | SWT.TOP); controlDecoration.setDescriptionText("HoverText"); FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_WARNING); controlDecoration.setImage(fieldDecoration.getImage()); controlDecoration.show();
TO e.g. Skip a Page depending on model:
Override the IWizard.getNextPage(), IWizard.getPreviousPage(),
@Override public IWizardPage getNextPage(IWizardPage page) { IWizardPage nextPage = super.getNextPage(page); if (modelUsercardWizard.isCreatingAnonymousCustomerCard() && nextPage == wizardPageUsercardcreationFoto) { return nextPage.getNextPage(); } return nextPage; } @Override public IWizardPage getPreviousPage(IWizardPage page) { IWizardPage prevPage = super.getPreviousPage(page); if (modelUsercardWizard.isCreatingAnonymousCustomerCard() && prevPage == wizardPageUsercardcreationFoto) { return prevPage.getPreviousPage(); } return prevPage; }
Update-Site: http://download.eclipse.org/eclipse/updates/4.5 |
Feature-Name: Eclipse-Platform x.y |
Plugin:
|
Packages:
|
The Forms API is described here https://eclipse.org/articles/Article-Forms/article.html
It brings some layouts and expandable secitons and forms. Indeed it implements the forms, which are used within eclipse to display plugins, etc.
Rules:
int delay = 5000; // delay for 5 sec. int period = 1000; // repeat every sec. Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { public void run() { // Task here ... } }, delay, period);
Display.getDefault().asyncExec(new Runnable() { public void run() { someSwtLabel.setText("Complete!"); } });
try{ composite.width ++; //layout of the composite doesn't work // composite.layout(true, true); //layout of parent works composite.getParent().layout(true, true); composite.redraw(); //marks the composite's screen are as invalidates, which will force a redraw on next paint request composite.update(); //tells the application to do all outstanding paint requests immediately }catch(org.eclipse.swt.SWTException e){ // Widget is allready disposed. Probably the application was closed. timer.cancel(); }
The code can be executed on UI thread as following:
Display.getDefault().asyncExec(new Runnable() { public void run() { someSwtLabel.setText("Complete!"); } });
The tab order of the controls on a form determines the sequence in which the focus will change when the user strikes the tab key. You can specify the tab order of controls via the setTabList() method of a Composite.
setTabList()
color_bgcolor = getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); color_foreground = getDisplay().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND); color_border = getDisplay().getSystemColor(SWT.COLOR_WIDGET_BORDER); color_dark_shadow = getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW); color_highlight_shadow = getDisplay().getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW); color_light_shadow = getDisplay().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW); color_normal_shadow = getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); color_text = color_dark_shadow; //constants final int shadow_margin_left = WIDTH-10; //drawing will happen here this.addPaintListener(new PaintListener() { public void paintControl(PaintEvent e) { //draw in this area. Must be inside of the Paint Listener, because the clientarea changes its size Rectangle clientArea = canvas.getClientArea(); final int text_margin_left = shadow_margin_left-textsize.y; final int text_margin_top = (clientArea.height)/2; //Background //0. default background e.gc.setBackground(color_light_shadow); e.gc.fillRectangle(0,0,clientArea.width, clientArea.height); //1. draw a gradient shadow e.gc.setForeground(color_light_shadow); e.gc.setBackground(color_dark_shadow); e.gc.fillGradientRectangle(shadow_margin_left, 1, clientArea.width, clientArea.height-1, false); //2. draw a light frame if(accordion.styleItemBorder){ e.gc.setForeground(color_highlight_shadow); e.gc.drawRectangle(1, 1, clientArea.width, clientArea.height); } //3. draw a dark frame e.gc.setForeground(color_normal_shadow); e.gc.drawRectangle(0, 0, clientArea.width, clientArea.height-1); //Text //rotate the screen Transform tr = new Transform(display); tr.rotate(-90); e.gc.setTransform(tr); e.gc.setFont(display.getSystemFont()); e.gc.setForeground(color_text); e.gc.drawString(text, -text_margin_top, text_margin_left, true); //rotate back tr.identity(); e.gc.setTransform(tr); //FOR DEBUGGING if(HAccordion.DEBUG){ //DEMO colors e.gc.setBackground(color_bgcolor); e.gc.fillRectangle(0, 10, 10, 10); e.gc.setBackground(color_dark_shadow); e.gc.fillRectangle(10, 10, 10, 10); e.gc.setBackground(color_foreground); e.gc.fillRectangle(10, 20, 10, 10); e.gc.setBackground(color_border); e.gc.fillRectangle(10, 30, 10, 10); e.gc.setBackground(color_dark_shadow); e.gc.fillRectangle(10, 40, 10, 10); e.gc.setBackground(color_highlight_shadow); e.gc.fillRectangle(10, 50, 10, 10); e.gc.setBackground(color_light_shadow); e.gc.fillRectangle(10, 60, 10, 10); e.gc.setBackground(color_normal_shadow); e.gc.fillRectangle(10, 70, 10, 10); //write down the index in the top left corner int index = accordionItem.getParent().getItemsIterator().getIndexOf(accordionItem); e.gc.drawText(String.valueOf(index), 1, 1); //random color int red = (int)(Math.random()*256); int green = (int)(Math.random()*256); int blue = (int)(Math.random()*256); Color random = new Color(getDisplay(),red,green,blue); //use colors random color for filling e.gc.setBackground(random); e.gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_BLACK)); //draw e.gc.fillOval(0,0,clientArea.width,clientArea.height); e.gc.drawRectangle(0, 0, clientArea.width-1, clientArea.height-1); } } }); // draws an image. White is told to be the transparent color class FactoryImages{ private static final Color NUM_DECORATOR_transparentColor = SWTResourceManager.getColor(SWT.COLOR_WHITE); private static final Color NUM_DECORATOR_textColor = SWTResourceManager.getColor(SWT.COLOR_BLACK); private static Image createTransparentImage(Display d, int width, int height) { // create a cursor with a transparent image // allows the red, green and blue color masks to be specified. PaletteData palette = new PaletteData(0xFF, 0xFF00, 0xFF0000); ImageData sourceData = new ImageData(width, height, 24, palette); // tell the platform which color should be made transparent int transparentPixel = sourceData.palette.getPixel(NUM_DECORATOR_transparentColor.getRGB()); sourceData.transparentPixel = transparentPixel; Image image = new Image(d, sourceData); GC gc = new GC(image); // bg gc.setBackground(NUM_DECORATOR_transparentColor); gc.fillRectangle(0, 0, width, height); //text gc.setBackground(NUM_DECORATOR_textColor); gc.drawText("Test", 0, 0, true); gc.dispose(); return image; } }
Generating a colored rectangle in memory
lblFoto.setImage( createImage(new RGB(100, 100, 100)) ); } // generate the image public static Image createImage(RGB... rgb) { PaletteData paletteData = new PaletteData(rgb); ImageData imageData = new ImageData(14, 14, 1, paletteData); for (int x = 4; x < 8; x++) { for (int y = 4; y < 8; y++) { imageData.setPixel(x, y, 1); } } return new Image(Display.getCurrent(), imageData); }
When implementing custom SWT Widgets think about:
An RCP Applicaiton may be switched to the RTL View by using the Eclipse Run Parameter
-dir rtl
How do concrete layouts behave when switched to the Right To Left view?
The WindowBuilder should be used to create composites in SWT. It has a preview function which is quite fragile.
Following should be considered when creating widgets with Windowbuilder:
class LayoutA{ public Composite column1; public LayoutA(Composite parent) { // OK - create in constructor this.column1 = parent; } } class LayoutB{ public Composite column1; public layout(Composite parent) { // WRONG - you Will not be able to use LayoutB.column1 in WindowBuilder preview this.column1 = parent; } }