Support free tutorials









vogella training Training Books



Eclipse 4 Renderer - Tutorial

Building Eclipse RCP applications based on Eclipse 4

Lars Vogel

Version 6.5

08.07.2013

Overview of the Rendering Framework in Eclipse 4

This tutorial gives an overview about the rendering framework introduced in Eclipse 4.


Table of Contents

1. Renderer Framework
1.1. Renderer
1.2. Renderer factory and renderer objects
1.3. Context creation of model objects
1.4. Using a custom renderer
2. Exercise: Defining a renderer
2.1. Target
2.2. Create plug-in
2.3. Enter dependencies
2.4. Create renderer implementation
2.5. Register renderer
2.6. Validate
3. Exercise: A custom part renderer
4. Alternative renderer
4.1. Alternatives to SWT
4.2. Vaadin renderer - Vaaeclipse
4.3. JavaFX renderer - e(fx)clipse
4.4. Eclipse RAP
4.5. Additional UI toolkits
5. Learn more about Eclipse 4 RCP development
6. Support this website
6.1. Thank you
6.2. Questions and Discussion
7. Links and Literature
7.1. Source Code
7.2. Renderer resources
7.3. vogella Resources

Get the book Eclipse RCP book

1. Renderer Framework

1.1. Renderer

An Eclipse application is modeled without a hard dependency to a specific user interface toolkit. Eclipse allows you to define a renderer factory. This renderer factory determines for every model element the responsible renderer object.

A renderer object is responsible for creating the user interface objects for its model element, monitoring their changes and reacting to these changes.

By default the Eclipse platform uses the SWT based WorkbenchRendererFactory as renderer factory. The org.eclipse.e4.ui.workbench.renderers.swt plug-in contains this default implementation.

1.2. Renderer factory and renderer objects

The renderer factory determines per model object the renderer object which is responsible for rendering the corresponding model object.

Renderer factories implement the IRendererFactory interface. In the getRenderer() method it returns a renderer object of type AbstractPartRenderer.

For example, if the model element is an instance of MPart, then an instance of the ContributedPartRenderer class is created by the default Eclipse renderer factory. The relevant code in the WorkbenchRendererFactory class is shown below.

// Other if statements above
else if (uiElement instanceof MPart) {
  if (contributedPartRenderer == null) {
    contributedPartRenderer = new ContributedPartRenderer();
    initRenderer(contributedPartRenderer);
  }
  return contributedPartRenderer;
} 

1.3. Context creation of model objects

During the rendering the IEclipseContext of those model elements which extend MContext (MApplication, MPart, etc) is created and populated.

For example an object of type ContributedPartRenderer is the default renderer for a MPart model element. This object creates a Composite and injects it into the local context of each part.

1.4. Using a custom renderer

The Eclipse platform allows you to extend or exchange the default renderer classes. For example you can change the stack to use tabs at the bottom instead of the top.

You can also implement renderer for other user interface toolkits than SWT. For example you could use JavaFX or Swing for your application.

Tip

If you switch from SWT to another user interface technology your non user interface related logic, e.g. services, the model application, etc. can be reused. But you need to re-implement your user interface components. For example a part written in SWT must be re-written in JavaFX to work together with a JavaFX Renderer.

The custom renderer factory is registered via the org.eclipse.core.runtime.products extension point. You use an additional property called rendererFactoryUri to point to the new factory class.

2. Exercise: Defining a renderer

2.1. Target

The following exercise serves as a simple example for creating a custom renderer. It implements a custom stack renderer which uses "* Demo *" instead of "*" to mark an editor dirty.

2.2. Create plug-in

Create a new simple plug-in called com.example.e4.renderer.swt. This plug-in is called the renderer plug-in in the following description.

2.3. Enter dependencies

Add the following plug-ins as dependencies to your renderer plug-in.

  • org.eclipse.e4.core.contexts

  • org.eclipse.e4.ui.workbench.renderers.swt

  • org.eclipse.e4.ui.workbench.swt

  • org.eclipse.e4.ui.workbench

  • org.eclipse.e4.core.services

  • org.eclipse.e4.ui.model.workbench

  • org.eclipse.swt

2.4. Create renderer implementation

Create in your renderer plug-in the com.example.e4.renderer.swt package.

Create the following classes. The new stack renderer extends the existing renderer.

package com.example.e4.renderer.swt;

import org.eclipse.e4.ui.model.application.ui.MDirtyable;
import org.eclipse.e4.ui.model.application.ui.MUILabel;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer;
import org.eclipse.swt.custom.CTabItem;

public class MyStackRenderer extends StackRenderer {
  
