Saturday, May 22, 2010

Add a Toolbar to a View in an Eclipse RCP Application

This article shows how to add a toolbar to a View and builds off of a clean RCP Application with a View. The full source code is found at the end of the article. Eclipse RCP applications such as the Eclipse IDE, can have a drop down menu and/or, as demonstrated here, a toolbar located at the top of any View. With just a few lines of code you can easily add an icon to a View's toolbar and have it activate an Action when clicked.

Step 0: Create a RCP Application with a View.

Step 1: Create an Action that defines what will happen when the icon in the toolbar is clicked. Make a new class that extends org.eclipse.jface.action.Action and implements IWorkbenchAction. The class needs a private static final String property used to set the ID in the constructor. Inside the run() method is where you put your custom code. In this "CustomAction" example, code is added to the run() method that opens up a JFace MessageDialog box using a handy static convenience method of the MessageDialog class.
package com.eclipsercptutorials.addviewtoolbar;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;

public class CustomAction extends Action implements IWorkbenchAction{

private static final String ID = "com.timmolter.helloWorld.CustomAction";

public CustomAction(){
setId(ID);
}

public void run() {

Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
String dialogBoxTitle = "Message";
String message = "You clicked something!";
MessageDialog.openInformation(shell, dialogBoxTitle, message);

}

public void dispose() {}

}



Step 2:Add the toolbar with its Action and icon to the View. In the View's createPartControl method new-up the Action, and set the Action's tool-tip text and icon. In this example, a .png icon image called "bomb.png" was added to the icons folder in the plugin project. To find out where to find nice icons for Eclipse RCP projects see: Add an Icon to an Eclipse RCP Application View. Add the Action to the View's ToolBarManager using the getViewSite().getActionBars().getToolBarManager().add(lCustomAction) method.
package com.eclipsercptutorials.addviewtoolbar;

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

public class MainView extends ViewPart {

public static final String ID = "com.eclipsercptutorials.addViewToolBar.MainView"; // the ID needs to match the id set in the view's properties

public MainView() { }

public void createPartControl(Composite parent) {

// Custom Action for the View's Menu
CustomAction lCustomAction = new CustomAction();
lCustomAction.setText("Open Dialog Box");
lCustomAction.setImageDescriptor(Activator.getImageDescriptor("icons/bomb.png"));
getViewSite().getActionBars().getToolBarManager().add(lCustomAction);

}

public void setFocus() { }

}

Step 3: Run the application and test if everything worked. Your application should now have a View with an icon in the View's toolbar, which opens up a MessageDialog when clicked. If you're not seeing it, nor the View's tab and title for that matter, make sure you specify that the title of the View should be shown in the layout.addStandaloneView() method of the Perspective's createInitialLayout() method - the second argument of the addStandaloneView() should be set to true.
package com.eclipsercptutorials.addviewtoolbar;

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

public class Perspective implements IPerspectiveFactory {

public void createInitialLayout(IPageLayout layout) {

layout.addStandaloneView(MainView.ID, true, IPageLayout.LEFT, 1.0f, layout.getEditorArea());
layout.setEditorAreaVisible(false); //hide the editor in the perspective

}
}




Piece of Cake!!

<--- Previous - Animation in Eclipse RCP Applications - A Bouncing Ball
---> Next - Add a Menu to a View in an Eclipse RCP Application
Also see: Eclipse RCP Tutorial Table of Contents

Wednesday, May 12, 2010

Animation in Eclipse RCP Applications - A Bouncing Ball

This article shows how to add animation to an Eclipse RCP Application and builds off of a clean RCP Application with a View. To demonstrate the animation, code is created that makes an image of the moon bounce around the view, using real physics equations to control the acceleration and spin. If you want a more in depth explanation of adding an image or updating the GUI from a worker thread please see the previous articles: Add an Image to an Eclipse RCP Application and Updating a Widget in an Eclipse RCP Application from a Worker Thread.

Step 0: Create a Hello World with Eclipse RCP Application and add a View to it.

Step 1: Add an Image to the view . For this tutorial, an image of the moon with a transparent background called moon.png was prepared and added to the project.





