Now we will create our first instance method, which is
ManHourCalculator>>initialize
. Select our "ManHourCalculator" class in the class pane (the left-hand pane) of the class browser, then click on the "Instance" tab on the right-hand pane. Select "New method" from the context menu and enter the following in the editor pane:initialize "Private - Initialize instance variables." super initialize. hourFieldModel := ValueHolder with: ''. adjustedFieldModel := ValueHolder with: ''. popupListModel := ListModel list: #('Positive' 'Somewhat' 'Not at all'). popupListModel addDependent: self.The
initialize
method will be called when an instance of the class is created. In this method we initialize our instance variables with ValueHolders. These object can hold another object, and respond to thevalue
andvalue:
methods. They can also send messages when the value they hold changes. As I said earlier, in a real application, we would be using another class as our model. If this were the case, then the ValueHolders would be wired to an instance of that class. Since I was going for simplicity in this tutorial, the ValueHolders will be our model. The final line sets up a dependency relationship that will cause a method to be called when the popuplist's value changes. More on this later.We now need to add a method to bind our screen widgets to our application. This occurs in the
createComponents
method. Here is the definition forManHourCalculator>>createComponents
:createComponents "Bind the screen widgets to our application code." super createComponents. self add: Button id: ##CalcButton name: nil aspect: #calcButtonPressed. self add: TextField id: ##HourField name: #hourField aspect: #hourFieldModel. self add: TextField id: ##AdjustedField name: nil aspect: #adjustedFieldModel. self add: Listbox id: ##PopupList name: nil aspect: #popupListModel.This code does several things. First, we call the
createComponents
method of our superclass, in this caseApplication
. ForApplication
this doesn't actually do anything, but it is always a good idea to call the superclass' version of an overridden method to make certain that your object gets all of the proper behavior. The next four lines setup the bindings between the components that will show up on the Palm screen, and our application. Theadd:id:name:aspect:
method does this for us. The first argument is the type of widget we are adding. (There are classes that map to each type of screen widget, and these are scattered under the hierarchy of classModel
.) The second argument is the widget ID that we assigned in our resource file. Here we are using the constants that we defined in our "Widgets" constant category. The third parameter creates a name for the component that we can reference later on. We don't need a name for the button since it will be an active component (meaning it will call our code), but the text field called#hourField
will be referenced from within our code. The final parameter is truly the "glue" between the widgets and the code. The aspect is the name of a method on our class that is called by the widgets. For the button, this is the method called when the user clicks on it. For the textfields and the listbox, this method will return a reference to the model for the caller. For those it is the ValueHolders we created earlier.It is always a good idea to categorize your methods. For some methods, the browser will automatically assign a new method to what it thinks is the best category. If it doesn't put a method where your think it should go, you can right-click on a method and select either "Quick categorize..." or "Categorize...". The first presents you with a list of common categories, while the second allows you to type in a new category. The categories are just for organization, but they help when trying to find a method. Methods like
createComponents
andinitialize
could go into theinitializing
category.Once you've accepted and categorized this method, we are ready to wire up our menu. This occurs in the
createMenus
method. With the "Instance" tab selected for our "ManHourCalculator" class, right-click in the list of methods, and select "New method...". Here's the code:createMenus "Wire up our menus to the code." super createMenus. self addMenuAction: #about forID: ##AboutMenuItem. self addMenuAction: #exit forID: ##ExitMenuItem.This method performs a similar function to that of
createComponents
, but the syntax is a bit different. Again, we call our superclass's method to get whatever behavior is provided there. We then setup our two menu items to do their thing. TheaddMenuAction:forID:
method says that for a given ID, call a certain method. The first one binds theManHourCalculator>>about
method to the menuitem whose ID is the value of the constant##AboutMenuItem
. The second sets up the binding between the menu item identified by the constant##ExitMenuItem
and the methodManHourCalculator>>exit
. We will define these methods in a minute. Now accept the method, and make sure it is in the "initialization" category.We will now define the methods that will live in the "aspects" category. (There is no default category called aspects, so after creating one of these methods, select "Categorize..." from the context menu and enter "aspects" for the category name.) There are three methods, and these correspond to our two textfields, and the list that we setup in
createComponents
. Right-click in the method list and select "New method..." for each of the following methods. (Be sure to accept each method when you're done with it.)hourFieldModel "Answer the model for the number of man hours entered by the user." ^hourFieldModel. popupListModel "Answer the model for the list of sure-ness choices." ^popupListModel. adjustedFieldModel "Answer the model for the adjusted number of man hours." ^adjustedFieldModel.These methods are attach the screen widgets to our model. Each one should return the object that will hold the value for a particular widget. Since we are using ValueHolders as our model, the code for each of these methods is quite simple. I'm not totally certain what piece of the system calls these, but they are required, so include them.