Accueil > Eclipse RAP > My first steps with Eclipse RAP [step6]

My first steps with Eclipse RAP [step6]


In step5, we have explained the generated code of the RAP Hello World Application. In this step we will improve our RAP Application to add basic user-interface (UI). At the end of this article, our RAP Application will look like this :

In RAP/RCP Application, UI is managed with SWT (Standard Widget Toolkit) :

SWT is an open source widget toolkit for Java designed to provide efficient, portable access to the user-interface facilities of the operating systems on which it is implemented.

SWT is an API to manage UI. There are several implementation of SWT :

  • for RCP Application, the basic idea of SWT is to use the operating systems (OS) native widget to render UI. There is an implementation of SWT for each OS (Windows, Linux…). Swing for instance emulates the UI widgets, that’s why the look and feel of Swing Application are the same for any OS, although look and feel of SWT Application change according to the OS (a button in SWT Application use Windows button look and feel if the SWT Application runs on Windows, use Linux button look and feel if the SWT Application runs on Linux..)..
  • for RAP Application, SWT is implemented with Qooxdoo Javascript widgets. The SWT implementation in RAP Application is called RWT (Rich Widget Toolkit). We will study it in the next article.

Download

You can download rap_step6.zip which contains the following explained projects :

  • org.akrogen.dynaresume.raphelloworld which is the generated Eclipse « RAP Hello World » explained in this article.

Add UI SWT Text/Label

In this section we will add the UI Text and Label to our RAP Application. In a RAP Application, UI Text, Label… widgets are managed with SWT API like RCP Application. The difference between RAP Application and RCP Application is the implementation of the SWT :

  • in RCP Application, SWT is implemented with the OS native widgets. For instance for Windows OS, org.eclipse.swt.win32.win32.x86 Plug-In is used.
  • in RCP Application, SWT is implemented with RWT which generates Javascript Qooxdoo widgets. org.eclipse.rap.rwt Plug-In is the SWT RAP widgets.

To add UI widgets in our RAP Application, we must (like RCP Application) :

  1. create a View which hosts SWT Text/Label.
  2. link the View to the default Perspective.

Create UserDetailView View

Creating the View consists of :

Declare View in the plugin.xml

Declare our view in the plugin.xml will be done like this :

<extension
      point="org.eclipse.ui.views">
   <view
         class="org.akrogen.dynaresume.raphelloworld.UserDetailView"
         id="org.akrogen.dynaresume.raphelloworld.userdetailview"
         name="User Detail View"
         restorable="true">
   </view>
</extension>

but it’s interesting to use PDE Tools to generate the View. To do that, open the org.akrogen.dynaresume.raphelloworld/plugin.xml, go to the Extrensions tab and click on Add… button of the All Extensions section :

This action opens the New Extension dialogue :

This dialogue shows you all the extension points that you can use in your RAP Application. In our case we must use org.eclipse.ui.views. To do that, type *view in the Extension Point filter, 2 (or more) extension points must appear :

Select org.eclipse.ui.views item and click on Finish button. This action add this extension :

If you go to the plugin.xml, you will see the new extension point :

Now we must link the View extension point to our View class. To do that select org.eclipse.ui.views node, click on the right mouse button to open the contextual menu and click on view node :

This action generates you the content of the org.eclipse.ui.views extension point :

Change fields values :

  • id field with org.akrogen.dynaresume.raphelloworld.userdetailview value.
  • name field with User Detail View value.
  • class field with org.akrogen.dynaresume.raphelloworld.UserDetailView value.

If you go to the plugin.xml, you will see the new extension point :

UserDetailView Class

In this section we will create the org.akrogen.dynaresume.raphelloworld.UserDetailView View class. Click on class* link :

This action opens the New Java Class wizard :

Click on Finish button, the wizard generates you org.akrogen.dynaresume.raphelloworld.UserDetailView class like this :

package org.akrogen.dynaresume.raphelloworld;

import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

public class UserDetailView extends ViewPart {

	public UserDetailView() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void createPartControl(Composite parent) {
		// TODO Auto-generated method stub

	}

	@Override
	public void setFocus() {
		// TODO Auto-generated method stub

	}

}

