Skip to main content
Jump to: navigation, search

Difference between revisions of "OTExample Stopwatch"

(layout issues, mostly tweaking the css for Geshi)
Line 1: Line 1:
In a running [[Object Teams Development Tooling|OTDT]] you can easily import
+
<css>
this project into your workspace using this menu path:
+
.source-java span.kw1 {color: #7F0055; font-weight: bold;}
New > Example > Object Teams > Stop Watch Example
+
.source-java span.kw2 {color: #7F0055; font-weight: bold;}
 +
.source-java span.kw3 {color: #000000; font-weight: normal;}
 +
.source-java span.kw4 {color: #7F0055; font-weight: bold;}
 +
.source-java span.co1 {color: #3F7F5F; font-style:normal;}
 +
.source-java span.co2 {color: #3F7F5F; font-style:normal;}
 +
.source-java span.coMULTI {color: #3F5FBF; font-style:normal;}
 +
.source-java span.es0 {color: #000000;}
 +
.source-java span.br0 {color: #000000;}
 +
.source-java span.st0 {color: #2A00ff;}
 +
.source-java span.nu0 {color: #000000;}
 +
.source-java span.me1 {color: #000000; font-style:italic;}
 +
.source-java span.me2 {color: #000000; font-style:italic;}
 +
/* reduce font-size for all listings: */
 +
div.source-java {font-size:small; !important;}
 +
pre.source-java {font-size:small; !important;}
 +
/* reset font for numbered listings: */
 +
div.source-java div.de1 { font-family:monospace;}
 +
div.source-java div.de2 { font-family:monospace;}
 +
/* restore box for numbered listings, which doesn't use pre: */
 +
.source-java { border:#2F6FAB 1px dashed; background-color:#F9F9F9; padding:4px; }
 +
</css>
 +
{{tip|Try it live:|
 +
In a running [[Object Teams Development Tooling|OTDT]] you can easily import this project into your workspace using this menu path:<pre>New > Example > Object Teams > Stop Watch Example</pre>
 +
}}
  
The Stopwatch example shows the most simple Model View Controller architecture
+
'''The Stopwatch example shows the most simple Model View Controller architecture using OT/J.'''
using OT/J. It contains basically of two classes:
+
  
'''Stopwatch (Model)'''
+
It consists basically of two classes:
 +
 
 +
==== 1. Stopwatch (Model)====
 
<source lang="java" enclose="div">
 
<source lang="java" enclose="div">
 
public class StopWatch implements Runnable {
 
public class StopWatch implements Runnable {
Line 84: Line 108:
 
about display of any kind.
 
about display of any kind.
  
Now for class '''WatchUI (combined View and Controller)''':
+
==== 2. Now for class '''WatchUI (combined View and Controller):====
<source lang="java" line="GESHI_NORMAL_LINE_NUMBERS" enclose="pre">
+
<source lang="java" line="1">
 
public team class WatchUI {
 
public team class WatchUI {
 
     static int ypos = 150;
 
     static int ypos = 150;
Line 167: Line 191:
 
 
 
// Callin method bindings: WatchDisplay (role object) is updated
 
// Callin method bindings: WatchDisplay (role object) is updated
// after the StopWatch (base object) advanced or was reset.
+
// after the StopWatch (base object) advanced or was reset.  
 
  void update() <- after void advance();
 
  void update() <- after void advance();
 
  void update()        <- after void reset();
 
  void update()        <- after void reset();
Line 182: Line 206:
 
</source>
 
</source>
  
'''What you see in this class'''
+
<div style="font-weight:bold;margin-top:15px;margin-bottom:-2px;">What you see in this class:</div>
 
* It's a '''team''' class (l.1)
 
* It's a '''team''' class (l.1)
 
* It declares a '''role''' <tt>WatchDisplay extends JFrame '''playedBy''' StopWatch</tt> (l.9)
 
* It declares a '''role''' <tt>WatchDisplay extends JFrame '''playedBy''' StopWatch</tt> (l.9)
Line 199: Line 223:
 
** The constructor furthermore '''activates the team''' so that it indeed receives triggers via its '''callin''' bindings.
 
** The constructor furthermore '''activates the team''' so that it indeed receives triggers via its '''callin''' bindings.
  
The program is starting using this tiny '''Main''':
+
 
 +
==== 3. The program is started using this tiny '''Main''':====
 
<source lang="java">
 
<source lang="java">
 
public class Main {
 
public class Main {
Line 208: Line 233:
 
}
 
}
 
</source>
 
</source>
We create both a model and a view, passing the model to the view where it will be decorated with a role.
+
We create both a model and a view, passing the model to the view where it will be decorated with a role, which in turn opens the UI.
  
The version shipped with the OTDT additionally bring an AnalogWatch in order to show how
+
''The version shipped with the OTDT additionally bring an AnalogWatch in order to show how
 
different views are connected to the same model. However, no further OT/J constructs or patterns
 
different views are connected to the same model. However, no further OT/J constructs or patterns
are used for this.
+
are used for this.''
  
 
[[Category:Object Teams]]
 
[[Category:Object Teams]]
 
[[Category:Object Teams Examples]]
 
[[Category:Object Teams Examples]]

Revision as of 15:36, 14 February 2010

Idea.png
Try it live:
In a running OTDT you can easily import this project into your workspace using this menu path:
New > Example > Object Teams > Stop Watch Example


The Stopwatch example shows the most simple Model View Controller architecture using OT/J.

It consists basically of two classes:

1. Stopwatch (Model)

public class StopWatch implements Runnable {

        /** Current time value */
        private int time = 0;

        /** Flag that indicates if the watch is running */
        private boolean running;

        /** Flag that indicates if there is a stop request */
        private boolean stopRequest;

        /** Increases the time value. */
        private synchronized void advance() {
                time++;
        }

        /** Starts the watch thread. */
        public synchronized void start() {
                if (!running) {
                        setRunning(true);
                        setStopped(false);
                        (new Thread(this)).start();
                }
        }

        /** Stops the watch thread. */
        public synchronized void stop() {
                setStopped(true);
        }

        /** Resets the time value. */
        public synchronized void reset() {
                time = 0;
        }

        /** Returns the current time value. */
        public synchronized int getValue() {
                return time;
        }

        /** Sets the running flag value. */
        private synchronized void setRunning(boolean value) {
                running = value;
        }

        /** Returns the stop flag value */
        private synchronized boolean isStopped() {
                return stopRequest;
        }

        /** Sets the stop flag value */
        private synchronized void setStopped(boolean value) {
                stopRequest = value;
        }

        /** This method contains the main loop that is executed while the watch is running. */
        public void run() {
                while (true) {
                        try {
                                Thread.sleep(1000);
                        } catch (InterruptedException e) {
                                setRunning(false);
                                return;
                        }
                        if (isStopped()) {
                                setRunning(false);
                                return;
                        }
                        advance();
                }
        }
}

This pure Java class only implements the functionality of a stopwatch with no thought whatsoever about display of any kind.

2. Now for class WatchUI (combined View and Controller):

  1. public team class WatchUI {
  2.     static int ypos = 150;
  3.  
  4.     /**
  5.      * Role class WatchDisplay is played by the base class StopWatch. The role
  6.      * class WatchDisplay is bound to the base class StopWatch with the keyowrd
  7.      * 'playedBy'.
  8.      */
  9.     protected class WatchDisplay extends JFrame playedBy StopWatch 
  10.     {
  11. 	private JTextField display;
  12. 	private JButton startButton;
  13. 	private JButton stopButton;
  14. 	private JButton clearButton;
  15.  
  16. 	/**
  17. 	 * This constructor is used for automatic role creation. E.g. via
  18. 	 * declared lifting. Role class constructor takes an object of the type
  19. 	 * of the declared base class. Setup the window, create a textfield for
  20. 	 * time display and three buttons "start", "stop", and "clear".
  21. 	 */
  22. 	public WatchDisplay(StopWatch w) {
  23. 		setTitle("Digital Stop Watch");
  24. 		setSize(new Dimension(300, 100));
  25. 		setLocation(410, ypos+=110);
  26. 		Container pane = getContentPane();
  27. 		pane.setLayout(new GridLayout(2,3));
  28. 		pane.add(new JLabel(""));
  29. 		display = new JTextField("0", 8);
  30. 		display.setHorizontalAlignment(JTextField.RIGHT);
  31. 		pane.add(display);
  32. 		pane.add(new JLabel(""));
  33. 		startButton = new JButton("start");
  34. 		startButton.addActionListener(new ActionListener() {
  35. 			public void actionPerformed(ActionEvent e) {
  36. 				start();
  37. 			}});
  38. 		pane.add(startButton);
  39. 		stopButton = new JButton("stop");
  40. 		stopButton.addActionListener(new ActionListener() {
  41. 			public void actionPerformed(ActionEvent e) {
  42. 				stop();
  43. 			}});
  44. 		pane.add(stopButton);
  45. 		clearButton = new JButton("clear");
  46. 		clearButton.addActionListener(new ActionListener() {
  47. 			public void actionPerformed(ActionEvent e) {
  48. 				clear();
  49. 			}});
  50. 		pane.add(clearButton);
  51. 		setVisible(true);
  52. 	}		
  53.  
  54. 	/**
  55. 	 * Shows the new time value on the watch display.
  56. 	 */
  57. 	void update() {
  58. 	    String val = getStringValue();
  59. 	    display.setText(val);
  60. 	}
  61.  
  62. 	// Abstract methods for mapping to the concrete base methods:
  63. 	abstract void   start();
  64. 	abstract void   stop();
  65. 	abstract void   clear();
  66. 	abstract String getStringValue();
  67.  
  68.        // callout method bindings: any call of the abstract WatchDisplay
  69.        // method will be forwarded to the concrete StopWatch method
  70. 	       start            ->       start;
  71. 	       stop             ->       stop;
  72. 	       clear            ->       reset;
  73. 	String getStringValue()	-> int   getValue() 
  74. 	    with {
  75. 		    // result is a predefined name.
  76. 		    result      <-   Integer.toString(result)
  77. 	    }
  78.  
  79. 	/* -------------------------------------------------------------- */
  80.  
  81. 	// Callin method bindings: WatchDisplay (role object) is updated
  82. 	// after the StopWatch (base object) advanced or was reset. 
  83. 	   void update()	<- after void advance();
  84. 	   void update()        <- after void reset();
  85.     }
  86.  
  87.     /**
  88.      * The team constructor uses declared lifting. A WatchDisplay role is
  89.      * created for the given StopWatch object.
  90.      */
  91.     public WatchUI (StopWatch as WatchDisplay w) {
  92.     	activate(ALL_THREADS); // Without this, the callin bindings have no effect.
  93.     }
  94. }
What you see in this class:
  • It's a team class (l.1)
  • It declares a role WatchDisplay extends JFrame playedBy StopWatch (l.9)
  • The role's constructor uses normal Swing programming to create a little UI (ll.22-52)
    • The buttons in this UI are connected to methods start,stop,clear (ll.36,42,48)
    • These methods are declared abstractly (ll.63-65)
  • A little update method sets the display text to whatever the abstract method getStringValue returns (ll.57-60,66)
  • The UI is connected to the Model only be a set of method bindings:
    • callout method bindings make corresponding methods of StopWatch accessible within WatchDisplay (ll.68-77)
    • thanks to these bindings these methods are no longer abstract
      • clear and getStringValue are mapped to method with different names in the base class (ll.72,73)
      • the parameter mapping for getStringValue additionally converts the provided int into a String (ll.74-77)
    • callin method bindings set the triggers when the display should be updated (ll.81-84)
  • The team's constructor receives a base object (StopWatch) which is automatically lifted to its WatchDisplay role before method entry (keyword as) (l.91)
    • By lifting the lifting constructor (l.22) is invoked which puts up the UI
    • The constructor furthermore activates the team so that it indeed receives triggers via its callin bindings.


3. The program is started using this tiny Main:

public class Main {
    public static void main(String[] args) {
	StopWatch w = new StopWatch();
	new WatchUI(w);
    }
}

We create both a model and a view, passing the model to the view where it will be decorated with a role, which in turn opens the UI.

The version shipped with the OTDT additionally bring an AnalogWatch in order to show how different views are connected to the same model. However, no further OT/J constructs or patterns are used for this.

Back to the top