Step 2: Create an inner class that implements Runnable, that updates the contents of the view at a regular interval. Later, during the initialization of the view, this worker thread is started, which calls the update() method of the view every ~15 milliseconds. The speed of the animation can be controlled by the TIMER_INTERVAL variable, which defines how long the thread should sleep before waking up and calling the update() method again.
class AnimatorThread implements Runnable{

// The timer interval in milliseconds
private static final int   TIMER_INTERVAL = 14;

public void go(){

Thread t = new Thread(this);
t.start();

}

public void run() {
try {
while(true){
animate();
Thread.sleep(TIMER_INTERVAL);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


Step 3: Create the view's contents and start the worker thread. In the createPartControl() method of the view, create a Canvas where the image will be painted. Set the canvas's background color and add a paintListener to it with code defining where the image of the moon should be painted. Finally, new up the worker thread class and start it.

public void createPartControl(Composite parent) {

parent.setBackground(new Color(parent.getDisplay(), 205, 38, 38));

// Create the canvas for drawing
canvas = new Canvas(parent, SWT.DOUBLE_BUFFERED);
canvas.setBackground(new Color(parent.getDisplay(), 0,0,0));
canvas.addPaintListener( new PaintListener() {

public void paintControl(PaintEvent e) {

GC gc = e.gc;
Transform trans = new Transform(e.display );
gc.getTransform( trans );
trans.translate( x, y );
trans.translate( IMAGE_WIDTH / 2f, IMAGE_WIDTH / 2f );
trans.rotate( a );
trans.translate( -IMAGE_WIDTH / 2f, -IMAGE_WIDTH / 2f );
gc.setTransform( trans );
trans.dispose();

gc.drawImage( moon, 0, 0, moon.getBounds().width, moon.getBounds().height, 0, 0, IMAGE_WIDTH, IMAGE_WIDTH); // Draw the moon

}
});

AnimatorThread at = new AnimatorThread();
at.go();
}


Step 4: Create the physics for the bouncing of the ball. Add some constants and variables as private members of the view class and an animate() method which calculates the next position of the moon. Last but not least, force a redraw of the canvas at the end of the animate() method. This invokes the code that was defined in the canvas's PaintListener.

public void animate() {

Display.getDefault().asyncExec(new Runnable(){

public void run(){

try{

float left = x;
float top = y;

// Determine the ball's location
directionY += GRAVITY;
x += directionX;
y += directionY;
a += directionA;

// Determine out of bounds
Rectangle rect = canvas.getClientArea();
if ( x > rect.width - IMAGE_WIDTH ) {
x = rect.width - IMAGE_WIDTH;
directionX = -directionX;
directionA -= ( directionY - directionA ) * FRICTION_WALL;
}
if ( x < 0 ) {
x = 0;
directionX = -directionX;
directionA += ( directionY - directionA ) * FRICTION_WALL;
}

if ( y > rect.height - IMAGE_WIDTH ) {
directionY = (int) ( -GRAVITY * Math.sqrt( ( 1 + 8 * ( rect.height - IMAGE_WIDTH ) / GRAVITY ) ) / 2 );
y = rect.height - IMAGE_WIDTH;
directionA += ( directionX - directionA ) * FRICTION_FLOOR;
}

float right = left + IMAGE_WIDTH;
float bottom = top + IMAGE_WIDTH;
if ( x < left )
left = x;
else
right = x + IMAGE_WIDTH;
if ( y < top )
top = y;
else
bottom = y + IMAGE_WIDTH;

// Force a redraw
canvas.redraw( (int) Math.floor( left ) - 1, (int) Math.floor( top ) - 1, (int) ( Math.ceil( right ) - Math.floor( left ) ) + 2, (int) ( Math.ceil( bottom ) - Math.floor( top ) ) + 2, false );

}catch(SWTException e){
//eat it!
}
}
});

}
Step 5: Run the application and test if everything worked. Your application should now have an image of the moon in the view that bounces back and forth across the view. As you resize the view, the moon's boundaries are recalculated. Here's the full code of the view:
package com.eclipsercptutorials.animation;

import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Transform;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.part.ViewPart;

public class MainView extends ViewPart {

public static final String ID = "com.eclipsercptutorials.animation.mainView"; // the ID needs to match the id set in the view's properties

// The image
private Image moon;

// The image width
private static int IMAGE_WIDTH = 85;

// Rate of downward acceleration per frame
private static final float GRAVITY        = .25f;

// Coefficient of friction
private static final float FRICTION_FLOOR = 5f / 9f;
private static final float FRICTION_WALL  = 5f / 11f;

// The location of the "ball"
private float              x              = 0;
private float              y              = 0;
private float              a              = 0;

// The direction the "ball" is moving
private float              directionX     = 4;
private float              directionY     = 0;
private float              directionA     = 0;

// We draw everything on this canvas
private Canvas             canvas;

public MainView() {

moon = Activator.getImageDescriptor("icons/moon.png").createImage();

}

public void createPartControl(Composite parent) {

parent.setBackground(new Color(parent.getDisplay(), 205, 38, 38));

// Create the canvas for drawing
canvas = new Canvas(parent, SWT.DOUBLE_BUFFERED);
canvas.setBackground(new Color(parent.getDisplay(), 0,0,0));
canvas.addPaintListener( new PaintListener() {

public void paintControl(PaintEvent e) {

GC gc = e.gc;
Transform trans = new Transform(e.display );
gc.getTransform( trans );
trans.translate( x, y );
trans.translate( IMAGE_WIDTH / 2f, IMAGE_WIDTH / 2f );
trans.rotate( a );
trans.translate( -IMAGE_WIDTH / 2f, -IMAGE_WIDTH / 2f );
gc.setTransform( trans );
trans.dispose();

gc.drawImage( moon, 0, 0, moon.getBounds().width, moon.getBounds().height, 0, 0, IMAGE_WIDTH, IMAGE_WIDTH); // Draw the moon

}
});

AnimatorThread at = new AnimatorThread();
at.go();
}

public void animate() {

Display.getDefault().asyncExec(new Runnable(){

public void run(){

try{

float left = x;
float top = y;

// Determine the ball's location
directionY += GRAVITY;
x += directionX;
y += directionY;
a += directionA;

// Determine out of bounds
Rectangle rect = canvas.getClientArea();
if ( x > rect.width - IMAGE_WIDTH ) {
x = rect.width - IMAGE_WIDTH;
directionX = -directionX;
directionA -= ( directionY - directionA ) * FRICTION_WALL;
}
if ( x < 0 ) {
x = 0;
directionX = -directionX;
directionA += ( directionY - directionA ) * FRICTION_WALL;
}

if ( y > rect.height - IMAGE_WIDTH ) {
directionY = (int) ( -GRAVITY * Math.sqrt( ( 1 + 8 * ( rect.height - IMAGE_WIDTH ) / GRAVITY ) ) / 2 );
y = rect.height - IMAGE_WIDTH;
directionA += ( directionX - directionA ) * FRICTION_FLOOR;
}

float right = left + IMAGE_WIDTH;
float bottom = top + IMAGE_WIDTH;
if ( x < left )
left = x;
else
right = x + IMAGE_WIDTH;
if ( y < top )
top = y;
else
bottom = y + IMAGE_WIDTH;

// Force a redraw
canvas.redraw( (int) Math.floor( left ) - 1, (int) Math.floor( top ) - 1, (int) ( Math.ceil( right ) - Math.floor( left ) ) + 2, (int) ( Math.ceil( bottom ) - Math.floor( top ) ) + 2, false );

}catch(SWTException e){
//eat it!
}
}
});

}


public void setFocus() {}

class AnimatorThread implements Runnable{

// The timer interval in milliseconds
private static final int   TIMER_INTERVAL = 14;

public void go(){

Thread t = new Thread(this);
t.start();

}

public void run() {
try {
while(true){
animate();
Thread.sleep(TIMER_INTERVAL);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


Piece of Cake!! <--- Previous - Updating a Widget in an Eclipse RCP Application from a Worker Thread ---> Next - Add a Toolbar to a View in an Eclipse RCP Application Also see: Eclipse RCP Tutorial Table of Contents

Tuesday, May 4, 2010

Create a String Date from a Date Object in Java

To create a Date String from a java.util.Date Object we can use the SimpleDateFormat class to convert from a Date to String. The following code example demonstrates creating a Date String from a Date Object using several different SimpleDateFormat formatting String patterns.

import java.text.SimpleDateFormat;
import java.util.Date;

public class CreateDateStringFromDate {


public static void main(String[] args) {

Date now = new Date();

SimpleDateFormat s = new SimpleDateFormat("ddMMyyyy");
System.out.println(s.format(now));

s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(s.format(now));

s = new SimpleDateFormat("yyyy/MM/dd");
System.out.println(s.format(now));

s = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(s.format(now));

s = new SimpleDateFormat("dd.MM.yyyy");
System.out.println(s.format(now));

s = new SimpleDateFormat("MMddyyyy");
System.out.println(s.format(now));

}

}




Here is the output of the example code:
23062010
2010-06-23 17:30:53
2010/06/23
2010-06-23
23.06.2010
06232010