Link View with Perspective

Now we must link Perspective with the UserDetailView, the id org.akrogen.dynaresume.raphelloworld.userdetailview of the view declared in the plugin.xml will be used.

Modify UserDetailView

Modify the org.akrogen.dynaresume.raphelloworld.UserDetailView class to add the view ID in the Java code :

public static final String ID = "org.akrogen.dynaresume.raphelloworld.userdetailview";

Here is the full code of org.akrogen.dynaresume.raphelloworld.UserDetailView :

package org.akrogen.dynaresume.raphelloworld;

import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

public class UserDetailView extends ViewPart {

	public static final String ID = "org.akrogen.dynaresume.raphelloworld.userdetailview";
	
	public UserDetailView() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void createPartControl(Composite parent) {
		// TODO Auto-generated method stub

	}

	@Override
	public void setFocus() {
		// TODO Auto-generated method stub

	}

}

Modify Perspective

Modify org.akrogen.dynaresume.raphelloworld.Perspective like this :

package org.akrogen.dynaresume.raphelloworld;

import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;

/**
 * Configures the perspective layout. This class is contributed through the
 * plugin.xml.
 */
public class Perspective implements IPerspectiveFactory {

  public void createInitialLayout(IPageLayout layout) {
    String editorArea = layout.getEditorArea();
    layout.setEditorAreaVisible(false);
    layout.setFixed(true);

    layout.addStandaloneView(UserDetailView.ID, false, IPageLayout.LEFT,
        1.0f, editorArea);
  }
}

Here we have linked the view to the Perspective with Java code.

RWT Text/Label

At this step the Perspective hosts the UserDetailView View. Now we can add UI widgets to the View by implementing UserDetailView#createPartControl(Composite parent). When you want to manage UI with SWT you can use :

  • SWT widgets to displays Text, Label….
  • SWT layout to manage layout of the parent container of the widgets.
  • SWT layouts data to customize layout for a widgets which belongs to an host container.
  • SWT listener to add/remove listener to the widget if you want to observe some events of the widget (text changed, focus in/out…).

SWT widgets

SWT provides rich widgets which extend org.eclipse.swt.widgets.Widget (Text, Label, Tree, Table….). You can see the screen of SWT Widgets here.

In our case, implement UserDetailView#createPartControl(Composite parent) like this :

@Override
public void createPartControl(Composite parent) {
	// User name
	Label nameLabel = new Label(parent, SWT.NONE);
	nameLabel.setText("Name:");
	Text nameText = new Text(parent, SWT.BORDER);

	// User lastName
	Label lastNameLabel = new Label(parent, SWT.NONE);
	lastNameLabel.setText("Last name:");
	Text lastNameText = new Text(parent, SWT.BORDER);
}

The SWT.BORDER set a border for SWT Text.

Here is the full code of org.akrogen.dynaresume.raphelloworld.UserDetailView :

package org.akrogen.dynaresume.raphelloworld;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

public class UserDetailView extends ViewPart {

	public static final String ID = "org.akrogen.dynaresume.raphelloworld.userdetailview";
	
	public UserDetailView() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void createPartControl(Composite parent) {
		// User name
		Label nameLabel = new Label(parent, SWT.NONE);
		nameLabel.setText("Name:");
		Text nameText = new Text(parent, SWT.BORDER);

		// User lastName
		Label lastNameLabel = new Label(parent, SWT.NONE);
		lastNameLabel.setText("Last name:");
		Text lastNameText = new Text(parent, SWT.BORDER);

	}

	@Override
	public void setFocus() {
		// TODO Auto-generated method stub

	}

}

Launch the RAP Application and you will see our basic UI composed with RWT Text and Label :

This render is not very pretty because we didn’t use SWT Layout to position the widgets.

SWT Layout

In this section we will use SWT Layout to position as we want the SWT widgets Label and Text. All SWT Layouts extend the abstract org.eclipse.swt.widgets.Layout class.

I suggest you to read Understanding Layouts in SWT if you want to learn more about SWT Layout. The SWT Layout that I use is the org.eclipse.swt.layout.GridLayout which manages a lot of case. GridLayout can be compared to the layout used for HTML table. In this section we will use org.eclipse.swt.widgets.GridLayout to have this render :