  protected void updateTab(CTabItem cti, MPart part, String attName,
      Object newValue) {
    if (UIEvents.UILabel.LABEL.equals(attName)) {
      String newName = (String) newValue;
      cti.setText(getLabel(part, newName));
    } else if (UIEvents.UILabel.ICONURI.equals(attName)) {
      cti.setImage(getImage(part));
    } else if (UIEvents.UILabel.TOOLTIP.equals(attName)) {
      String newTTip = (String) newValue;
      cti.setToolTipText(newTTip);
    } else if (UIEvents.Dirtyable.DIRTY.equals(attName)) {
      Boolean dirtyState = (Boolean) newValue;
      String text = cti.getText();
      boolean hasAsterisk = text.length() > 0 && text.charAt(0) == '!';
      if (dirtyState.booleanValue()) {
        if (!hasAsterisk) {
          cti.setText("* Demo *" + text);
        }
      } else if (hasAsterisk) {
        cti.setText(text.substring(1));
      }
    }
  }


  private String getLabel(MUILabel itemPart, String newName) {
    if (newName == null) {
      newName = ""; //$NON-NLS-1$
    }
    if (itemPart instanceof MDirtyable && ((MDirtyable) itemPart).isDirty()) {
      newName = '*' + newName;
    }
    return newName;
  }
} 

package com.example.e4.renderer.swt;

import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
import org.eclipse.e4.ui.workbench.renderers.swt.WorkbenchRendererFactory;

public class MyRendererFactory extends WorkbenchRendererFactory {
  private MyStackRenderer stackRenderer;

  @Override
  public AbstractPartRenderer getRenderer(MUIElement uiElement, Object parent) {
    if (uiElement instanceof MPartStack) {
      if (stackRenderer == null) {
        stackRenderer = new MyStackRenderer();
        super.initRenderer(stackRenderer);
      }
      return stackRenderer;
    }
    return super.getRenderer(uiElement, parent);
  }
} 

2.5. Register renderer

Register your renderer in the plugin.xml file of your com.example.e4.rcp.todo file. For this create a new property on the extension for your product. Use rendererFactoryUri as name and bundleclass://com.example.e4.renderer.swt/com.example.e4.renderer.swt.MyRendererFactory as value. This setting is similar to the setting of the applicationCSS or the lifeCycleURI property hence you should know how to do this.

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>

   <extension
         id="product"
         point="org.eclipse.core.runtime.products">
      <product
        application="org.eclipse.e4.ui.workbench.swt.E4Application"
        name="to-do">
         <property
               name="applicationXMI"
               value="com.example.e4.rcp.todo/Application.e4xmi">
         </property>
         <property
               name="appName"
               value="to-do">
         </property>
      <property
        name="rendererFactoryUri"
        value="bundleclass://com.example.e4.renderer.swt/[CONTINUE...]
        com.example.e4.renderer.swt.MyRendererFactory">
       </property>
      </product>
   </extension>

</plugin> 

2.6. Validate

Start your application and change a Todo in your TodoDetailPart. The dirty indicator should now be different as indicated in the following screenshot.

Stack renderer with alternative dirty implementation

3. Exercise: A custom part renderer

In this exercise you create a custom part renderer which renders all parts with an SWT browser widget.

Warning

This example might not work on Linux, as the SWT browser widget sometimes has issues on Linux.

package com.example.e4.renderer.swt;

import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.workbench.renderers.swt.SWTPartRenderer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;

public class MyPartRenderer extends SWTPartRenderer {
  public static final String ID = "de.vogella.javascript.maps.view";

  @Override
  public Object createWidget(MUIElement element, Object parent) {
    final Composite mapComposite = new Composite((Composite) parent,
        SWT.NONE);
    System.out.println(parent.getClass());
    mapComposite.setLayout(new GridLayout(1, false));
    final Browser browser = new Browser(mapComposite, SWT.NONE);
    browser.setUrl("http://www.vogella.com");
    GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
    browser.setLayoutData(data);
    return mapComposite;
  }
} 

Extend the MyRendererFactory to the following to use your own part renderer.

package com.example.e4.renderer.swt;

import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
import org.eclipse.e4.ui.workbench.renderers.swt.WorkbenchRendererFactory;

public class MyRendererFactory extends WorkbenchRendererFactory {

  private MyStackRenderer stackRenderer;
  private MyPartRenderer partRenderer;

  @Override
  public AbstractPartRenderer getRenderer(MUIElement uiElement, Object parent) {

    if (uiElement instanceof MPart) {
      if (partRenderer == null) {
        partRenderer = new MyPartRenderer();
        super.initRenderer(partRenderer);
      }
      return partRenderer;
    } else if (uiElement instanceof MPartStack) {
      if (stackRenderer == null) {
        stackRenderer = new MyStackRenderer();
        super.initRenderer(stackRenderer);
      }
      return stackRenderer;
    }
    return super.getRenderer(uiElement, parent);

  }

} 

