For information about the design and functionality of the MIDlet, see section Design.
The MIDlet consists of the SWTClock
class, which
is the main class and implements both the analog clock and start-up
screen, and an eSWT MIDlet starter, which creates the eSWT UI thread and
also manages the MIDlet lifecycle.
To implement the SWTClock
class:
Create the SWTClock.java
class file.
Import the required classes.
import java.util.Calendar; import java.util.Timer; import java.util.TimerTask; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Display; import org.eclipse.ercp.swt.mobile.MobileShell;
Set SWTClock
to extend SWTMIDlet
. Create the
required variables.
public class SWTClock extends SWTMIDlet { Display display; MobileShell shell; Canvas canvas; Button exitButton; int exitButtonH; int h = -1; Image imgClock; Point imgClockSize; Image imgExit; Image imgH; Point imgHSize; Image imgM; Point imgMSize; Image imgS; Point imgSSize; int m = -1; int s = -1;
Implement the application logic and rendering:
The runUI
method sets up the layout for the
main view. First, the method sets the Shell
to full
screen, and then it sets the methods for drawing and destroying the Canvas
. Finally, the method sets up the exit button, timer,
and a listener to listen for changes in the device orientation.
protected void runUI(Display display) { this.display = display; shell = new MobileShell(display); shell.setFullScreenMode(true); // Create the clock image imgClock = new Image(display, getClass().getResourceAsStream( "/clock.png")); Rectangle r = imgClock.getBounds(); imgClockSize = new Point(r.width, r.height); // Create the Canvas which will draw the clock. canvas = new Canvas(shell, SWT.NONE); canvas.addPaintListener(new PaintListener() { public void paintControl(PaintEvent e) { Rectangle r = canvas.getClientArea(); if (imgClock != null) { e.gc.drawImage(imgClock, (r.width - imgClockSize.x) / 2, (r.height - imgClockSize.y) / 2); } if (imgH != null) { e.gc.drawImage(imgH, (r.width - imgHSize.x) / 2, (r.height - imgHSize.y) / 2); } if (imgM != null) { e.gc.drawImage(imgM, (r.width - imgMSize.x) / 2, (r.height - imgMSize.y) / 2); } if (imgS != null) { e.gc.drawImage(imgS, (r.width - imgSSize.x) / 2, (r.height - imgSSize.y) / 2); } } }); canvas.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { disposeResources(); } }); // Create the exit Button. imgExit = new Image(display, getClass().getResourceAsStream("/exit.png")); exitButton = new Button(shell, SWT.PUSH); exitButton.setImage(imgExit); exitButton.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { } public void widgetSelected(SelectionEvent e) { exit(); } }); exitButtonH = exitButton.computeSize(-1, -1).y; // Layout everything while hidden, then show the app. layout(); shell.open(); // For the benefit of the automatic start screen, produce the first // drawn screen without the arms. flush(); // Start the timer that will repeatedly request a redraw every second. Timer t = new Timer(); t.scheduleAtFixedRate(new TimerTask() { public void run() { try { SWTClock.this.display.syncExec(new Runnable() { public void run() { update(); } }); } catch (Exception e) { e.printStackTrace(); } } }, 0, 1000); // Start listening to UI orientation changes for layout updates. shell.addControlListener(new ControlListener() { public void controlMoved(ControlEvent e) { } public void controlResized(ControlEvent e) { layout(); } }); } private void disposeResources() { if (imgClock != null) { imgClock.dispose(); } if (imgExit != null) { imgExit.dispose(); } if (imgH != null) { imgH.dispose(); } if (imgM != null) { imgM.dispose(); } if (imgS != null) { imgS.dispose(); } } private void flush() { while (display.readAndDispatch()) ; }
The layout
method re-sizes the elements on
the screen after the resolution has changed (usually due to an orientation
change).
private void layout() { Rectangle rect = shell.getClientArea(); if (rect.width < rect.height) { canvas.setSize(rect.width, rect.height - exitButtonH); exitButton.setBounds(0, rect.height - exitButtonH, rect.width, exitButtonH); } else { canvas.setSize(rect.width - exitButtonH, rect.height); exitButton.setBounds(rect.width - exitButtonH, 0, exitButtonH, rect.height); } }
The update
method is called every second,
and it modifies the elements in the view to correspond to the new
time. It does this by replacing images that are no longer correct.
private void update() { if (canvas == null || canvas.isDisposed()) { return; } Calendar cal = Calendar.getInstance(); int m = cal.get(Calendar.MINUTE); int h = cal.get(Calendar.HOUR); if (h == 12) { h = 0; } h = h * 5 + m / 12; if (h == 60) { h = 0; } int s = cal.get(Calendar.SECOND); boolean changed = false; if (this.h != h) { this.h = h; if (imgH != null) { imgH.dispose(); } imgH = new Image(display, getClass().getResourceAsStream( "/h" + h + ".png")); if (imgHSize == null) { Rectangle r = imgH.getBounds(); imgHSize = new Point(r.width, r.height); } changed = true; } if (this.m != m) { this.m = m; if (imgM != null) { imgM.dispose(); } imgM = new Image(display, getClass().getResourceAsStream( "/m" + m + ".png")); if (imgMSize == null) { Rectangle r = imgM.getBounds(); imgMSize = new Point(r.width, r.height); } changed = true; } if (this.s != s) { this.s = s; if (imgS != null) { imgS.dispose(); } imgS = new Image(display, getClass().getResourceAsStream( "/s" + s + ".png")); if (imgSSize == null) { Rectangle r = imgS.getBounds(); imgSSize = new Point(r.width, r.height); } changed = true; } if (changed) { canvas.redraw(); } } }
To make developing eSWT MIDlets faster and
easier, the Java Developer's Library provides an eSWT MIDlet starter,
consisting of two classes, which you can use as a basis for implementing
MIDlets with eSWT UIs. The starter creates the eSWT UI thread and
also manages the MIDlet lifecycle for you. If supported by the device,
the starter uses the org.eclipse.ercp.swt.midp.UIThreadSupport
class to safely obtain a platform-optimized thread for the eSWT
UI. Otherwise, the starter creates a random thread for the UI.