Modify UserDetailView#createPartControl(Composite parent) like this :

@Override
public void createPartControl(Composite parent) {

	Composite composite = new Composite(parent, SWT.NONE);
	composite.setLayout(new GridLayout(2, false));

	// User name
	Label nameLabel = new Label(composite, SWT.NONE);
	nameLabel.setText("Name:");
	Text nameText = new Text(composite, SWT.BORDER);

	// User lastName
	Label lastNameLabel = new Label(composite, SWT.NONE);
	lastNameLabel.setText("Last name:");
	Text lastNameText = new Text(composite, SWT.BORDER);
}

It’s important to create a new Composite parent instead of using the Composite parent coming from createPartControl, because this last has already a layout (FillLayout). If you change the Layout of the Composite parent coming from createPartControl you could have some problems with SWT LayoutData ClassCastException (please see SWT Layout Data section).

Here is the full code of the org.akrogen.dynaresume.raphelloworld.UserDetailView :

package org.akrogen.dynaresume.raphelloworld;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

public class UserDetailView extends ViewPart {

	public static final String ID = "org.akrogen.dynaresume.raphelloworld.userdetailview";

	public UserDetailView() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void createPartControl(Composite parent) {

		Composite composite = new Composite(parent, SWT.NONE);
		composite.setLayout(new GridLayout(2, false));

		// User name
		Label nameLabel = new Label(composite, SWT.NONE);
		nameLabel.setText("Name:");
		Text nameText = new Text(composite, SWT.BORDER);

		// User lastName
		Label lastNameLabel = new Label(composite, SWT.NONE);
		lastNameLabel.setText("Last name:");
		Text lastNameText = new Text(composite, SWT.BORDER);
	}

	@Override
	public void setFocus() {
		// TODO Auto-generated method stub

	}

}

Launch the RAP Application and you will see our basic UI composed with RWT Text and Label :

SWT Layout Data

If you want to customize the layout for a widget, you must use Layout Data. A Layout Data is linked to the SWT Layout which is used for the Composite which hosts widgets. You cannot use for instance RowData in the widget where Composite parent use GridLayout. In our case we will use org.eclipse.swt.layout.GridData for SWT Text so those widgets will take the full space :

Modify UserDetailView#createPartControl(Composite parent) like this :

@Override
public void createPartControl(Composite parent) {

	Composite composite = new Composite(parent, SWT.NONE);
	composite.setLayout(new GridLayout(2, false));

	// User name
	Label nameLabel = new Label(composite, SWT.NONE);
	nameLabel.setText("Name:");
	Text nameText = new Text(composite, SWT.BORDER);
	nameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

	// User lastName
	Label lastNameLabel = new Label(composite, SWT.NONE);
	lastNameLabel.setText("Last name:");
	Text lastNameText = new Text(composite, SWT.BORDER);
	lastNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
}

Here is the full code of the org.akrogen.dynaresume.raphelloworld.UserDetailView :

package org.akrogen.dynaresume.raphelloworld;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

public class UserDetailView extends ViewPart {

	public static final String ID = "org.akrogen.dynaresume.raphelloworld.userdetailview";

	public UserDetailView() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void createPartControl(Composite parent) {

		Composite composite = new Composite(parent, SWT.NONE);
		composite.setLayout(new GridLayout(2, false));

		// User name
		Label nameLabel = new Label(composite, SWT.NONE);
		nameLabel.setText("Name:");
		Text nameText = new Text(composite, SWT.BORDER);
		nameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		// User lastName
		Label lastNameLabel = new Label(composite, SWT.NONE);
		lastNameLabel.setText("Last name:");
		Text lastNameText = new Text(composite, SWT.BORDER);
		lastNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
	}

	@Override
	public void setFocus() {
		// TODO Auto-generated method stub

	}

}

Launch the RAP Application and you will see our basic UI composed with RWT Text and Label :

SWT Listener

Sometimes you want to observe with listener the change of state of the widgets. This is done with SWT Listener. In our case, we will add a new Label on the top of the UI and display the Name+Last Name as soon as the user types a content in the SWT Text.

