Frame Rate
If all you want is know the time it took since last stepping, have a look at the FrameRateMorph
. It holds two instance variables, lastDisplayTime
and framesSinceLastDisplay
, which are calculated in the Morph’s #step
method:
FrameRateMorph>>#step
"Compute and display (every half second or so) the current framerate"
| now mSecs mSecsPerFrame framesPerSec newContents |
framesSinceLastDisplay := framesSinceLastDisplay + 1.
now := Time millisecondClockValue.
mSecs := now - lastDisplayTime.
(mSecs > 500 or: [mSecs < 0 "clock wrap-around"]) ifTrue:
[mSecsPerFrame := mSecs // framesSinceLastDisplay.
framesPerSec := (framesSinceLastDisplay * 1000) // mSecs.
"…"
lastDisplayTime := now.
framesSinceLastDisplay := 0]
You can use similar logic in your morph.
Note that FrameRateMorph
implements #stepTime
to return 0
, so that it is called as often as possible. You might need to adjust your calculations according to this number.
Process synchronization
If your goal cannot be achieved by the means above, you have three options.
omit the block/fork
Do you really need the fork in #timer
? What about this:
Myclass>>#timer
tstart:=Time millisecondClockValue.
sem:= Semaphor new.
sem wait.
Transcript show: result.
^ result
This will block until your result is ready.
fork and wait
If you insist on using a forked block, consider #forkAndWait
:
Myclass>>#timer
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result] forkAndWait.
^ result
This will also block until your result is ready.
make a callback
You could proactively call code once your result is ready
Callback via argument
Pass a one-argument-block to a changed timer function and
operate on the result:
Myclass>>#timerDo: aBlock
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result.
aBlock value: result] fork.
and then
| obj |
" assume that obj is an instance of Myclass"
obj timerDo: [:result |
"do something meaningful with the result, eg, show it "
blaObject showResult: result.].
Callback block via instance variable
Add an instance variable, eg callBack
to Myclass
and change #timer
to
Myclass>>#timer
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result.
callBack value: result] fork.
and then use it like
| obj |
" assume that obj is an instance of Myclass"
obj callBack: [:result |
"do something meaningful with the result, eg, show it "
blaObject showResult: result.].
obj timer.
Callback via message send
Note this might be dangerous and not what you are after
The third option is not to save a block as callback but send
a message to an object directly upon result arrival.
Add two instance variable, eg target
and selector
to Myclass
and change #timer
to
Myclass>>#timer
tstart:=Time millisecondClockValue.
[sem:= Semaphor new.
sem wait.
Transcript show: result.
target perform: selector with: result] fork.
and then use it like
| obj |
" assume that obj is an instance of Myclass"
obj
target: blaObject;
selector: #showResult: .
obj timer.
However, with all process synchronization you can get yourself into all different kinds of trouble, so if possible, please try the first option first.