Do get some benefits of the Java2D
support for Draw2d and GEF you must have installed the Java2D for SWT
2.0 framework.
Because the new classes are delivered as fragments of the Draw2d and
GEF plugins, you will not need to modifiy or update your project
classpath: once installed, the new classes will be automatically added
to the plugin classpath.
Because the new classes are defined in
the same package as their original counterpart it is easy to guess
which class to use.
The key change in your code is to create a J2DLightweightSystem
instead of the regular LightweightSystem.
Let see at an example:
| Regular Draw2d example | Java2D enhanced |
|---|---|
| public class Demo { public static void main(String args[]){ Shell shell = new Shell(); shell.open(); shell.setText("Draw2d"); LightweightSystem lws = new J2DLightweightSystem(shell); IFigure panel = new Figure(); panel.setLayoutManager(new FlowLayout()); lws.setContents(panel); Clickable button = new Button("Click me"); Clickable checkbox = new CheckBox("Check box"); Shape ellipse = new Ellipse(); ellipse.setBackgroundColor(ColorConstants.yellow); Shape rectangle = new RectangleFigure(); rectangle.setBackgroundColor(ColorConstants.lightBlue); panel.add(button); panel.add(checkbox); panel.add(ellipse); panel.add(rectangle); Display display = Display.getDefault(); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); } } } |
public class Demo { public static void main(String args[]){ Shell shell = new Shell(); shell.open(); shell.setText("Draw2d with Java2D"); LightweightSystem lws = new J2DLightweightSystem(shell); IFigure panel = new Figure(); panel.setLayoutManager(new FlowLayout()); lws.setContents(panel); Clickable button = new Button("Click me"); Clickable checkbox = new CheckBox("Check box"); Shape ellipse = new Ellipse(); ellipse.setBackgroundColor(ColorConstants.yellow); Shape rectangle = new RectangleFigure(); rectangle.setBackgroundColor(ColorConstants.lightBlue); panel.add(button); panel.add(checkbox); panel.add(ellipse); panel.add(rectangle); Display display = Display.getDefault(); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); } } } |
That's all!
You can even mix regular and enhanced lightweight systems if they are
not attached to the same canvas.
For GEF, a little bit more work have to be done, because the LightweightSystem if often created internally to some classes.
More, to efficiently manage the new scaling capabilities, the intermediate ScalableGraphics object created by some classes (like the scalable layers) have to be short-circuited.
The GEF support comes with the essential framework classes already converted to Java2D. The following list summarizes the available classes: as their name if the regular GEF class name prefixed with J2D, their meaning is obvious:
Converting an existing GEF application, or writing a new one is almost straightforward:
For example, to convert the Logic example to support Java2D, you will have to change the following lines of code:
| Original LogicEditor class |
New code |
|---|---|
| public class
LogicEditor extends GraphicalEditorWithPalette { ... protected void configureGraphicalViewer() { super.configureGraphicalViewer(); ScrollingGraphicalViewer viewer = (ScrollingGraphicalViewer)getGraphicalViewer(); ScalableFreeformRootEditPart root = new ScalableFreeformRootEditPart(); ... |
public class
LogicEditor extends J2DGraphicalEditorWithPalette { ... protected void configureGraphicalViewer() { super.configureGraphicalViewer(); ScrollingGraphicalViewer viewer = (ScrollingGraphicalViewer)getGraphicalViewer(); ScalableFreeformRootEditPart root = new J2DScalableFreeformRootEditPart(); |
The LogicEditor will now render through the Java2D engine, while the SWT engine can be reactivated through the user prefrences.
If you want to write applications that can support both rendering engines, you have to use one of the key top level classes instead of their regular Draw2d or GEF one.
One area where you may have to write some more intrusive code is when you plan to support scaling for both engines.
For example, let us look at the org.eclipse.draw2d.examples.zoom example available from the GEF CVS website.
The main class org.eclipse.draw2d.examples.zoom.ZoomExample is modified as explained above:public static void main(String args[]){
Display d = new Display();
final Shell shell = new Shell(d);
shell.setSize(800, 800);
LightweightSystem lws = new J2DLightweightSystem(shell);
...
But this is not sufficinet: if you run this application you will have a blank screen and nothing will appear if you change the zoom level!
The reason is that the zoom is actually performed inside another the class ZoomContainer which is not aware of the new rendering method.
Following the Draw2d recommandations, scaling is supported inside this figure that acts as the root figure of the application and manages the zoom related computations. The rendering process is delegated to a ScaledGraphics object, and this is the piece of code we are concerned with:
| Original ZoomContainer code |
New code |
|---|---|
| protected void
paintClientArea(Graphics graphics) { if (getChildren().isEmpty()) return; boolean optimizeClip = getBorder() == null || getBorder().isOpaque(); ScaledGraphics g = new ScaledGraphics(graphics); if (!optimizeClip) g.clipRect(getBounds().getCropped(getInsets())); g.translate(getBounds().x + getInsets().left, getBounds().y + getInsets().top); g.scale(zoom); g.pushState(); paintChildren(g); g.popState(); g.dispose(); graphics.restoreState(); } |
protected void
paintClientArea(Graphics graphics) { if (getChildren().isEmpty()) return; boolean optimizeClip = getBorder() == null || getBorder().isOpaque(); // ScaledGraphics g = new ScaledGraphics(graphics); if (!optimizeClip) g.clipRect(getBounds().getCropped(getInsets())); g.translate(getBounds().x + getInsets().left, getBounds().y + getInsets().top); graphics.scale(zoom); graphics.pushState(); paintChildren(g); graphics.popState(); // g.dispose(); // graphics.restoreState(); } |
Because the scaled rendering is the very job of Java2D, the intermediate ScaledGraphics is no longer needed, thus simplifying the painting code.
If you also plan to support the regular Draw2d engine, all the necessary work is already done for the classes delivered with the new framework, but you have to test for it inside your code. For example the above new code will become:
protected void paintClientArea(Graphics graphics) {
// Preconditions are always verified first!
if (getChildren().isEmpty()) return;
boolean optimizeClip = getBorder() == null || getBorder().isOpaque();
// Creates a new ScaledGraphics or continue with the current one
Graphics g = null;
if (graphics instanceof J2DGraphics) {
// Java2D engine
g = graphics;
} else {
g = new ScaledGraphics(graphics);
}
// Always preserve current state
g.pushState();
// Apply application specific code
if (!optimizeClip)
g.clipRect(getBounds().getCropped(getInsets()));
g.translate(getBounds().x + getInsets().left, getBounds().y + getInsets().top);
g.scale(zoom);
// Paint figures with the new graphics state
paintChildren(g);
// Restore it
g.popState();
// dispose of the temporary ScaledGraphics
if (g instanceof ScaledGraphics) g.dispose();
}
This pattern is sufficiently generic (and really necessary in very few situations) that we can conclude that you can now provide the best of both worlds to your clients.
© 2002 - 2004, Holongate.org