Modify org.akrogen.dynaresume.raphelloworld.UserDetailView class like this :

@Override
public void createPartControl(Composite parent) {

	Composite composite = new Composite(parent, SWT.NONE);
	composite.setLayout(new GridLayout(2, false));

	// User 
	final Label userLabel = new Label(composite, SWT.NONE);
	GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
	gridData.horizontalSpan = 2;
	userLabel.setLayoutData(gridData);
		
	// User name
	Label nameLabel = new Label(composite, SWT.NONE);
	nameLabel.setText("Name:");
	final Text nameText = new Text(composite, SWT.BORDER);
	nameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
	//nameText.setLayoutData(new GridData(SWT.FILL, 1, true, false));

	// User lastName
	Label lastNameLabel = new Label(composite, SWT.NONE);
	lastNameLabel.setText("Last name:");
	final Text lastNameText = new Text(composite, SWT.BORDER);
	lastNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		
	// Add Listener
	nameText.addModifyListener(new ModifyListener() {			
		@Override
		public void modifyText(ModifyEvent event) {
			userLabel.setText(nameText.getText() + " " + lastNameText.getText());
		}
	});
	// Add Listener
	lastNameText.addModifyListener(new ModifyListener() {			
		@Override
		public void modifyText(ModifyEvent event) {
			userLabel.setText(nameText.getText() + " " + lastNameText.getText());
		}
	});
}

You can notice that :

  • SWT Text are final because they are used in the inner class of the SWT event listener.
  • SWT Label User (first label) use gridData.horizontalSpan = 2; which shows you another case with SWT GridLayout which is enable to support span.

Here is the full code of org.akrogen.dynaresume.raphelloworld.UserDetailView :

package org.akrogen.dynaresume.raphelloworld;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

public class UserDetailView extends ViewPart {

	public static final String ID = "org.akrogen.dynaresume.raphelloworld.userdetailview";

	public UserDetailView() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void createPartControl(Composite parent) {

		Composite composite = new Composite(parent, SWT.NONE);
		composite.setLayout(new GridLayout(2, false));

		// User 
		final Label userLabel = new Label(composite, SWT.NONE);
		GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
		gridData.horizontalSpan = 2;
		userLabel.setLayoutData(gridData);
		
		// User name
		Label nameLabel = new Label(composite, SWT.NONE);
		nameLabel.setText("Name:");
		final Text nameText = new Text(composite, SWT.BORDER);
		nameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		//nameText.setLayoutData(new GridData(SWT.FILL, 1, true, false));

		// User lastName
		Label lastNameLabel = new Label(composite, SWT.NONE);
		lastNameLabel.setText("Last name:");
		final Text lastNameText = new Text(composite, SWT.BORDER);
		lastNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		
		// Add Listener
		nameText.addModifyListener(new ModifyListener() {			
			@Override
			public void modifyText(ModifyEvent event) {
				userLabel.setText(nameText.getText() + " " + lastNameText.getText());
			}
		});
		// Add Listener
		lastNameText.addModifyListener(new ModifyListener() {			
			@Override
			public void modifyText(ModifyEvent event) {
				userLabel.setText(nameText.getText() + " " + lastNameText.getText());
			}
		});
	}

	@Override
	public void setFocus() {
		// TODO Auto-generated method stub

	}

}

Launch the RAP Application and type content in the « Name » text widget:

You will see that the Label User is refreshed with SWT Text Name content. Type content in the « Last name » text widget: You will see that the Label User is refreshed with SWT Text Name+SWT Text « Last Name » content.

Conclusion

In this article we have seen how to manage UI in RAP Application with only Java code (RWT which is SWT implementation for RAP). RCP Application manage also UI with SWT, so it’s very easy to manage Single Sourcing to have with the same code a RCP/RAP Application.

Creating UI manually can be boring, but fortunately there is an Eclipse Plug-In WindowBuilder which provides SWT Designer to help you create UI with design way. WindowBuilder – SWT GridLayout section shows you how it’s possible to design UI with SWT GridLayout.

In the next article [step7] : create RAP Application with a view by using RAP 1.4, create RCP Application with a view and compare it with RAP Application.

Catégories :Eclipse RAP

Laisser un commentaire