Recent Changes - Search:



edit SideBar


(This page is being revised frequently)

What you can get out of this tutorial and sample code

GUI in operation


Note: You must be using Pharo v1.3 or higher. This code will not work in v1.2. A Note to the Powers That Be Please do not revert Announcements back to the v1.2 code!

Go to then download the most recent

The .st file is self contained. It makes no changes to classes outside the package. All together there are 100+ methods in 3 classes, plus 9 Announcement subclasses. The code was developed on a Windows XP box.

My version numbering scheme: As a category inside Pharo, the 110421 of Sandbox110421 is the date I started the project, (21 April 2011). The 3 numbers after the hyphen ( is the version (-001, -002, etc.). I am not quite ready to post this through SqueakSource, so there's no mcz file to install from. If you place the .st file in your Pharo root directory, you should be able to file it in.


The best place to ask questions about Announcements ("How do I ...?") is the Pharo mailing list. I might be able to explain how my code works, but I probably can't explain why your code doesn't. Go there to sign up for the mailing lists so you can post. The difference between the Pharo list and the Pharo-user list is that the user list is the better place to discuss something that involves the current stable release. Sign up for both.

You can view and search Smalltalk forums (including the Pharo lists) through You can read threads, but you have to be on the mailing list to post to it through that site. I also use it to search for general Smalltalk questions.

Starting the code

Before you try to figure it out, give it a run-through first to see what it does. Start by opening a Workspace and a Transcript. Type MyGUI open in the Workspace, and doIt. You may also want to open the Process Browser (set it to auto-update). Opening a Transcript is not necessary, but it will give you a second view on the data being processed.

The main loop

The temperature goes up or down by a combination of 4 elements: a random value, a fudge factor (representing external forces like summer heat), the heater (goes on when it gets too cold), and a cooler (goes on when it get too hot). The random value will be between 0 and 1. The other values should be close to zero. Fudge can be a negative number, but heater and cooler are set as positive only (cooler is subtracted). If the total is greater than or equal to 0.5, then the temperature goes up a fixed amount (the bumpTemp). If it's less than 0.5 it goes down that amount.

	| oldCurrentTemp newCurrentTemp rand|

	oldCurrentTemp := currentTemp.  
	rand := Random new.
	[ 	(rand next + fudge + heater - cooler ) >= 0.5 
			ifTrue:  [newCurrentTemp := oldCurrentTemp + bumpTemp] 
			ifFalse: [newCurrentTemp := oldCurrentTemp - bumpTemp].

		self currentTemp: newCurrentTemp.  "currentTemp: also sends announcements"
		oldCurrentTemp := newCurrentTemp.	

		(Delay forSeconds: delaySeconds) wait.
		running ifFalse: 
			[^ nil].  "exits the loop"
	] repeat.

The Announcements structure.

There are 5 announcements made by MyTherm: (in currentTemp:aNumber)

  • AnnouncementHot
  • AnnouncementWarm
  • AnnouncementCool
  • AnnouncementCold
  • AnnouncementMyLoopMessage

There are 4 announcements made by MyControl: (in heaterStart, heaterStop, coolerStart, and coolerStop)

  • AnnouncementHeaterOn.
  • AnnouncementHeaterOff.
  • AnnouncementCoolerOn.
  • AnnouncementCoolerOff.

MyControl subscribes to these announcements: (in initialize)

  • self subscribeHot. (AnnouncementHot)
  • self subscribeWarm. (same pattern)
  • self subscribeCool.
  • self subscribeCold.

MyGUI subscribes to the four announcements made by MyControl (in startupMyControl),

  • self subscribeHeaterOn.
  • self subscribeHeaterOff.
  • self subscribeCoolerOn.
  • self subscribeCoolerOff.

and MyGUI also subscribes to one announcement made by MyTherm (also in MyGUI>>startupMyControl).

  • self subscribeMyLoopMessage.

The subscriptions all follow similar patterns. For example:


	therm announcer subscribe: AnnouncementCold send: #heaterStart to: self.

'therm' is an instance variable in MyControl. It is initialized to an instance of MyTherm. 'announcer' is an instance variable in MyTherm which is initialized to an instance of Announcer. All the functionality of Announcer (handling subscriptions, etc) is done through 'announcer'. Again, I repeat, this requires the Announcement classes from v1.3 or above. Pharo 1.2 Announcements work on a different design.

If you look at MyControl>>subscribeHot, you'll see examples of subscribe:do: These are not used in the program. They are there to show you how to write them with 0, 1, or 2 parameters.

More on Announcements

The primary announcements are made in the MyTherm >>currentTemp:aNumber. The announcements made in MyControl are secondary.

When the loop inside MyTherm>>myLoop is running,

  • it modifies currentTemp (using a formula based on a random number plus modifiers).
  • it runs self currentTemp: newCurrentTemp.

currentTemp:aNumber method, has logic which determines whether to make an announcement, and if so, which one. That code is key reading to understanding how Announcements are implemented in the sample code.

Thoughts on creating GUIs

A GUI is just an interface. It does not manage the logic. All the operational code is in MyTherm and MyControl. That's a big point in GUI design. Don't put any logic in the GUI! Try to make the GUI interface (what you see when you run 'MyGUI open') bare bones enough that you can swap in a different GUI using the same class underlying classes.

The one thing MyGUI does (and has to do), is convert text field entries into numbers. Each of the "setXXXX" methods makes sure that the text entered will convert into a number (either an integer or float). I have used an exception-handling routine to trap bad input in the numeric entry fields. Look at MyGUI>>setPrefTemp for an example of exception-handling for this purpose.

How To Use the Model, in more detail

What is being simulated by this model?

Step 1: Make a backup copy of your image file % change file. The code runs an endless loop in a process at a priority lower than the desktop. If you start tinkering with the loop or the process level, you may find that the only thing you can do is to totally shutdown Pharo without saving. (Been there, done that!) I am comfortable saying that the process is under control in the download.

Step 2: (Optional) Open the World Menu and click on Tools. Then open Process Browser . Right click in the TOP LEFT BOX. Select "Turn on auto-update". When the loop process is running, it will appear in the process list (starts with [delaySemaphore wait]. If you get stuck in an endless loop, you can terminate the process through this browser.

Step 3: To start:

   Open a Transcript.

   Type MyGUI open into a Workspace.

A gui will open. Position the Transcript and GUI so they don't overlap.

Step 3:

Try changing numbers from inside the GUI. Push all the buttons. The boxes are for numbers (floats are ok). Floats between -1 and 1 require 0. "zero point" in front (i.e. 0.03).

Step 4:

You can change these parameters at any time, including while the loop is running! These methods all start with 'set':

  • the preferred temp,
  • the current temp,
  • the turn on margin (how many degrees below preferred temp before heater turns on, or above prefTemp for cooler)
  • the turn off margin (how many degrees over preferred temp before heater turns off, or under prefTemp for cooler)
  • the loop delay time in seconds (can be a float, i.e. 1.5),
  • the adjustment that heater adds to the random number (As a suggestion, use the range 0.0 to 0.5)
  • the adjustment that cooler subtracts from the random number (As a suggestion, use the range 0.0 to -0.5)
  • the 'fudge' factor (use to simulate an external heating/cooling factor).

What makes the temperature change?

Look in MyTherm>>myLoop.

A random number between 0 and 1 is generated. When it's greater than 0.5, the temperature goes up 1 degree. When it's lower than 0.5 it drops 1 degree. That number can be adjusted by 3 factors: the heater (adds some), the cooler (subtracts some), and a 'fudge factor'.

Think of the fudge factor as some kind of external element that is causing the temperature to change. For example, it's winter time and it's really cold outside. So set the fudge factor (it appears as "f:") to a negative value (suggestion, between 0 and -0.5). Or maybe you are simulating an engine, so you want a positive fudge factor to represent friction heat being generated.

Edit - History - Print - Recent Changes - Search
Page last modified on May 06, 2011, at 09:11 PM