Implementing methods for Stopwatch
Now, you must implement one public instance method and fifteen private instance methods for Stopwatch. You can implement them in any order.
Method open
For this example, begin by implementing open, which calls methods that define the user interface:
1. Ensure that Stopwatch is selected.
2. Verify that the settings in the browser are for viewing private instance methods. Add the method category Startup.
3. With Startup highlighted, select New Method Template from the Methods menu.
4. Revise the displayed template so it includes the following:
open
"Public - Create and realize the receiver."
self
createShell;
createWindow;
realizeWindow.
5. Save the method. If you typed in the text shown above, open is shown in the list of methods.
Now, define the private instance methods. The following two methods go into the Getters & Setters category and are used for displaying the elapsed time:
Method timeElapsedDisplay:
timeElapsedDisplay: aTextWidget
"Private - Sets the timeElapsedDisplay for the receiver."
timeElapsedDisplay := aTextWidget.
Method timeElapsedDisplay
timeElapsedDisplay
"Private - Answers the timeElapsedDisplay for the receiver."
^timeElapsedDisplay.
The following eleven methods go into the Window Creation category:
Method createWindow
createWindow
"Private - Create the stopwatch. The outside window is 'shell.'
The form that manages layout of widgets is 'widgetManager.'
The time widgets ('label' and 'timeDisplay') are on the top.
The buttons ('startButton' and 'stopButton') are on the bottom."
self createTopLevelShell.
self createForm.
self createTimeWidgets.
self createLabel.
self createButtons.
self createStartButton.
self createStopButton.
self manageChildren.
self timeElapsedDisplay: timeDisplay.
Method createTopLevelShell
createTopLevelShell
"Private - Creates a window."
shell := CwTopLevelShell
createApplicationShell: 'shell'
argBlock: nil.
shell title: 'Stopwatch'.
Method createShell
createShell
"Private - Creates a shell for aWidget."
shell :=
CwTopLevelShell
appCreateShell: self class name
applicationClass: CwAppContext defaultApplicationClass
display: CgDisplay default
argBlock: nil.
Method createForm
createForm
"Private - Creates a form to hold user interface elements."
widgetManager := shell
createForm: 'widgetManager'
argBlock: nil.
widgetManager manageChild.
Method createTimeWidgets
createTimeWidgets
"Private - Controls placement of the label and text pane."
timeWidgets := widgetManager
createRowColumn: 'timeWidgets'
argBlock: [:w | w
orientation: XmHORIZONTAL;
marginHeight: 20;
marginWidth: 5;
rightAttachment: XmATTACHFORM;
topAttachment: XmATTACHFORM].
Method createLabel
createLabel
"Private - Creates a label."
label := timeWidgets
createLabel: 'label'
argBlock: [:w | w labelString: 'Time elapsed:'].
timeDisplay := timeWidgets "Define a text pane."
createText: 'timeDisplay'
argBlock: [:w | w width: 190].
timeDisplay setString: 'Hours:Minutes:Seconds'.
Method createButtons
createButtons
"Private - Control positioning of the buttons."
buttons := widgetManager
createRowColumn: 'buttons'
argBlock: [:w | w
orientation: XmHORIZONTAL;
spacing: 15;
marginWidth: 12;
topAttachment: XmATTACHWIDGET;
topWidget: timeWidgets;
leftAttachment: XmATTACHFORM;
rightAttachment: XmATTACHFORM;
bottomAttachment: XmATTACHFORM].
Method createStartButton
createStartButton
"Private - Create the Start button."
startButton := buttons
createPushButton: ' Start '
argBlock: nil.
startButton
addEventHandler: ButtonReleaseMask
receiver: self
selector: #startButtonMotion:clientData:callData:
clientData: startButton.
Method createStopButton
createStopButton
"Private - Create the Stop button."
stopButton := buttons
createPushButton: ' Stop/Interval '
argBlock: nil.
stopButton
addEventHandler: ButtonReleaseMask
receiver: self
selector: #stopButtonMotion:clientData:callData:
clientData: stopButton.
Method manageChildren
manageChildren
"Private - Places the widgets."
timeWidgets manageChild.
label manageChild.
timeDisplay manageChild.
buttons manageChild.
startButton manageChild.
stopButton manageChild.
Method realizeWindow
realizeWindow
"Private - Realizes the receiver's widget hierarchy."
shell realizeWidget.
At this point, you can open an instance of Stopwatch by evaluating the following in a Transcript or Workspace window:
Stopwatch new open
The window should resemble the following:
Note that when you select a push button, a debugger opens. To change this behavior, finish implementing the methods. The following two methods go into the category Event Handlers:
Method startButtonMotion:clientData:callData:
startButtonMotion: aButton clientData: aRowColumn callData: callData
"Private - The user pressed the Start button. Display the time elapsed."
startTime := Time now.
self timeElapsedDisplay
setString: ' 00:00:00'. "12 spaces between ' and 00"
Implementing this method enables
Stopwatch to display the following after you select
Start:
Method stopButtonMotion:clientData:callData:
stopButtonMotion: aButton clientData: aRowColumn callData: callData
"Private - End timing. Subtract the ending time from the
starting time to determine the time elapsed."
| elapsedTime |
startTime == nil ifTrue: [ ^self ].
elapsedTime := self calculateTime:
(Time fromSeconds:
( (Time now asSeconds) - startTime asSeconds )).
self timeElapsedDisplay
setString: ' ', ((elapsedTime printString) "12 before ,"
copyFrom: 2 to: 9).
Method calculateTime:
Finally, implement calculateTime: in the category Time Operations:
calculateTime: time
"Private - Answer the time elapsed in a format that
displays Hours:Minutes:Seconds."
| answer |
answer := WriteStream on: (String new: 8).
time hours < 10 ifTrue: [answer nextPut: $0].
time hours printOn: answer.
answer nextPut: $:.
time minutes < 10 ifTrue: [answer nextPut: $0].
time minutes printOn: answer.
answer nextPut: $:.
time seconds < 10 ifTrue: [ answer nextPut: $0].
time seconds printOn: answer.
^answer contents.