Run your application and test that every part is now rendered as browser.

Note

Currently all parts show the same URL, but you could extend your renderer to access for example tags at the parts to determine the URLs which should be used.

Using a Browser Renderer for the Parts

Warning

After finishing the test, remove the rendererFactoryUri property from the plugin.xml file of your application plug-in, so that your application works again as before.

4. Alternative renderer

4.1. Alternatives to SWT

You can use any user interface technology for your RCP application, as long as you provide a renderer implementation for it. There are already several default implementations besides SWT available. This section lists the most popular ones.

A popular misconception about a different renderer is that you can port your SWT applications unchanged to it, for example to Vaadin or JavaFX. That is not the case. Alternative renderer implementations do not port automatically your user interface implementation which relate to code. For example in the exercises of this book your parts or your tool controls are implemented with SWT classes.

You have to re-implement these user interface components. The value of alternative renderer implementations lies in the fact that you have an application framework with a modeled application and dependency injection of which your user interface framework can take advantage. This allows you to use the Eclipse 4 application framework with the user interface toolkit of your choice.

4.2. Vaadin renderer - Vaaeclipse

Vaaclipse is a framework for building web applications using the Eclipse 4 platform and Vaadin. It allows to use the power of the Eclipse framework in web development.

You find more information about this project on the following homepage: Vaaclipse

The following screenshots show demo applications of Vaaclipse.

Vaadin renderer for Eclipse 4

Vaadin renderer for Eclipse 4

4.3. JavaFX renderer - e(fx)clipse

The e(fx)clipse provides a JavaFX renderer for Eclipse 4 RCP application. For more information see the e(fx)clipse homepage. The following screenshot shows an example Eclipse RCP application using JavaFX as renderer.

JavaFX renderer example

4.4. Eclipse RAP

Eclipse RAP is an approach to provide a web implementation for the SWT API and makes it relatively easy to run an Eclipse 3.x RCP application in the web without code modifications.

Eclipse RAP is special case as the renderer is still the default SWT renderer but there is a translation layer between SWT and the actual widget that is produced. This allows you to reuse your SWT user interface code to run as a web application.

Currently the Eclipse RAP team does not officially support the Eclipse 4 API but several Open Source ports have been made. See for example Eclipse 4 on RAP wiki.

4.5. Additional UI toolkits

Writing source code is the current default approach by the Eclipse platform to create your user interfaces.

Currently several Open Source frameworks are developed to simplify the creation of user interface components or to remove a hard dependency to a specific rendering framework. The following description is a limited selection of possible approaches.

The jo-widget project provides components which can be rendered to SWT, Swing and JavaFX. See the jo-widget homepage for more information.

The Eclipse XWT project supports the creation of user interface components based on XML files. See the XWT wiki for documentation.

The Eclipse Sapphire project allows you to create user interfaces based on a property editor. See the Eclipse Sapphire homepage for details.

The Wazzabi project provides functionality to model the user interface via EMF and to generate the SWT user interface at runtime based on this model. See the Wazzabi homepage for more information.

The EMF Parsley project plans to provide model based user interface components. See the EMF Parsley project page for more information.

5. Learn more about Eclipse 4 RCP development

I hope you enjoyed this tutorial. You find this tutorial and much more information also in the Eclipse 4 RCP book from this author.

6. Support this website

This tutorial is Open Content under the CC BY-NC-SA 3.0 DE license. Source code in this tutorial is distributed under the Eclipse Public License. See the vogella License page for details on the terms of reuse.

Writing and updating these tutorials is a lot of work. If this free community service was helpful, you can support the cause by giving a tip as well as reporting typos and factual errors.

6.1. Thank you

Please consider a contribution if this article helped you. It will help to maintain our content and our Open Source activities.

6.2. Questions and Discussion

If you find errors in this tutorial, please notify me (see the top of the page). Please note that due to the high volume of feedback I receive, I cannot answer questions to your implementation. Ensure you have read the vogella FAQ as I don't respond to questions already answered there.

7. Links and Literature

7.1. Source Code

Source Code of Examples

7.2. Renderer resources

Receipes for Efxclipse for JavaFX

7.3. vogella Resources

vogella Training Android and Eclipse Training from the vogella team

Android Tutorial Introduction to Android Programming

GWT Tutorial Program in Java, compile to JavaScript and HTML

Eclipse RCP Tutorial Create native applications in Java

JUnit Tutorial Test your application

Git Tutorial Put all your files in a distributed version control system