Creating a GEF Editor – Part 6: Model Refactoring and Editing Diagram Entities

Previous Tutorial: Creating a GEF Editor – Part 5: Loading the Model from an EMF File

We finished the last tutorial with a working “editor” on which not much editing could be done… So in this tutorial we’ll be adding some editing capabilities to the GEF editor.
But before this, while preparing this tutorial I saw that doing some refactoring to the model we could reduce duplicate code, which is always good. So I did a full refactoring of the model, from which we will start this tutorial (I also renamed the ObjectProcessDiagram class to OPMObjectProcessDiagram for consistency). For your convenience, the new .ecore file can be downloaded from here. Replace your current .ecore file with this file and do “Generate All” on your .genmodel file. This will probably generate some compile errors on your project, but they can be fixed pretty easily. Furthermore, delete the (generated) ObjectProcessDiagram.java file in the modeling project. This will cause more compiler problems that can also be easily fixed, and after this your code should be clean and ready to go (as you see, model refactoring is not yet at the level of code refactoring and has a long way to go… which is pretty bad because it makes developer think too much about the model because model changes are expensive. But NEVER be afraid of refactoring, just do it with caution and with a backup/version control system at hand). You can also download the code (all eclipse projects including generated code) from which the tutorial starts from here.
BTW, I also upgraded my eclipse to the latest eclipse Indigo release, modeling tools package and impressively, things worked just fine. So lets get working.

  1. First thing we are going to do is add the OPMProcess model entity to our editor. Looking at the model we see that the OPMObject and OPMProcess classes share most (actually all) of their attributes… so why duplicate? basically this is because the real OPMObject and OPMProcess contain many more attributes that do differentiate them. But this sharing of information makes us think that also the classes used by GEF should have some hierarchy so that code is not duplicated. So we are going to create an interface OPMThingFigure (for the OPMObjectFigure and OPMProcessFigure classes) and an abstract class OPMThingEditPart (for the OPMObjectEditPart and OPMProcessEditPart). In the first case we had to use an interface instead of an abstract class because we had some problems with draw2d painting order and instancing order between the super-class and the sub-class (or something like that… I should have written that down :-(), which made the code look pretty ugly.
    package com.vainolo.phd.opm.gef.editor.figure;
    
    import org.eclipse.draw2d.IFigure;
    import org.eclipse.draw2d.Label;
    
    public interface OPMThingFigure extends IFigure {
    	public Label getNameLabel();
    }
    
    package com.vainolo.phd.opm.gef.editor.part;
    
    import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
    
    import com.vainolo.phd.opm.gef.editor.figure.OPMThingFigure;
    import com.vainolo.phd.opm.model.OPMThing;
    
    public abstract class OPMThingEditPart extends AbstractGraphicalEditPart {
    	@Override protected void refreshVisuals() {
    		OPMThingFigure figure = (OPMThingFigure)getFigure();
    		OPMThing model = (OPMThing)getModel();
    		OPMObjectProcessDiagramEditPart parent = (OPMObjectProcessDiagramEditPart) getParent();
    
    		figure.getNameLabel().setText(model.getName());
    		parent.setLayoutConstraint(this, figure, model.getConstraints());
    	}
    }
    

    Now remove the refreshVisuals method from the OPMObjectEditPart class and make the class extend OPMThingEditPart. Also make OPMObjectFigure implement OPMThingFigure and rename the getLabel method to getNameLabel to make them compatible with the interface.

    package com.vainolo.phd.opm.gef.editor.figure;
    
    import org.eclipse.draw2d.Figure;
    import org.eclipse.draw2d.Graphics;
    import org.eclipse.draw2d.Label;
    import org.eclipse.draw2d.RectangleFigure;
    import org.eclipse.draw2d.XYLayout;
    import org.eclipse.draw2d.geometry.Rectangle;
    
    public class OPMObjectFigure extends Figure implements OPMThingFigure {
    	private Label label;
    	private RectangleFigure rectangle;
    
    	public OPMObjectFigure() {
    		setLayoutManager(new XYLayout());
    		rectangle = new RectangleFigure();
    		add(rectangle);
    		label = new Label();
    		add(label);
    	}
    
    	@Override protected void paintFigure(Graphics graphics) {
    		Rectangle r = getBounds().getCopy();
    		setConstraint(rectangle, new Rectangle(0, 0, r.width, r.height));
    		setConstraint(label, new Rectangle(0, 0, r.width, r.height));
    	}
    
    	public Label getNameLabel() {
    		return label;
    	}
    }
    
    package com.vainolo.phd.opm.gef.editor.part;
    
    import org.eclipse.draw2d.IFigure;
    
    import com.vainolo.phd.opm.gef.editor.figure.OPMObjectFigure;
    
    public class OPMObjectEditPart extends OPMThingEditPart {
    
    	@Override
    	protected IFigure createFigure() {
    		return new OPMObjectFigure();
    	}
    
    	@Override
    	protected void createEditPolicies() {
    		// TODO Auto-generated method stub
    
    	}
    }
    

    The editor should still be working as it did before this refactoring (try it just in case…)

  2. We’ll add now the OPMProcess to our editor. This is done much like we did for OPMObject: create a figure which represent the model object and create an edit part to manage that figure:
    package com.vainolo.phd.opm.gef.editor.figure;
    
    import org.eclipse.draw2d.ConnectionAnchor;
    import org.eclipse.draw2d.Ellipse;
    import org.eclipse.draw2d.EllipseAnchor;
    import org.eclipse.draw2d.Figure;
    import org.eclipse.draw2d.Graphics;
    import org.eclipse.draw2d.Label;
    import org.eclipse.draw2d.XYLayout;
    import org.eclipse.draw2d.geometry.Rectangle;
    
    public class OPMProcessFigure extends Figure implements OPMThingFigure {
    	private Label nameLabel;
    	private Ellipse ellipse;
    	private ConnectionAnchor connectionAnchor;
    
    	public OPMProcessFigure() {
    		setLayoutManager(new XYLayout());
    		ellipse = new Ellipse();
    		add(ellipse);
    		nameLabel = new Label();
    		add(nameLabel);
    	}
    
    	@Override protected void paintFigure(Graphics graphics) {
    		Rectangle r = getBounds().getCopy();
    		setConstraint(ellipse, new Rectangle(0, 0, r.width, r.height));
    		setConstraint(nameLabel, new Rectangle(0, 0, r.width, r.height));
    		ellipse.invalidate();
    		nameLabel.invalidate();
    	}
    
    	public Label getNameLabel() {
    		return nameLabel;
    	}
    
    	public ConnectionAnchor getConnectionAnchor() {
    		if (connectionAnchor == null) {
    			connectionAnchor = new EllipseAnchor(this);
    		}
    		return connectionAnchor;
    	}
    }
    
    package com.vainolo.phd.opm.gef.editor.part;
    
    import org.eclipse.draw2d.IFigure;
    
    import com.vainolo.phd.opm.gef.editor.figure.OPMProcessFigure;
    
    public class OPMProcessEditPart extends OPMThingEditPart {
    
    	@Override protected IFigure createFigure() {
    		return new OPMProcessFigure();
    	}
    }
    
  3. Now for some editing functionality. The first thing we are going to do is let the user add new entities to the diagram. This is a bit more complicated than other editing capabilities but it gives you (well, at least it gave me) much satisfaction. Before we delve into the code, it is good to have at least a superficial understanding on what we will be doing.
    The way to add new entities to a GEF diagram is by using palette tools, where the user select the tool and then clicks on the diagram to add the figure. In GEF, creation of new entities is done using a CreationToolEntry that when activated (I’m not sure if this is when the tool is selected or when the user clicks on the diagram), creates a new model entity (using a provided factory) and fires a CreateRequest on the EditPart that is represented by the figure currently below the mouse. CreateRequests are handled by a LayoutEditPolicy instance that is installed in the EditPart on which the new entities are added, in our case we use an XYLayoutEditPolicy because the OPMObjectProcessDiagram uses an FreeformLayout which is a subclass of XYLayout. The XYLayoutPolicy creates a Command that is executed and causes the model to change.
    But this is only one part of the trip. After the model is edited, we (probably) need to repaint the diagram in some way. In our case, we need to inform the OPMObjectProcessModelEditPart that there has been a change to its children and that it must repaint them. Here is one of the cases where EMF saves us times with ready-built notifiers that can be used in this case. We create an Adapter class inside the OPMObjectProcessDiagramEditPart that listens to changes to the model and refreshes the view when changes are detected (an Adapter is regularly called an Observer in java, but for some reason I still do not understand the EMF developers decided to name it differently, creating some confusion since they are implementing an Observer design pattern and not an Adapter design pattern. I really hope they have good reasons).
    There are a lot of code changes, so we’ll do this slowly. As I always like, changes are coded so that at all times our code compiles.
  4. First thing we do is create a new Command to be executed by the framework to add a new entity to the diagram:
    package com.vainolo.phd.opm.gef.editor.command;
    
    import org.eclipse.draw2d.geometry.Dimension;
    import org.eclipse.draw2d.geometry.Point;
    import org.eclipse.draw2d.geometry.Rectangle;
    import org.eclipse.gef.commands.Command;
    
    import com.vainolo.phd.opm.model.OPMObjectProcessDiagram;
    import com.vainolo.phd.opm.model.OPMThing;
    
    public class OPMThingCreateCommand extends Command {
    
    	private static final Dimension defaultDimension = new Dimension(50, 50);
    	private static final String defaultName = "<...>";
    
    	private OPMThing newThing;
    	private Rectangle constraints;
    	private OPMObjectProcessDiagram opd;
    
    	@Override public void execute() {
    		newThing.setName(defaultName);
    		if(constraints != null) {
    			newThing.setConstraints(constraints);
    		}
    		newThing.setOpd(opd);
    	}
    
    	@Override public void undo() {
    		newThing.setOpd(null);
    	}
    
    	public void setLocation(Point location) {
    		constraints = new Rectangle(location, defaultDimension);
    	}
    
    	public void setParent(OPMObjectProcessDiagram opd) {
    		this.opd = opd;
    	}
    
    	public void setThing(OPMThing newThing) {
    		this.newThing = newThing;
    	}
    }
    
  5. Now we create a the XYLayoutPolicy that will be installed in the OPMObjectProcessDiagramEditPart to handle the creation of new entities:
    package com.vainolo.phd.opm.gef.editor.policy;
    
    import org.eclipse.gef.commands.Command;
    import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
    import org.eclipse.gef.requests.CreateRequest;
    
    import com.vainolo.phd.opm.gef.editor.command.OPMThingCreateCommand;
    import com.vainolo.phd.opm.model.OPMObjectProcessDiagram;
    import com.vainolo.phd.opm.model.OPMThing;
    
    public class OPMObjectProcessDiagramXYLayoutPolicy extends XYLayoutEditPolicy {
    
    	@Override protected Command getCreateCommand(CreateRequest request) {
    		Command retVal = null;
    		if(request.getNewObject() instanceof OPMThing) {
    			OPMThingCreateCommand command = new OPMThingCreateCommand();
    			command.setLocation(request.getLocation());
    			command.setParent((OPMObjectProcessDiagram)(getHost().getModel()));
    			command.setThing((OPMThing)(request.getNewObject()));
    			retVal = command;
    		}
    		return retVal;
    	}
    }
    
  6. Now we do two changes in the OPMObjectProcessDiagramEditPart: we install the new EditPolicy and we add a model listener so the class is notified of model changes and can reflect them in the editor if desired. We must also add creation of a OPMProcessEditPart in our OPMEditPartFactory for the sake of completeness:
    package com.vainolo.phd.opm.gef.editor.part;
    
    import java.util.ArrayList;
    import java.util.List;
    import org.eclipse.draw2d.FreeformLayer;
    import org.eclipse.draw2d.FreeformLayout;
    import org.eclipse.draw2d.IFigure;
    import org.eclipse.draw2d.LineBorder;
    import org.eclipse.emf.common.notify.Adapter;
    import org.eclipse.emf.common.notify.Notification;
    import org.eclipse.emf.common.notify.Notifier;
    import org.eclipse.gef.EditPolicy;
    import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
    
    import com.vainolo.phd.opm.gef.editor.policy.OPMObjectProcessDiagramXYLayoutPolicy;
    import com.vainolo.phd.opm.model.OPMObjectProcessDiagram;
    import com.vainolo.phd.opm.model.OPMThing;
    
    public class OPMObjectProcessDiagramEditPart extends AbstractGraphicalEditPart {
    
    	private OPMObjectProcessDiagramAdapter adapter;
    
    	public OPMObjectProcessDiagramEditPart() {
    		super();
    		adapter = new OPMObjectProcessDiagramAdapter();
    	}
    
    	@Override
    	protected IFigure createFigure() {
    		FreeformLayer layer = new FreeformLayer();
    		layer.setLayoutManager(new FreeformLayout());
    		layer.setBorder(new LineBorder(1));
    		return layer;
    	}
    
    	@Override
    	protected void createEditPolicies() {
    		installEditPolicy(EditPolicy.LAYOUT_ROLE, new OPMObjectProcessDiagramXYLayoutPolicy());
    	}
    
    	@Override protected List<OPMThing> getModelChildren() {
    		List<OPMThing> retVal = new ArrayList<OPMThing>();
    		OPMObjectProcessDiagram opd = (OPMObjectProcessDiagram) getModel();
    		retVal.addAll(opd.getThings());
    		return retVal;
    	}
    
    	@Override public void activate() {
    		if(!isActive()) {
    			((OPMObjectProcessDiagram)getModel()).eAdapters().add(adapter);
    		}
    		super.activate();
    	}
    
    	@Override public void deactivate() {
    		if(isActive()) {
    			((OPMObjectProcessDiagram)getModel()).eAdapters().remove(adapter);
    		}
    		super.deactivate();
    	}
    
    	public class OPMObjectProcessDiagramAdapter implements Adapter {
    
    		@Override public void notifyChanged(Notification notification) {
    			refreshChildren();
    		}
    
    		@Override public Notifier getTarget() {
    			return (OPMObjectProcessDiagram)getModel();
    		}
    
    		@Override public void setTarget(Notifier newTarget) {
    			// Do nothing.
    		}
    
    		@Override public boolean isAdapterForType(Object type) {
    			return type.equals(OPMObjectProcessDiagram.class);
    		}
    	}
    
    }
    

    We created an inner class to handle model updates since it is the cleanest way we found that we could do it. Implementing the Adapter interface directly caused name collisions with functions used by the NodeEditPart interface which will be used later when we add connections between the model entities, and doing this in an external class required exposing the refreshChildren which is protected.
    Now the modifications to the OPMEditPartFactory:

    package com.vainolo.phd.opm.gef.editor.part;
    
    import com.vainolo.phd.opm.model.OPMObject;
    import com.vainolo.phd.opm.model.OPMObjectProcessDiagram;
    import com.vainolo.phd.opm.model.OPMProcess;
    
    import org.eclipse.gef.EditPart;
    import org.eclipse.gef.EditPartFactory;
    
    public class OPMEditPartFactory implements EditPartFactory {
    
    	@Override public EditPart createEditPart(EditPart context, Object model) {
    		EditPart part = null;
    
    		if(model instanceof OPMObjectProcessDiagram) {
    			part = new OPMObjectProcessDiagramEditPart();
    		} else if(model instanceof OPMObject) {
    			part = new OPMObjectEditPart();
    		} else if(model instanceof OPMProcess) {
    			part = new OPMProcessEditPart();
    		}
    
    		if(part != null) {
    			part.setModel(model);
    		}
    
    		return part;
    	}
    }
    
  7. We are almost done. The creation tools that we define in GEF work on model entities and for this they must be able to create new model classes instances on demand, therefore they require factory classes to provide them with this functionality. For this purpose we create two new classes: an OPMObjectFactory and a OPMProcessFactory.
    package com.vainolo.phd.opm.gef.editor.factory;
    
    import org.eclipse.gef.requests.CreationFactory;
    
    import com.vainolo.phd.opm.model.OPMFactory;
    import com.vainolo.phd.opm.model.OPMObject;
    
    public class OPMObjectFactory implements CreationFactory {
    
    	@Override public Object getNewObject() {
    		return OPMFactory.eINSTANCE.createOPMObject();
    	}
    
    	@Override public Object getObjectType() {
    		return OPMObject.class;
    	}
    
    }
    
    package com.vainolo.phd.opm.gef.editor.factory;
    
    import org.eclipse.gef.requests.CreationFactory;
    
    import com.vainolo.phd.opm.model.OPMFactory;
    import com.vainolo.phd.opm.model.OPMProcess;
    
    public class OPMProcessFactory implements CreationFactory {
    
    	@Override public Object getNewObject() {
    		return OPMFactory.eINSTANCE.createOPMProcess();
    	}
    
    	@Override public Object getObjectType() {
    		return OPMProcess.class;
    	}
    
    }
    
  8. To wrap things up, we must provide the GEF editor with a palette that contains the tools we want to add:
    package com.vainolo.phd.opm.gef.editor;
    
    import org.eclipse.gef.palette.CreationToolEntry;
    import org.eclipse.gef.palette.PaletteGroup;
    import org.eclipse.gef.palette.PaletteRoot;
    import org.eclipse.gef.palette.SelectionToolEntry;
    
    import com.vainolo.phd.opm.gef.editor.factory.OPMObjectFactory;
    import com.vainolo.phd.opm.gef.editor.factory.OPMProcessFactory;
    
    public class OPMGraphicalEditorPalette extends PaletteRoot {
    
    	PaletteGroup group;
    
    	public OPMGraphicalEditorPalette() {
    		addGroup();
    		addSelectionTool();
    		addOPMObjectTool();
    		addOPMProcessTool();
    	}
    
    	private void addSelectionTool() {
    		SelectionToolEntry entry = new SelectionToolEntry();
    		group.add(entry);
    		setDefaultEntry(entry);
    	}
    
    	private void addGroup() {
    		group = new PaletteGroup("OPM Controls");
    		add(group);
    	}
    
    	private void addOPMObjectTool() {
    		CreationToolEntry entry = new CreationToolEntry("OPMObject", "Create a new Object", new OPMObjectFactory(), null, null);
    		group.add(entry);
    	}
    
    	private void addOPMProcessTool() {
    		CreationToolEntry entry = new CreationToolEntry("OPMProcess", "Create a new Process", new OPMProcessFactory(), null, null);
    		group.add(entry);
    	}
    }
    

    and we tell the editor that we want to install our palette as the editor’s palette:

    package com.vainolo.phd.opm.gef.editor;
    
    import java.io.IOException;
    
    import org.eclipse.core.resources.IFile;
    import org.eclipse.core.runtime.IProgressMonitor;
    import org.eclipse.emf.common.util.URI;
    import org.eclipse.emf.ecore.resource.Resource;
    import org.eclipse.emf.ecore.resource.ResourceSet;
    import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
    import org.eclipse.gef.DefaultEditDomain;
    import org.eclipse.gef.palette.PaletteRoot;
    import org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette;
    import org.eclipse.ui.IEditorInput;
    import org.eclipse.ui.IEditorSite;
    import org.eclipse.ui.IFileEditorInput;
    import org.eclipse.ui.PartInitException;
    
    import com.vainolo.phd.opm.gef.editor.part.OPMEditPartFactory;
    import com.vainolo.phd.opm.model.OPMPackage;
    import com.vainolo.phd.opm.model.OPMObjectProcessDiagram;
    
    public class OPMGraphicalEditor extends GraphicalEditorWithFlyoutPalette {
    
    	private Resource opdResource;
    	private OPMObjectProcessDiagram opd;
    
    	public OPMGraphicalEditor() {
    		setEditDomain(new DefaultEditDomain(this));
    	}
    
    	@Override protected void initializeGraphicalViewer() {
    		super.initializeGraphicalViewer();
    		getGraphicalViewer().setContents(opd);
    	}
    
    	@Override protected void configureGraphicalViewer() {
    		super.configureGraphicalViewer();
    		getGraphicalViewer().setEditPartFactory(new OPMEditPartFactory());
    	}
    
    	@Override protected PaletteRoot getPaletteRoot() {
    		return new OPMGraphicalEditorPalette();
    	}
    
    	@Override public void doSave(IProgressMonitor monitor) {
    		if(opdResource == null) {
    			return;
    		}
    
    		try {
    			opdResource.save(null);
    		} catch(IOException e) {
    			// TODO do something smarter.
    			e.printStackTrace();
    			opdResource = null;
    		}
    	}
    
    	@Override public void init(IEditorSite site, IEditorInput input) throws PartInitException {
    		super.init(site, input);
    
    		loadInput(input);
    	}
    
    	private void loadInput(IEditorInput input) {
    		OPMPackage.eINSTANCE.eClass(); // This initializes the OPMPackage singleton implementation.
    		ResourceSet resourceSet = new ResourceSetImpl();
    		if(input instanceof IFileEditorInput) {
    			IFileEditorInput fileInput = (IFileEditorInput) input;
    			IFile file = fileInput.getFile();
    			opdResource = resourceSet.createResource(URI.createURI(file.getLocationURI().toString()));
    			try {
    				opdResource.load(null);
    				opd = (OPMObjectProcessDiagram) opdResource.getContents().get(0);
    			} catch(IOException e) {
    				// TODO do something smarter.
    				e.printStackTrace();
    				opdResource = null;
    			}
    		}
    	}
    }
    

    BTW, if you didn’t notice, I also added save capabilities to the editor. While you cannot (yet) save manually, when you close the editor it will ask you if you want to save the file before closing (even if you didn’t do any changes).

  9. That’s it. Execute your editor, select a tool and add new entities to the diagram! This is how this looks in my diagram:

There is lots of work left, like moving the diagram entities, changing their names, and linking them. I promise to add these capabilities in the next few days.

The final eclipse project files can be downloaded here. Sorry, but the zip file somehow got broken, and I don’t have the time to fix it right now. maybe later 🙂

Bye…

Next Tutorial: Creating a GEF Editor – Part 7: Moving Elements and Direct Editing

19 thoughts on “Creating a GEF Editor – Part 6: Model Refactoring and Editing Diagram Entities

  1. Why are you invalidating the ellipse and nameLabel in the OPMProcessFigure class but not the corresponding atributes in the OPMObjectFigure class? Just wondering which vesion is the correct/best version.

    • At this stage of the tutorial both codes work since there are no changes done through the editor. But the final code is like the one that is shown in the OPMProcessFigure class and it is also implemented on the OPMObjectFigure class in the later tutorials, as you can see in the repository

  2. Hi.

    Thanks for the tutorial!

    EMF-Adapters are both: Adapters AND Observers. You can use an AdapterFactory to adapt EMF-Objects to other interfaces:

    SomeInterface adapter = (SomeInterface) SomeInterfaceAdapterFactory.getInstance().adapt(model, SomeInterface.class).
    This will add the adapter (which implements the Adapter and SomeInterface inteface) to the adapters list of the model.

    ls

    • Thanks for the clarification. But it is still confusing that observers are called adapters (at least is confused me for some time).

  3. getModelChildren() method
    retVal.addAll(opd.getThings());
    we dont write any method named getThings() so how is it done

    • Hi. Did you use the ecore file I linked? in that case the problem is that the link points to the latest version of the ecore which has changed a lot. The link was updated to point to the file that matches the tutorial.

  4. hi..
    I am not able to drag and drop figures from palette! Is there are any listeners that i should add ?

  5. HI, Thanks for your posts.
    I’ve tried to run your project on kepler version, but I can’t see the palette on the GEF Editor. Nothing happens. What am I missing?

  6. Hello, Vainolo : )

    If you know about ScalableImageFigure of GMF, you can help poor me. T^T
    My figure’s image has big pixels.
    I guess the image was displayed simply. Because, when i increase size of figure, the figure’s image becomes more clear.
    like this : figure 1 on this site. http://www.adobe.com/inspire/2014/02/illustrator-web-designer.html

    I don’t know what is problem .. OTL …
    What happens to my figure … ?

    Thank you 😀
    Heizel.

  7. Hi Vainolo,
    Greetings!
    How can I bring in my images in the GEF palette ? For ex: image of a computer
    I tried working with Epsilon toolkit of Eclipse but that went on vain.
    I kindly request you to provide me a solution . A good guidance would be appreciated.

  8. Hello,

    I think the zip with the .zip from which the tutorial starts is broken. It fails when I try to decompress it.

    Thanks!

    • Yes, the zip file seems broken. I removed the link from the tutorial as it is too much effort to rebuild it. Thanks for the heads up

  9. Hi,

    I want to understand folowing method.

    @Override protected void paintFigure(Graphics graphics) {
    Rectangle r = getBounds().getCopy();
    setConstraint(rectangle, new Rectangle(0, 0, r.width, r.height));
    setConstraint(label, new Rectangle(0, 0, r.width, r.height));
    }

    Why do we need to create new Rectangle every time paint figure gets called. Is it possible to cache it and use it if it is changed. I tried creating object level variable to hold/cache the figure, but it it did not work, from the canvas , it goes off.

    • Yes, a new rectangle is created. This is the simplest way to do it, and I had no need to optimize the code for better performance. Caching is sometimes evil :-).

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.