Implementation

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.

SWTClock class

To implement the SWTClock class:

  1. Create the SWTClock.java class file.

  2. 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;
  3. 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;
  4. 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();
              }
          }
      }

eSWT MIDlet starter

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.