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:
open "Public - Create and realize the receiver." self createShell; createWindow; realizeWindow.
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 Handling:
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