Last updated on 2012-12-11
I am creating a GEF editor for the Object Process Methodology modeling language. The modeling language uses an isosceles triangle, resembling the one that is provided by the org.eclipse.draw2d.Triangle
class. Problem is the Triangle
provided by the framework cannot be extended or customized (it is always draw having base=2*height, inside the bounds of the figure).
So heck, I had to implement my own triangle class, based on the implementation provided by the framework. Just like the Triangle
class, I extended the org.eclipse.draw2d.Shape
class, implemented the fillShape()
and outlineShape()
methods (as the javacode for the class said I should do), and also the validate
method, like in the org.eclipse.drawd2.Triangle
class. I fired up my application and surely, my new non-isosceles triangle showed on screen. But if I moved it disappeared, appearing again when I did another operation that required a refresh on the triangle (like moving another figure above the triangle).
Looking at the original Triangle
implementation, it had another overridden method which was not mentioned anywhere and I did not implement: primTranslate
. Well so it happens that the setBounds
method in the org.eclipse.draw2d.Figure
class uses the primTranslate
method to move the figure when the bounds of the figure are moved to a new origin point. So I went and coded my own primTranslate
method and now everything is working fine.
So what did I learn today? First, I learned that if you extend the org.eclipse.draw2d.Shape
class you should most probably override the primTranslate
method. Second, extending classes is not always straightforward and must be done with care, because the base classes may have a lot of underlying functionality that is not documented. Third, you should always explain how your class should be overridden, specially if your class is part of a large framework and you expect the users of the framework to override it.
And if you want, here is the code of the generic triangle class:
package com.vainolo.phd.opm.gef.editor.figure; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.Shape; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PointList; /** * A triangle that uses all of its bounds to draw an isosceles triangle * in the figure's bounds, like this: * * ______ * | /\ | * | / \ | (bounds shown as surrounding rectangle). * |/____\| * * The implementation is based on the {@link org.eclipse.draw2d.Triangle} implementation. * * @author vainolo * */ public final class Triangle extends Shape { /** The points of the triangle. */ protected PointList triangle = new PointList(3); /** * {@inheritDoc} */ @Override public void primTranslate(int dx, int dy) { super.primTranslate(dx, dy); triangle.translate(dx, dy); } /** * {@inheritDoc} */ @Override protected void outlineShape(Graphics graphics) { graphics.drawPolygon(triangle); } /** * {@inheritDoc} */ @Override protected void fillShape(Graphics graphics) { graphics.fillPolygon(triangle); } /** * Validates the figure, drawing a vertical isosceles triangle filling the * figure's bounds. */ @Override public void validate() { super.validate(); bounds = getBounds().getCopy(); Point top = new Point(bounds.x+bounds.width/2, bounds.y); Point left = new Point(bounds.x, bounds.y+bounds.height); Point right = new Point(bounds.x+bounds.width, bounds.y+bounds.height); triangle.removeAllPoints(); triangle.addPoint(top); triangle.addPoint(left); triangle.addPoint(right); } }
9/8/2011 – Update
Seems that my triangle code is not completely correct. While it draws filled triangles correctly triangles that are not filled are shown without the bottom line. Reading the code of org.eclipse.draw2d.Triangle
I came with the following changes:
- Shrink and resize the bounds of the containing rectangle before creating the triangle (that is how it is done in their implementation).
- STOP using the
bounds
variable in thevalidate
functions, specially since I am changing it.
@Override public void validate() { super.validate(); Rectangle r = getBounds().getCopy(); r.shrink(getInsets()); r.resize(-1, -1); Point top = new Point(r.x+r.width/2, r.y); Point left = new Point(r.x, r.y+r.height); Point right = new Point(r.x+r.width, r.y+r.height); triangle.removeAllPoints(); triangle.addPoint(top); triangle.addPoint(left); triangle.addPoint(right); }
Be First to Comment