undefineCursor

"Undefine the cursor for the window."

(self subpartNamed: 'Push Button1') yourself primaryWidget
window undefineCursor.

5. Go back to the Composition Editor and make the following connections.

a. Connect *openedWidget* of the window to the *changeCursor* script.

b. Connect *aboutToCloseWidget* of the window to the *freeCursor* script.

c. Connect *aboutToCloseWidget* of the window to the *undefineCursor* script.

Note that the order of the two last connections is important.

6. Test your part and enjoy!

## Busy Cursor

**Question**

Can `#showBusyCursor` in a development application be packaged with the user application?

**Answer**

The *Programmer's Guide to Building Parts for Fun and Profit* suggests that you create two different applications, *Edit* and *Run*. You package only the *Run* applications when creating your packaged image. The same applies to VisualAge for Smalltalk applications and parts themselves.

As `AbtShellView>#showBusyCursor` is defined in `AbtRunViewsApp`, it is packaged into your run time image.

**Note this!**

Please don't be confused by similarity in the names of `showBusyCursor` and `showBusyCursorWhile:`. The method `showBusyCursorWhile:` is an instance method of the class `EmSystemConfiguration`. Its comment says, "Show the busy cursor during execution of a Block. The cursor is not changed if the graphics system has not been started."

The following code shows you another way you can change the cursor. The example can be evaluated in a Transcript window:
| window cursor |

window := Transcript shell window.

cursor := CgDisplay default busyCursor.

window defineCursor: cursor.

(Delay forSeconds: 5) wait.

window undefineCursor.

By the way, do not explicitly free this cursor. As for disabling the mouse
you might want to consider one of the following:

1. The easiest way to disable the mouse pointer is to use the message grabPointer:. (This method is an instance method in CwComposite.) The argument is a cursor. So, you can send it the clock cursor and you won't have to set that up yourself. This method sends all mouse input to the shell, regardless of where the pointer is on the screen. This is also the bad part, as the user can't use the mouse for other things. When you are done, send the message ungrabPointer.

2. Another way is to add an event handler when you start the processing.
You can do something like this:

Smalltalk

shell addEventHandler: ButtonPressMask

receiver: self

selector: #eventHandler:clientData:event:

clientData: nil.

The advantage of this method is that it applies only when the mouse
pointer is in the window. Call the above when you want the input
blocked. When you are done, call the above again, except change
addEventHandler to removeEventHandler. Make sure to add
CwConstants to the class's pool dictionaries. Now you need to add the
method eventHandler:clientData:event:, which gets called when there is
input. You can either leave this method blank to do nothing, or maybe
use the following option.

3. To implement a beep, add the PlatformFunction pool dictionary to the class. The following is valid for OS/2:
eventHandler: widget clientData: clientDate event: event
"There has been user input. Beep."
DosBeep callWith: 100 with: 200.

## Caret Shape Cursor

**Question**

I have some text entry fields where the cursor is positioned at the right edge. If I tab into these (empty) fields, I nearly cannot detect in which field the focus is actually set because of the look of the cursor which is a thin line. How can I define another caret-look for entry fields?

**Answer**

You can't change the caret look for your entry field. The entry field input cursor, known also as the caret ("I" bar) is defined by the operating system and cannot be changed by an application. Some operating systems have configuration options to change the mouse cursor, resize cursor, and the text input cursor. If you want a VisualAge for Smalltalk solution, you could connect the `gettingFocus` and `losingFocus` event to a label's `show` and `hide` actions. Put the label next to the entry field, as

Address _______*

The asterisk will show when the field has the focus, and hide when it doesn't.

## Mouse Pointer Location

**Question**

How can I find the position of the mouse cursor on the screen?

**Answer**

You can detect the cursor location in one of two ways: You can call the `OSWidget` class method `widgetUnderCursor` to see where the cursor is, or you can add a Pointer Motion Mask event handler to find where the cursor is and see if it's in the desired area (see page 192 of the *IBM Smalltalk Programmer's Reference* for an example of the latter). You can change the font of a cursor by following the example on page 124 of the *IBM Smalltalk Programmer's Reference*.
## Icon as Cursor

**Question**

How can I use an icon as cursor?

**Answer**

The following code snippet reads an icon out of a DLL and uses it as a cursor.

```
Smalltalk
| window datavent map cursor shell label icon gc image |
shell := CwTopLevelShell
createApplicationShell: 'shell'
argBlock: [:w | w title: 'label example'].
shell width: 200;
height: 200;
x: 1;
y: 1.
label := shell
createLabel: 'label'
argBlock: nil.
label labelString: 'this is a label.'.
label manageChild.
shell realizeWidget.
window := shell window.
"get an icon from a file"
icon := Cglcon
fromResource: 153
filename: 'd:v3clientdllabticons.dll'.
```
"create a bitmap from the icon"

```
 := window
    createBitmap: icon width
    height: icon height
    depth: 1.
```

"get device independent image"
```
image := icon shapeImage.
gc := bitmap
    createGC: 0
    values: nil.
```

"create a rectangular area of data for the cursor"
```

    putDeviceIndependentImage: gc
    image: image
    srcRect: (0@0 extent: image extent)
    destRect: (0@0 extent: image extent).
```

"Create the cursor. I hardcoded a hotspot at 20,20. A better idea might be to use image width and image height."

```
cursor := bitmap
    createBitmapCursor: bitmap
    x: 20
    y: 20.
    bitmap freeBitmap.
```

"Display the cursor."
```
window defineCursor: cursor.
(Delay forSeconds: 5) wait.
window undefineCursor.
cursor freeCursor.
gc freeGC.
```
## Animated Busy Cursor

**Question** How can I display an animated busy cursor similar to the activity indicator on the print preview? I know I can use the System `showBusyCursorWhile:` method that displays the system clock, but sometimes the users may think the system is locked.

**Answer** Check out the spinning clock in the VisualAge for Smalltalk Help Examples for an example of how to make an animated progress indicator.

## Adding Pull-Down Menu Choices Dynamically

**Tip** Listed below is some sample code that you can use to dynamically add pull-down menu choices. You will need to add a callback method to do some processing when the user clicks the new pull-down choice.

### Smalltalk

```perl
addMenuChoice
  "Dynamically add a new menu choice to a menu "
```

```perl
| newMenuChoice |
newMenuChoice := ((self subpartNamed: Menu1') widget)
  createPushButton: New Choice'
  argBlock: nil.
newMenuChoice addCallback: XmNactivateCallback
  receiver: self
  selector: #newChoicePushed:clientData:callData:
  clientData: nil.
newMenuChoice manageChild.
```

## Toggle Buttons in Menu

**Question** I want to have a menu with toggle buttons `Sort by Date` and `Sort by Name` (and possibly some other sort criteria). I want to have a check mark in one of these buttons only. I tried to connect the `selectionChanged` events to a script but for some reason this script runs only once. What would be a way of making this work?
**Answer**

You'll need to write a script for each toggle button and connect it to the `selectionChanged` event. Here's what the scripts might look like:

**Smalltalk**

```ruby
sortByNameSelectionChanged: selectionBoolean
"Sort by name."
```

```ruby
selectionBoolean == true
```

```ruby
ifTrue:
    [ (self subpartNamed: 'SortByName') disable.
    (self subpartNamed: 'SortByDate') clear, enable.
    <perform sort by name statements> ]
```

**Smalltalk**

```ruby
sortByDateSelectionChanged: selectionBoolean
"Sort by date."
```

```ruby
selectionBoolean == true
```

```ruby
ifTrue:
    [(self subpartNamed: 'SortByDate') disable.
    (self subpartNamed: 'SortByName') clear; enable.
    <perform sort by date statements>]
```

The `selectionBoolean` value needs to be checked because the statements should only be executed when the menu item is checked, not unchecked.

## Disabling Push Buttons on Pop-Up Menus

**Question**

How do I disable push buttons on pop-up menus?

**Answer**

You can use a `setSensitive:` method to disable a push button. The default setting for the value of the `XmNsensitive` resource is `true`. This method will allow you to set it to `false`.

If you want the push button to be disabled initially, try using the `createPopUpMenu:argBlock:` method. When you create a menu through a Smalltalk script, you first create the menu, and then add individual buttons to it. Each button can then be enabled or disabled. An example of how to do this is listed below:
createPopUp: parent
| menu |

menu := parent createPopUpMenu: 'popUp' argBlock: nil.

 menu createPkushButton: 'Add' argBlock: nil)
    addCallback: XmNactivateCallback
    receiver: self
    selector: #addSomething^clientData^callData:
    clientData: nil;
    setSensitive: false;
    manageChild.
^menu

Pop-up Menus for Icon Gadgets

Question

How do I dynamically create pop-up menus for dynamically created icon
gadgets?

Answer

To dynamically create a pop-up menu for the dynamically created icon
gadget, use the following:

"Create an icon gadget for each item and set its attributes."

iconGadget := (AbtIconGadgetView new
    label: 'MyIcon';
    largeIcon: icon;
    parentView: container;
    openWidget;
    yourself).

Instead of making the association with the menu before the *openWidget*
message, add the following code afterward to associate the pop-up menu
with the icon:
```perl
iconGadget menu: ((self subpartNamed: 'Menu1')
    parentView: container;
    openWidget).
```

## Sharing a Menu Between Containers

**Tip**

If you want to share a menu, you will need to create a reusable menu part and add multiple instances of it for connecting to each container. See page 413 of the VisualAge for Smalltalk User's Guide for details.

## Dragging Versus Pop-Up

**Question**

What is the difference between obtaining a pop-up menu and dragging?

**Answer**

Drag does not start unless the mouse is moved a threshold amount. If we are not in drag mode, the pop-up is displayed. (This is a general algorithm; it varies slightly, depending on the platform you are running on.)

## Icons on a Menu Bar

**Question**

I tried adding an icon as a menu bar item and a menu pull-down item. To do that, I created a menu as usual, then selected **Open Settings** from the **Menu Choice** pop-up menu, then clicked on **Label Type - Graphic, Graphic Type - Icon, Module name: abticons, ID: 1**. That gave me a file cabinet icon on the menu, but the icon was displayed as a bitmap—that is, the background was white, not transparent. The comment in the `AbtLabelView->#calcGraphicLabelType` says "For OS/2 and Windows, only bitmaps (not icons) are allowed as menu items, so if the parent will be a menu, then force the graphic to be a bitmap." Is there a remedy?

**Answer**

I've not seen a menu bar at the bottom of the frame, but that is not native widget behavior. The word processor must be implementing this (or perhaps, to use PM-terminology, overriding `WM_FORMATFRAME` to move it to a new location). You may want to investigate using an `AbtRowColumnView` for building your tool bar. It can be attached to the bottom, the top, or wherever on your window. It is a special part that automatically attaches buttons to each other. To see an example, do the following:
1. From the **Options** menu select **Add Part** in the Composition Editor.

2. Type in **AbtRowColumnView** as the class and select **Part** in the radio button set.

3. Drop the part within your window, attaching it at the top and sides to the window.

4. Drop several push buttons within the row column part. Use some that are graphic and some that are text, just to see how it works.

5. If you want a scrollable tool bar, you can drop a scrolled window part (from the Canvas palette) and connect the workView of the scrolled window to the row column part (moving the row column off to the side).

## Creating a Tool Bar

**Question**

What would be an easy way to create a tool bar for an application? Can you simply add a menu bar to the window and have the items displayed as icons?

**Answer**

Basically, what you need is a part that you can put onto a window and have the attachments made automatically to the parent. This part would also have to accept buttons that are dropped onto it in edit mode, and automatically make the attachments from the button to the tool bar frame.

To do this you could use the **AbtFrameView** and the **AbtRowColumnView**. These parts are not on the palette, but you can still drop them onto the Composition Editor. Drop the row column into the frame view. You need to open its settings and make sure that it is connected on all sides to the frame with preferably a offset of zero. Now, when you drop your push buttons inside the row column, they automatically space apart, making a tool bar a little easier to deal with.

## Synchronizing a Combo Box

**Question**

Suppose you have two combo boxes dropped on a window. The first combo box contains a set of names, while the second combo box contains valid descriptions for each of these names. How can you synchronize the two in such a way that when you type an invalid code in the first combo box, the second one will be cleared?
**Answer**

One of the ways of doing this is just to connect the `selectedIndexChanged` event of the first combo box to a script, where you validate the index, and modify the second combo box accordingly.

## Adding Items to Combo Box

**Question**

How do I allow a user to add new items to a combo box?

**Answer**

Try this:

* Hook a keyboard event handler to the combo Box

* Within the event handler, sort out any Enter keys

* Whenever you encounter an Enter key you do something like

```
Smalltalk
<combobox> items add: (<combobox> object).
```

In order to invoke the keyboard event handler, you hook a method to the `aboutToOpenWidget` event of your main window; in this script you include:

```
Smalltalk
<combobox> widget addEventHandler: KeyReleaseMask
receiver: self
selector: #keyRelease:clientData:event:
clientData: nil.
```

Then you can add a `keyRelease:clientData:event:` method to your class which will be called for each key entered while the combo box has the input focus.

## Drag-and-Drop Support on List Boxes

**Question**

Is it possible to have drag and drop support for list boxes? The documentation only describes the situation for containers. I would like to give the user the ability to move an item in a list box to a new position in the same list box using drag and drop.
Answer

The drag-and-drop concepts are fairly universal. The nice things containers will do for you is let you specify what sort of object can be moved, copied, or linked.

Basically, the drag-and-drop callbacks in IBM Smalltalk are exposed as events for your list box in VisualAge for Smalltalk. If you open the settings for the list box and select drag/drop on the notebook page, the events are added to the connection pop-up menu. These events are exactly the same as the callbacks listed in Chapter 9 of the *IBM Smalltalk Programmers Reference*.

The following example illustrates how to drag and drop items within a list box:

1. Add a list box to any window.

2. Open its settings and go to page Drag/Drop: select **Allow Drag** and **Allow Drop and Move** as the valid default operation in both cases.

3. Use any collection as the items of the list, as usual.

4. Connect the *dropped* event of the list to the following script:

Smalltalk

```perl
moveltems: aCallback
| items itemsDropped position index |

items := aCallback sourceModel.
itemsDropped := aCallback sourceItems.
itemsDropped empty ifTrue: [ ^nil ].
index := items indexOf: itemsDropped first.
position := aCallback event y // aCallback offsets first y negated.
itemsDropped do: [ :item | items remove: item ifAbsent: [ ] ].
index < position ifTrue: [ position := position - 1 ].
position > items size ifTrue: [ position := items size ].
items addAll: itemsDropped afterIndex: position.
aCallback sourceWidgetyorData items: items.
```

The example works for a list and for a multiselect list.
## List Box Behavior

**Question**

When the focus is on the list box part and the user clicks on a character key, the list box should scroll to the first item begining with this character. When typing another character, the list box should scroll to the next item that starts with the character that was typed first, followed by the character that was typed second. Is it possible to get this behavior from the list box parts, and if so, how?

**Answer**

On OS/2 and Windows, pressing a character scrolls to the list box entry that starts with that character. You might override this behavior by creating a form around the list box and using `CwComposite>>interceptEvents:` to trap the events going to the list box.

But an easier solution (and one you see see many times) is to add a **Search** entry field above the list box and scroll the list box with `CwList>>topItemPosition:` as the user types in it.

## Identifying Last Selected Item

**Question**

For our application, we would like to know what the last selected item in our multiple-select list was. We need this, because the user can press a button that will open a detailed view on that item. I would like to see an attribute such as *last item selected*. Any ideas how to achieve this?

**Answer**

There is no public attribute available on the multiple-select list part that will tell you the last item selected. However, with a tiny bit of code, you can get this information. Here is what you can do. First, connect the `aboutToOpenWidget` event of your window to the following script:

### Smalltalk

addCallbackToList
"Set up a callback for the multiple selection list"

(self subpartNamed: 'Multiple Select List1') widget
addCallback: XmNmultipleSelectionCallback
receiver: self
selector: #multipleSelect:clientData:callData:
clientData: nil.
Then, add an instance variable to your visual part's class definition called `lastItemSelected`, with the appropriate get and set methods. Now, write the following script to maintain your `lastItemSelected` value:

**Smalltalk**

multipleSelect: widget clientData: clientData callData: callData

"Save the last item that was selected. The 'includes:' logic will exclude any items that were deselected, since itemPosition will return the last item either selected or deselected. Caching the itemPosition value for performance."

| currentPosition |

currentPosition := callData itemPosition.
(callData selectedItemPositions includes: currentPosition)
ifTrue: [
    self lastItemSelected: currentPosition].

## Default Action Requested

**Question**

How do I get an event that could work as the DefaultActionRequested available in a text part for a combo box?

**Answer**

This question indicates an apparent oversight, and I've opened DCR 6872 for a future release. In the meantime, you can add an activate callback to the widget. For example, I hooked the following code to the combo box's `openedWidget` event:

**Smalltalk**

addComboBoxActivateCallback: aComboBoxView
aComboBoxView widget addCallback: XmNactivateCallback
receiver: self
selector: #myComboBoxDefaultAction:clientData:callData:
clientData: nil.

The `myComboBoxDefaultAction:clientData:callData:` will be invoked when the user presses Enter. Or, if you prefer, you could create a subclass of `AbtComboBoxView` that adds the new event See also `AbtAbstractTextView` for an example, especially the methods `postCreationInitialization`,
`defaultActionEvent`, and `defaultAction:clientData:callData:`. I suspect they could be copied to your subclass with only minor modification (and the addition of the `defaultEventRequested` to the public interface, of course). For an Multiline Edit (MLE) part, the activate callback for `CwText` applies only when it is single-line (since the Enter key means "add line" to a multiline `CwText`).

## Combo Box Behaviour

**Question**

I have dropped a combo box on my form. I populated it with a number of items and set one of them as the initial item. I grab the selected item and pass it to a variable. When I type a value in the combo box, it seems to search the list of items for a match (for example, on the first letter typed). Of course, it does not display anything. When I tab out of the field and inspect the variable, it has not captured the data entered in the field, but instead, it has the list item that matched on the first character. Is this the default behavior of a combo box?

**Answer**

That is indeed the default behavior of a combo box. The entry field is just for you to be able to type in an existing entry as an alternative to using the scroll bar to find it in the list. However, you can add the behavior you describe with a combination of connections and scripts.

## Skipping through a Notebook

**Question**

I am writing an application demonstrating various features of VisualAge for Smalltalk. One of the things I want to do is to skip through a notebook without user intervention, as in a slide show. The question I have is, how can you automatically skip to the next page?

**Answer**

You can turn notebook pages by setting the `currentPageIndex` or `currentPage`. Here is an example using delays, so that the pages turn a bit slower:
Smalltalk

| delay numberOfPages |

delay := Delay forSeconds: 2.

numberOfPages := (self subpartNamed: 'PMNotebook1')
components size.

2 to: numberOfPages do: [ :i |
(self subpartNamed: 'PM Notebook1') currentPageIndex: i.
delay wait.
].

Bitmap on Notebook Tab

Question

Is it possible to display a bitmap on the tab of a notebook page? And if so,
how do you do this?

Answer

If you would like to have a bitmap appear on the tab of a notebook page, you can use the `tabContents` attribute for the notebook page. It is looking for an `AbtBitmapDescriptor`. Here is a piece of sample code that puts a bitmap on the tab of a page. Connect the `aboutToOpenWidget` event of the window to the following script:

Smalltalk

bitmapTab

| bitmap |

bitmap := ((AbtBitmapDescriptor new
            
             {
               "module_name": "AbtBmp20";
               "id": 101}
             ) baseGraphic).

(self subpartNamed: 'NotebookPage') tabContents: bitmap.

It is also a good idea to free the bitmap after you are done using it. Use of
the *baseGraphic* and the *gpiDeleteBitmap* (see below) methods is highly
platform specific. The way I would go about doing this is to assign an
instance variable to the *baseGraphic* in the *bitmapTab* method and connect
the following script to the *closeWidget* event of the window:
### Smalltalk

```
 bitmapFree
 instanceVariableName gpiDeleteBitmap
```

This causes resources used up by this bitmap to be freed when this window is closed.

## Hiding and Showing Pages

**Question**

How do I hide and show pages of an OS/2 Windows notebook?

**Answer**

I believe hide is not supported for notebook pages, you must destroy the page. Here is how I add a page dynamically (basically, I copy from the `abtBuildInternals` method and add an `openWidget` send):

### Smalltalk

```
addNotebookPage: aNotebook named: aName
| page label |

aNotebook subpartNamed: aName
put: (page := AbtPortableNotebookPageView newPart).
page
  framingSpec: (AbtViewAttachmentConstraint new
    leftEdge: (AbtEdgeConstant new offset: 34);
    topEdge: (AbtEdgeConstant new offset: 90)).
page subpartNamed: 'label' put: (label := AbtLabelView newPart).
label object: Time now printString;
framingSpec: (AbtViewAttachmentConstraint new
  leftEdge: (AbtRunEdgeAttachmentConstraint new attachment:
    XmATTACHFORM;
    offset: 65);
  rightEdge: (AbtRunEdgeAttachmentConstraint new attachment:
    XmATTACHNONE);
  topEdge: (AbtRunEdgeAttachmentConstraint new attachment:
    XmATTACHFORM;
    offset: 95);
  bottomEdge: (AbtRunEdgeAttachmentConstraint new attachment:
    XmATTACHNONE)).
page openWidget.
label openWidget.
```
To remove the page, I call *destroyPart* on the page. This is just a simplified example; in your case, you would substitute *label* for an embeddable view that represents the entire page.

## Porting Notebooks across Platforms

**Question**

If you try to port an OS/2-Windows notebook from an OS/2 platform to Windows NT or 95, the notebook is replaced by a VisualAge icon. Why?

**Answer**

The OS/2-Windows notebook is not available on Windows NT or 95, since it is built from a 16-bit class library. However, you can migrate the notebook to the portable notebook (which is supported under all VisualAge platforms) by selecting **Morph** from the pop-up menu of the icon that you are seeing. This will morph the OS/2 notebook to the portable notebook.

## Navigating between Columns

**Question**

How do I navigate between columns in a container without using the mouse?

**Answer**

Use `CELLSINGLESELECT` selection technique.

## Selecting Valid Items

**Question**

I am using a container details part. There are some rows that cannot be selected by the user (depending on the data in the object), whereas other rows may be selected. Is there some kind of callback I can capture that would allow me to deselect a row when I do not want the object to be valid?

**Answer**

The container details will signal a *selectedItemsChanged* event every time the user modifies the selection. You can then examine the selected items, and change the selection to include only the valid objects (using *selectedItems*:). Be careful of getting stuck in a loop (some parts will resignal *selectedItemsChanged* even if the new selection is the same as the previous one). You may have to keep track of this yourself.
## Validating Input Fields

**Question**

We have a written a notebook application where data needs to be entered on different pages. After the data has been entered, I need to see whether it is valid. The following problem occurs when the user skips to the next or previous page. A prompt might pop up on the new page, displaying a message that shows the validation error from the previous page. What can we do to prevent this from happening?

**Answer**

To solve the problem, it sounds like a good idea to use a form checker:

1. Drop a form checker part onto the free-form surface.

2. Following the example on page 149 in the VisualAge for Smalltalk User's Guide, connect the `verificationRoot` attribute of the form-checker part to the `self` attribute of each notebook page you want to verify.

3. Add an instance variable called `lastPageSelected` to your visual part class

4. Connect the `switchedToMe` event for each page to the following script:

**Smalltalk**

saveLastPage

"Save the current page as the last page

selected before the page is turned"

self lastPageSelected:

(self subpartNamed: 'OS/2-Windows Notebook') topPageIndex.

5. Connect `switchFromMe` to the `check` action of the form-checker part.

6. Create a script called `keepPageOnTop` as follows:

**Smalltalk**

keepPageOnTop

"Keep the last page selected on top of the notebook by

switching to it."

(self subpartNamed: 'OS/2-Windows Notebook')

topPageIndex: self lastPageSelected.

7. In the set method for `lastPageSelected`, be sure to add a catch for the special case when the notebook is first opened and the index is 0 instead of 1:
```
lastPageSelected: anInteger

| realPage |
realPage := (anInteger = 0)
ifTrue: [1]
ifFalse: [ anInteger ].
lastPageSelected := realPage
```

8. Connect the `checkFailed` event of the form-checker part to the `keepPageOnTop` script. Also connect that same event to the `showErrorToUser` action.

## Container Column List Box

**Question**

How do I create a container details column that displays a drop-down list box for each item?

**Answer**

Take a look at AbtContainerTreeChildrenAttributesPage and the methods `initializeHasChildrenAttributeList:` and `initializeChildrenAttributeList:`. Also take a look at EwEditPolicy. Another good place to look for examples is the EwExampleLauncher and CwExampleLauncher. You can load these by selecting the Smalltalk programming examples from the **Load Features** menu option. EwExampleLauncher is the one that you want to examine. Type `EwExampleLauncher new open`, select the code and execute it to bring up the example launcher. I think the EwxTableListExample contains exactly what you are looking for and the Abt stuff listed above will help you incorporate the code into the AbtLayer. EwxEditPolicy also contains similar examples.

## Columns with GUI Elements

**Question**

Can I create columns that contain GUI elements, in particular check boxes, so that the user can click a button to toggle a boolean?

**Answer**

Yes, but only for the container, as AbtTableView does not support this. Intercept the `aboutToBeginEdit` event and set the edit policy. See the `initializeChildrenAttributeList` method in `AbtContainerTreeChildrenAttributesPage` for an example. You would specify `EwToggleButtonEditPolicy` as the edit policy and initialize it appropriately.
## Adding Records to Container

**Question**

How do I add more records to a container after the user presses the page down key?

**Answer**

The *packetRequested* event is not signaled until an *at*: request comes into the *BufferedCollection* and is indexing into a slot that does not have a value. Do you know if this is occurring? What is happening? How many rows have you told the container that the virtual collection has?

## Changing Labels

**Question**

How can I change the color of the label that appears with an icon?

**Answer**

Below is an example of using the *AbtContainerIconListView* (hover help on parts palette shows 'Container Icon List'):

1. Add a container icon list to your visual part.

2. Create a script *aboutToOpenProcessing* to add a callback handler to do the background drawing. (See the sample code at the end of this message.)

3. Implement the appropriate callback method *drawBackground*. This method will be called twice, once for the icon image and once for the label.

4. Add a connection from your visual part *aboutToOpenWidget* event to the script *aboutToOpenProcessing*.

You are now ready to test your part; just connect the *items* attribute of the container icon list to the data items you want to display.
aboutToOpenProcessing
| iconListwidget |

"Get the container icon list wigdet (at the Ew* layer)"

iconListwidget: 'Container Icon List1' ) widget.

"Set up our own background drawing callback"

iconListwidget applicationDrawnBackground: true.
iconListwidget addCallback: XmNdrawBackgroundCallback receiver:
self selector: #drawBackground: clientData: nil.
drawBackground: aWidget clientData: clientData callData: callData

| oldColor anRC |

"Only draw the label background in this case"

(callData region == XmLABELREGION)
ifTrue: [ anRC oldColor anRC setForeground:
        (aWidget colorMap palette nearestPixelValue:
         (CgRGBColor red: 16rFFFF green: 16rFFFF blue: 0)).
        anRCable fillRectangle: anRC gc x:
        anRC x y: anRC y width: anRC width height: anRC height.
        anRC setForeground: oldColor ].

Deselecting Details Tree Items

Question

I have set up a container details tree to display two levels of information. A
second list box displays the selected entries from the first. When a parent
is expanded, and its child is selected, all works fine. However, if I collapse
the parent without deselecting the child, the child is automatically
deselected anyway. This does not seem to be the proper behavior upon
collapsing its parent. Is there a work-around to keep a child selected once
its parent is collapsed?
Answer

The philosophy of the tree views is that the children do not exist in the container unless they are displayed. The reason for this philosophy is that the container may contain a large number of items that have children that have children that have children. To optimize the tree views for performance, we do not hold onto the children and they change from collapse to expand (that is why we request them each time an item is expanded). Because they do not exist for the container they are removed from selection when the item is collapsed.

Smalltalk

addNotebookPage: aNotebook named: aName
| page label |
aNotebook subpartNamed: aName
    put: (page := AbtPortableNotebookPageView newPart).
page
    framingSpec: (AbtViewAttachmentConstraint new
        leftEdge: (AbtEdgeConstant new offset: 34);
        topEdge: (AbtEdgeConstant new offset: 90)).
page subpartNamed: 'label' put: (label := AbtLabelView newPart).
label object: Time now printString;
    framingSpec: (AbtViewAttachmentConstraint new
        leftEdge:
            (AbtRunEdgeAttachmentConstraint new
                attachment: XmATTACHFORM;
                offset: 65);
rightEdge:
            (AbtRunEdgeAttachmentConstraint new
                attachment: XmATTACHNONE);
        topEdge: (AbtRunEdgeAttachmentConstraint new
            attachment: XmATTACHFORM;
            offset: 95);
bottomEdge: (AbtRunEdgeAttachmentConstraint new
    attachment: XmATTACHNONE)).
page openWidget.
label openWidget.
## Resizing Container Columns

**Question**

How can I resize container columns on the fly?

**Answer**

I have resizable container columns by using the following snippet in an initialization method (`columnWidth` is a value that I calculated):

### Smalltalk

newColumns add: (AbtContainerDetailsColumn newPart
    heading: columnHeading;
    width: columnWidth;
    abtWhen: #cellValueRequested
    perform: (DirectedMessage new
    receiver: self;
    selector: #fillCell؛
    arguments: (Array with: nil)
);
parentView: (self subpartNamed: 'Row Container');
openWidget;
yourself).

This is the essence of the fillCell: method.

### Smalltalk

fillCell: callData
"Fill in cell data."

| columnIndex item |

columnIndex := callData column index.

"columnIndex is the column number"

item := callData item.

"item is the object associated with the row"

callData value: (item someMethod: columnIndex).

"set the cell value by getting some data from the object"
## Changing Scroll Bar Size

**Question**

I am working on a touch-screen-only application and the scroll bars on the container details part are too small for my fat fingers. Is it possible to change the size so even I can use it?

**Answer**

It appears that the only way to do this is to set `scrollingWithHiddenScrollBars` to `true` on the container details view, create the large push buttons with arrows (as in the multimedia support), and connect those buttons to the different scrolling events on the container details view.

## Container Details Tree Children

**Question**

Can you use a derived attribute for the children of the parent in a `ContainerDetailsTree`?

**Answer**

There is a limitation in container tree view. You need to ensure that the children of a parent are identical (`==`) each time they are accessed, otherwise the tree will refuse to expand.

In other words, you cannot use a derived attribute for the children of the parent, where there is the possibility that at different times, the children of the parent will not be identical objects. Instead, the first time you get the children of the parent you need to store them in an instance variable of the parent, so the next time the parent is asked for its children, it returns precisely the same children as it did last time. This of course precludes the children from ever changing.

The problem comes about because the tree view checks the children it had last time when it does the expand operation and, if the current children are not the same as the previous children, it assumes that the previous children have been deleted and does not expand them.

## Hiding the Heading on a Container Details View

**Tip**

To disable the heading of a container details view, make a connection from the column's `aboutToOpenWidget` event to the column's `heading` action. This must be done for every column but it works. It should not be hard to add something to the settings page of the container to encapsulate this behavior.
## Disabling a Notebook Tab

**Question**

How do I disable the tab of a notebook?

**Answer**

There are several kinds of notebook types, but one of them offers an 'aboutToChangePage'-type event that you can hook up to do the very thing you want to do.

## List with Icon Column

**Question**

How do I create a list with an icon column and several detail columns?

**Answer**

You need to use a details-tree container part. First, the column parts should have an attribute to display value specified in their settings view. Second, the objects that you are using as the items should have methods with the names you specified in the attribute to display fields of the column part's settings. For the column where you want the icon, its Attribute to display method should answer (return) an instance of `CgIcon`. Since the details tree container has multiple columns, you can specify an icon for any of the columns, not just one column and not just the first column. This is why the icon attribute of the visual information requested is not used. This also works with bitmap resources if you return them as pixmaps.

## Hiding a Column

**Question**

How do I hide a container details column using the hide action?

**Answer**

Hiding a container details column is not supported even though the actions to hide and show the column are in its public interface. The reason is that the interface actually inherits these actions. We are looking for a way avoid having unsupported features show up in the public interface.

## Removing an Icon

**Question**

How come, when you remove an icon from the icons collection of a container, it is still visible in the container view?
**Answer**

It is likely that the container does not get refreshed. There are a couple of solutions to that. You can send a `refreshAll` to the container which will update the view. You can also tear off the `items` attribute and use the following code to do the same:

**Smalltalk**

```
(self subpartNamed: 'itemsCollection''
    performActionNamed: #remove
    with: anItem.
```

## Adding Icons Dynamically

**Question**

How do I dynamically add icons to a container and use context menus in different variations?

**Answer**

To learn how to dynamically add icons to a container during run time, instead of statically during development time, see the example in the *VisualAge for Smalltalk User's Guide and Reference*, pages 229-236. This example allows you to use a context menu while clicking the second mouse button anywhere in the container surface except on top of the icons.

There are other ways to use the context menu. For instance, you may want to be able to bring up the context menu while clicking the second mouse button both on the container surface and on top of the icons. To do this, you just have to modify the following method:

**Smalltalk**

```
fillContainer: itemsCollection defaultAction: aScriptName

iconGadget := (AbtIconGadgetView new
  label: each;
  largeIcon: icon;
  parentView: container;
  openWidget;
  menu: ((self subpartNamed: 'Menu') yourself) ← add this line
  yourself).
```

By adding that one line, you can now click anywhere inside the container, including on top of the icons, and see a context menu.
Another variation to the use of context menus within a container is to click
the second mouse button on top of the icon and see a context menu, but not
see a context menu when you click the second mouse button from anywhere
else in the container. To do this, edit the same method, except that the
same segment of code now looks like this:

Smalltalk

iconGadget := (AbtIconGadgetView new
label: each;
largelcon: icon;
parentView: container;
openWidget;
menu: (((self subpartNamed: 'Menu') yourself)
  createWidget;
  setPostCreationSettings;
  yourself);
yourself).

In addition to changing this piece of code, you also must delete the
connection between the container's menu attribute and the menu's self
attribute.

After these few changes, you should be able to see a context menu by
clicking the second mouse button on the icons only, not on the container's
surface.

Refreshing a Container Details View

Question

What is the refresh design for a container details view?

Answer

You can use the `add:` API or perform the `add:` action. If you perform the action, the model will signal to its views (in this case the details view) that an item was added. The code works this way so you can add an item to the collection without having to refresh the entire list. You can set the `refreshEntireListOnChange` attribute to `true` to cause the entire list to be refreshed with each addition. The default for the containers is to have `refreshEntireListOnChange` set to `false` while the lists' default is `true`.
## Access to Container Object Attribute

**Question**

What event do I need to trigger from so that I can have access to an attribute of an object in a container icon area?

**Answer**

If you are using

**Smalltalk**

(self subpartNamed: '???') items addAll: (aCollection)

you are dealing with the ordered collection, which holds the items, and you are using their basic protocol. That collection's protocol does not know anything about event notification, which is VisualAge stuff. When using the second way

**Smalltalk**

(self subpartNamed: '???') performActionNamed: #addAll with: aCollection.

you are dealing with a variable that contains that ordered collection. It comes down to a method

**Smalltalk**

AbtObservableWrapper>>abtPerformActionNamed: actionName ifAbsent: aBlock arguments: args

Within that method a *signalEvent: #whateverYourActionIs* occurs.

## Removing an Icon

**Question**

How do I remove an icon from the container icon view?

**Answer**

Your problem may be that the container does not get refreshed. There are a couple of solutions to that:

1. Send a *refreshAll* to the container.

2. Tear off the items attribute and use something like this:
(self subpartNamed: 'items of blahblah')
performActionNamed: #remove with: anItem.

That causes a refresh of the container as well. You want to signal that the
items have been updated and then anything connected will refresh.

## Error: "Attribute Does Not Exist"

**Question**

In the container details part, what causes an "attribute does not exist" error?

**Answer**

Each of the objects in the items collection must have the attribute shown in the column header to get the data to display. If any of them doesn't, you will get an error.

## Adding an Icon to A List Part

**Question**

How do I set up a list part that can show an icon in the first column, followed by several detail columns?

**Answer**

You need to use a details-tree container part. First, the column parts should have an *attribute to display* value specified in their settings view. Second, the objects that you are using as the items should have methods with the names you specified in the *attribute to display* fields of the column part's settings. For the column that is to display the icon, its *attribute to display* method should answer (return) an instance of Cglcon.

## Drag-and-Drop

**Question**

I have developed a drag-and-drop-intensive application under OS/2 that works just fine. When I tried to port it to Windows, I expected it would work like the native style (right-button-drag on OS/2, left-button-drag on Windows) but I see this is not the case—I still have to drag with the right mouse button on Windows. Why?
**Answer**

The drag-and-drop function built into VisualAge is completely emulated and has nothing to do with the operating system settings. Which button is used internally is completely under Smalltalk control. The default is right-button drag under all operating systems.

If you want to use the left button on Windows to make the user interface on Windows conform to its standard, give this a try:

Smalltalk

EwDragAndDropManager default button: Button1

## Multiline Text

**Question**

I am developing my GUI via the Composition Editor. I added a text label, but now I want it to be multiline. I have a window like this:

<figure><img src="image_11.png" /></figure>

but I want it to look like this:

<figure><img src="image_12.png" /></figure>

Is there a way to achieve this?
**Answer**

Yes. Connect the *labelString* attribute of the label to this script:

```
Smalltalk
label
| cr |
```

```
cr := CldtConstants at: 'LineDelimiter'.
```

```
^this is', cr, 'a pen'.
```

## Window Titles

**Tip**

If a window is going to appear in the OS/2 task list, the title is clipped (by OS/2) to 64 characters. When we create a window in OS/2, we automatically add the title to the task list. The only windows whose titles do not get added are dialog windows. However, if you were programming this in C, you would have to add the window title to the task list explicitly. It should be possible to create a window in Smalltalk and not add the title to the task list.

## Querying the Caret Position in Text

**Question**

I have an entry field, such as a text edit field, or multiline edit field. I want to know where the caret (the blinking I-beam cursor) is within the text.

**Answer**

The parts you are talking about have the *queryCursorPosition* action. You can use it in a script or through a visual connection. It is described in the *VisualAge for Smalltalk User's Reference*.

## Color Bitmap Resolution

**Question**

How can I improve the resolution on 256 color bitmaps in Windows?

**Answer**

Basically, you have to set the palette of the window to be equal to the palette of the bitmap. To do this, connect the *openedWidget* event of your window to a script like the following:
### Smalltalk

fixColors
"Ask the image for its palette and
set the window to have the same palette."

| imageDesc |

imageDesc := (self subpartNamed: 'Form1')
backgroundGraphicsDescriptor.
(self subpartNamed: 'Form1') primaryWidget shell window set Palette:
imageDesc image palette.

(self subpartNamed: 'Form1') backgroundGraphicsDescriptor:
imageDesc.

**Note:** This example assumes that you are setting the background of a form.

## Automatic Tab Moving

### Question

How do I implement automatic tab moving in a VisualAge text field?

### Answer

You can implement auto-tabbing in VisualAge by writing some script and
making a connection to that script. Here is an example: Suppose you have
two text fields. Go into the settings of field1 and set its text limit to 5.
Then, connect the *object* event (make sure it is the event) of the text entry
field to the following script:

### Smalltalk

autoTab

| position limit |

position := ((self subpartNamed: 'paper1') queryCursorPosition).
limit := (self subpartNamed: 'paper1') textLimit.
(position = limit)
ifTrue: [ (self subpartNamed: 'paper2') setFocus ].

Now, if the user types five characters in the first text field, focus is
automatically set to the second text field.
**Question**

Is there a way to have it just tab to the next field? (I have around 10 fields and would rather avoid hard-coding all the names.)

**Answer**

Use some code such as:

```
Smalltalk
| widget list index next |
```

```
widget := (self subpartNamed: 'Window') framingWidget.
```

```
list := widget tabList.
```

```
index := list indexOf: ((self subpartNamed: field name)
primaryWidget).
```

```
next := list at: (index + 1).
```

```
(next,，《userData）setFocus
```

We hooked this to a text field and passed in the self of the text field as the parameter.

This code is given as-is. That is, it has some drawbacks. First, when you get to the end, you will have to know the number to reset it to. We don't have that check in the code above. And, when it gets to a group of push buttons, I'm not sure of the behavior (it may just go to the first in a group). This is a good start, however, and the concerns mentioned can be checked for in a script.

## User Input Error

**Question**

How can I get the `userInputConvertError` event to fire if the user does not change an invalid field?

**Answer**

You must modify the method

`AbtTextConverterManager->#primCommitUserInput:` to handle this or run this script (using `aDateString` as an example) when losing focus:

```
Smalltalk
(AbtDateConverter new) primDisplayToObject: aDateString
ifError: [^error]
CwAppContext default asyncExecInUI: aView setFocus.
```
Closing the Window

Question

When I press the Esc key, the window closes. What event is triggered by
pressing the Esc key? Can I capture this event to alter the behavior?

Answer

Yes. Connect the shell's *closeWidgetRequest* event to a script like this:

Smalltalk

myShellCloseWidgetRequest: aConfirmationCallbackData

aConfirmationCallbackData doit: false.

The window won't close as long as *doit*: is set to *false*. When you use
*openOwnedWidget* as opposed to *openWidget*, you are actually creating a
dialog box as opposed to a standard frame window. It is the dialog box that
provides the default behavior of closing when the Esc key is pressed (and
this is operating system behavior, not part of VisualAge).

The solution above hooks to the system *close* action. Since you are
bringing up a dialog, the Esc key is mapped to *close* by the CwDialogShell
class (for details, see AbtShellView class>>cwModalWidgetClass and
AbtShellView>>primCreateWidget). If you do not set an owner window,
the CwTopLevelShell is used as the shell class (see AbtShellView
class>>cwWidgetClass).

You could map the Esc key (or any key you prefer) to close. Here's an
example. First, connect the Window part's *openedWidget* event to a script:

Smalltalk

hookKeyReleaseEvent
(self subpartNamed: 'Window') components do: {:view |
view primaryWidget
addEventHandler: KeyReleaseMask
receiver: self
selector: #keyReleased:clientData:callData:
clientData: nil}

This puts a key release hook on every widget under Window. Next, add a
method to handle the key release:
Smalltalk

keyReleased: w clientData: d callData: callData
(callData keysym == XKCancel) ifTrue: {self closeWidgetCommand}.

Note: XKCancel is the Motif name for the Esc key.

## Transparent Background

**Question** How can I make the background of some text placed on top of a bitmap be transparent?

**Answer** CwLabels cannot be made transparent. I suggest you hook the expose callback of the form and draw the text yourself.

## Getting the Anchor Block Handle

**Question** How do I get the anchor block handle of a primary visual part?

**Answer** Here is an example of how you can get the anchor block handle of your primary visual part:

Smalltalk

(self subpartNamed: Window) yourself primaryWidget
osWidget handle winQueryAnchorBlock

## Turning Off Error Message

**Question** How do I turn off the error message ** error ** that is shown by data converters such as AbtStringConverter on text parts?

**Answer** Turn off the setting *reformatOnFocusChange* for each of the text fields you wish to affect. You can do this in the settings notebook.
## Locating the Focus

**Question**

How can I determine which form contains the widget that has the focus?

**Answer**

The following code shows how you can determine which widget has the focus:

### Smalltalk

queryFocusForm

| focusWidget focusView |

focusWidget := self shell focusWidget.

(focusWidget notNil and:

[ (focusView := focusWidget userData) isKindOf: AbtBasicView])

ifTrue: [

[ focusView notNil and: [ focusView isKindOf: AbtFormView ] ]

whileFalse: [ focusView := focusView parentView ] ].

^focusView

Note that *userData* of the widget of AbtBasicView subclasses refer back to their view. You could accomplish the same thing by iterating the target form components and comparing their widget against the focus widget, but the above is quicker.

## Bitmaps on Buttons

**Question**

Is there a way to drop a bitmap (BMP) on a button visually?

**Answer**

Yes. Use the following code:

### Smalltalk

myPushButtonView graphicsDescriptor:

(AbtImageDescriptor new moduleName: 'bitmap.bmp')
Progress Indicator Window

Question

I would like to use a progress-indicator window in my application. I can't seem to find a ready part for this. CwWorkingDialog seems to be the base part, but it does not provide the *percentage completed* support. The EtWindow class seems to offer all support, but I am confused as to how to get it started. What would be the recommended way for implementing a progress indicator window?

Answer

The following example shows how you can use the CwProgressDialog to create a progress indicator:

Smalltalk

| shell main form dialog fraction |

shell := CwTopLevelShell createApplicationShell: 'shell'
  argBlock: [ :w | w title: 'Main' ].

main := shell createMainWindow: 'main'
  argBlock: [ :w | w width: 400; height: 300].

form := main createForm: 'mainForm' argBlock: nil.

form manageChild.

main manageChild.

shell realizeWidget.

dialog := CwProgressDialog for: main.

dialog mwmInputMode: MWMINPUTFULLAPPLICATIONMODAL.

dialog open.

[[ (fraction := dialog fractionComplete) < 1 ] whileTrue:
   [ (Delay forSeconds: 1) wait.

fraction := fraction + (1 / 10).

dialog fractionComplete: fraction ].

dialog close ] fork.
## Hot Spots

**Question**

If I try to set the `borderWidth` attribute for a hot spot, either from the *General* page for the part or from code, I see these settings when I query the value. However, what is the reason that I won't be able to actually *see* the border?

**Answer**

You can't see the hot spot because it is never mapped. It is generally used as a clickable spot for images, hence it does not draw any border.

**Question**

How can I create hot spots that can be reshaped?

**Answer**

Create a subclass of AbtHotSpot, overriding the `containsPoint:` method. Create a subclass of AbtHotSpotView and override `postCreationInitialization` to use your AbtHotSpot subclass. Hot spots can only be rectangular. However, if you need a nonrectangular shape, you can try using multiple smaller hot spots that are next to each other to approximately cover the area you need.

**Question**

How do I find the coordinates of a hot spot?

**Answer**

To get the x and y coordinates of the hot spot, send it the message `x` or `y`. To get its width and height, send `width` or `height`. This is true for all parts.

## Links

**Question**

What is a link in the world of drag-and-drop?

**Answer**

Link means that the instances dropped get added to the target and remain in the source. *Copy* duplicated the instances and *move* deletes them in the source.

## Wallpaper

**Question**

How do I display an image as a wallpaper with more than 16 colors?

**Answer**

Here's a complete script you can use and connect to the `openedWidget` event of the window:
### Smalltalk

```
showWallpaper
| anImageDescriptor |
```

```
anImageDescriptor := AbtImageDescriptor new
  moduleName: '< d:\myPath\imageFileName >';
  yourself.
(self subpartNamed: 'Window') primaryWidget shell window set Palette:
  anImageDescriptor image palette.
(self subpartNamed: 'Window') backgroundGraphicsDescriptor:
  anImageDescriptor.
```

In the (`self subpartNamed: 'Window'`) above, `'Window'` should be replaced with the name of the part where you want to specify the wallpaper.

### Question

Is it true that the wallpaper of a window part under Windows 3.1 can represent only 16 colors?

### Answer

Under Windows, by default, the color palette of the image is mapped to the closest values of the system palette. Typically, the system palette does not have many of the colors found in most bitmaps, so the mapping is poor. To get the image to appear the way you want, add the following code snippet just before you display your image.

### Smalltalk

```
<myWindow> primaryWidget shell window set Palette:
<myImageDescriptor> image palette
```

This code snippet must be executed after `<myWindow>` has been opened.

## Labels on Message Prompter

### Question

Can I change the labels on an AbtMessagePrompter?

### Answer

No. AbtMessagePrompter uses CwMessagePrompter, which uses the native operating system API, such as WinMessageBox under OS/2, and that does not support button string substitution. I suggest creating your own view with your message, then displaying it as a dialog, like this:
myView openApplicationModalWidget suspendExecutionUntilRemoved.
(myView result == ...) ifTrue: ...

The *result* method is implemented by your view and is the result of the user's selection, probably saved in an instance variable.

## Visual Part Reuse

**Question** Can I reuse my visual parts?

**Answer** Yes, by creating reusable forms. Create a new visual part, then select and delete the default window. Add a Form and make it the primary part. Lay out your GUI design and add in any functionality you like. Save the part and add it to the palette for everyone to reuse! You can also reuse menus.

## Supported Image Formats

**Question** What are the image formats that VisualAge for Smalltalk supports?

**Answer** Individual bitmap files and icon resources in DLLs work for push button images and for wallpaper. You can also have individual graphic files. Open the settings on the button and choose label type Graphic, graphic type Image and enter the filename (should be path relative to your VisualAge directory). Enter a text label first if you are using hover help, since the text for the button is what appears.

## Click-Sensitive Bitmap

**Question** How do I display a bitmap and then sense mouse clicks over it?

**Answer** Look at the Graphic Link example (AbtGraphicLinkView) in the VisualAge Help Example feature. It uses Smalltalk code to track mouse clicks and movements over a bitmap. For your application, you might put hot spot parts on the bitmap.
## Setting Help

**Question**

How do I programatically set the help file and help topic IDs for the menu items?

**Answer**

I assume you want to use a symbolic name that will be mapped to an actual name at execution time. This is handy for dealing with files whose names include version information. For example, ABTVAE30.OS2 contains such a mapping entry. The entry *abtvahelp* is the symbolic entry we use in the settings view as the help file name. It is mapped to an actual file name of ABTVAE30 at execution time. When we updated the file for Version 4 to ABTVAE40, we simply updated the one entry in the mapping file and did not have to touch any code. The entries in a given mapping file do not support automatic substitution. The design is such that the name of the mapping file can vary by platform (for example ABTVAE30.OS2 is the English version while ABTVAJ30.OS2 would be Japanese) and these mapping files would map the symbolic name to the appropriate locale-specific name. Your application would then register the mapping file with the locale character as a wild card. You can see an example of this in the method AbtEditBaseApp class>>#loaded. Create locale-specific versions of the mapping file where, within each mapping file, a consistent symbolic name maps to the locale-specific actual (absolute) file name and then register the mapping file name with the locale character as a wild card.

## Modifying Data Entry Parts

**Question**

Is there a *userModified* event for data entry parts?

**Answer**

The available events are *losing focus*, which occurs whether the field value has changed or not, and *object*, which is triggered for any changes including user and programmatic changes.

## Reacting to Keyboard Input

**Question**

How do I receive keyboard input and react to it?
**Answer**

You can set up an event handler to handle key press events and check for the F4 there. See page 188 of the *IBM Smalltalk Programmer's Reference* for a description and example of this. Add an event handler to your window:

**Smalltalk**

(self subpartNamed: 'Window') primaryWidget
addEventHandler: KeyPressMask
receiver: self
selector: #keyEventHandler:clientData:event:
clientData: nil.

Then you handle the event like this:

**Smalltalk**

keyEventHandler: widget clientData: clientData event: event
Transcript show: event keysym printString

## Using Esc to Close Nonmodal Dialog

**Question**

Can I use Esc to close a nonmodal dialog?

**Answer**

Since you are bringing up a dialog, the Esc key is mapped to close by the CwDialogShell class (see AbtShellView class>>cwModalWidgetClass and AbtShellView>>primCreateWidget for details). If you do not set an owner window, the CwTopLevelShell is used as the shell class (see AbtShellView class>>cwWidgetClass).

You could map the Esc key (or any key you prefer) yourself to close. Here's an example. First, connect the Window part's *openedWidget* event to a script:

**Smalltalk**

hookKeyReleaseEvent
(self subpartNamed: 'Window') components do:
  [ :view | view primaryWidget
    addEventHandler: KeyReleaseMask
    receiver: self
    selector: #keyReleased:clientData:callData:
    clientData: nil ]
This puts a key release hook on every widget under *Window*. Next, add a method to handle the key release:

### Smalltalk

```
keyReleased: w clientData: d callData: callData
```

```
(callData keysym == XKCancel) ifTrue: [self closeWidgetCommand].
```

**Note:** `XKCancel` is the Motif name for the Esc key.

## Multiline Edit Part and Tab Order

**Question**

If I drop a multiline edit part on a window, I can't use the tab key to navigate through the different objects on the window. The multiline edit part uses the tab key for spacing. Is there another way to navigate through the window?

**Answer**

You can use `Ctrl+Tab` instead to navigate through the different objects on a window.

## Using Predefined Function Keys

**Question**

Why does the following code not work to catch the event when pressing a function key? The code adds an `eventHandler` to the widget of the part and should cause a debugger window to come up as soon as an function key is pressed.

### Smalltalk

```
| widget |
widget := (self subpartNamed: 'myForm') primaryWidget.
widget addEventHandler: KeyPressMask
    receiver: self
    selector: #keyPressed:clientData:event:
    clientData: widget.
```

The event handler looks like this:
### Smalltalk

```perl
keyPressed: widget clientData: clientData event: event
| key |
key := event keysym.
```

```perl
(key = XF10 | key = XF22) ifTrue: self halt.
```

```perl
(key = XF9 | key = XF21) ifTrue: self halt.
```

### Answer

The above code is correct, but you should take into account that some of the function keys have been reserved for the system. For example, PF10 on a window (with a menu bar) will move the cursor to the first menu bar item. Hence the debugger window will not come up in the above example.

## Grabbing Typed Words

### Question

When using a multiline edit (MLE) window, I would like to grab the words as they are typed. The only event I saw that looked like it might be of use was the notify on each key stroke. If I use that, I'd have to look for a blank and then post a signal that a word has been completed. Am I missing something? Is there a mechanism already there?

### Answer

No you are not missing something. The MLE does not parse its own text. If you are interested in dropping to the widget layer, you can also check out the `XmNvalueChangedCallback` and `XmNmodifyVerifyCallback`. The `XmNmodifyVerifyCallback` is fired before the text shows up when the user has typed a character. The `XmNvalueChangedCallback` is fired after the text has been displayed in the MLE.

## Dropping an Item on a Push Button

### Question

How can I use the drag-and-drop operation between one item of a list box and a graphical push button representing a trash can? It seems that when I drop an item of the list box on the graphical button, my icon is replaced by the label of the item.

### Answer

What is described above is the default behavior. However, all of the drag-and-drop events are public, so you can do whatever you want. The way to get the graphical push button to remain graphical is to connect the `dropped` event of the push button to a script that accepts a parameter. The parameter will be an instance of `EwDropCallbackData`. It contains information on what you just dropped on the push button as well as other
things. Be aware, though, if you connect from any of these drag-and-drop
events, you become responsible for what happens in these cases.

Changing a Part's Settings View

Question

I created a newTextView part inherited from AbtTextView and extend it with
a new attribute dataRequired of type Boolean to see if this field must include
data or not.

Now I want to add a toggle button for this attribute to the attributes page in
the part's settings notebook. I found a class AbtTextViewAttributesPage in
the subapplication AbtEditViewsSubApp which probably defines this
attributes page. In opening this view part, I do not see anything except
some connections that point to nowhere. In testing the view part I get the
attributes page. Why do I get this behavior?

Answer

It is a little strange, but you are not seeing anything because the form has
no size when you edit the settings page. It has no attachments so it
tight-wraps around its children. Here's what you can do:

1. Select **View Parts List**... to bring up its settings and change its size to nonzero.

2. Modify the view as you want.

3. Generate archival code and remove the code that sets the form size.

4. Regenerate the run-time code (see the *test* method in the archival code for details).

Steps (3) and (4) are necessary because the Composition Editor does not provide a way to specify that the form is an unattached form (what is called a *shrink-wrap* form).

Hiding Table Columns Dynamically

Tip

If you want to hide one or more columns of a table, here is what you have to
do. Unfortunately, no action is available that lets you hide a column. You
can, however, hide the entire table. As a work-around, you can simulate the
wanted behavior by manipulating the *ratioWidth* of the column: Setting the
value to zero will make it look as though the column has been hidden.
Initializing a View Wrapper

Question

When I use a view wrapper, the widget does not get created until I send it
the openWidget request. Therefore, I can't do anything (for example, set
some of its features) until after the first time I've issued openWidget which
in many cases is not desirable. I got around this by the following code:

Smalltalk

((self subpartNamed: 'MyWindow') value) isNil
ifTrue: [
(self subpartNamed: 'MyWindow') createValue].

However, both *value* and *createValue* selectors are private. How can I solve
this problem without resorting to the use of private methods?

Answer

You should be able to set feature values via attribute-to-attribute
connections. Although the connections will not actually do anything until the
view is created, once it is, all the connections are aligned.

Adding Columns to Tables

Question

How can I dynamically add columns to a table?

Answer

Here is some code that will give you the ability to add columns dynamically.
Smalltalk

AbtTableView>>addLastColumnNamed: aColName
columnHeader: aColumnHeader
attributeName: anAttributeName
readOnly: aBoolReadOnly
converter: aConverter

"Public - This is a helper function which will create a new column view and add it to the table. The column will be added to the end of the table. Its width will be equal to the width of the most narrow column currently in the table."

| cv |
ailing the cv
(cv := AbtTableColumnView new)
attributeName: anAttributeName;
columnHeader: aColumnHeader;
readOnly: aBoolReadOnly;
ratioWidth: self suggestedNewColumnWidth;
converter: aConverter.
self subpartNamed: aColName put: cv.
cv openWidget.
^true

Smalltalk

AbtTableView>>subpartNamed: aColName put: aColumnView

| colNdx |
(self components includesKey: aColName)
ifTrue: [ ^false ].
colNdx := self components size + 1.
self subpartNamed: aColName put: aColumnView partIndex: colNdx.
### Smalltalk

```
AbtTableView>>suggestedNewColumnWidth
```

"Use this method when adding new columns dynamically at runtime to prevent the new column from being too small."

```
| ans |
self components size = 0
    ifTrue: [ ^1 ].
ans := 9999999999.
self components
do: [ :col | ans := ans min: col ratioWidth ].
^ans
```

### Smalltalk

```
AbtTableColumnView>>openWidget
```

"Public. Category: AbtRun-Internal"

```
| pv |
(pv := self parentView) == nil ifTrue: [ ^self ].
pv setUpWidget.
```

## Synchronize Table Scrolling

### Question

Is there any way of synchronizing the scrolling of two tables in the same window? I would like to move the vertical scroll bar of one table and have the scroll bar of the other table move in the same way.

### Answer

To synchronize the scrolling of two tables, you will have to use callbacks. The slider bar is a CwScrollBar widget. Callbacks can be specified for the various slider requests (for example, moving the slider, clicking on the arrows). Each callback method will have to scroll the second table. For example, suppose you set up an increment callback for table A. The method specified for this callback gets called every time the user clicks on the slider bar down arrow. The callback method will have to scroll the second table down one row.

To synchronizing scrolling between two tables, you would need to add callbacks for each type of scroll request. In addition, you would need to add them for both CwScrollBar widgets.
## Changing Table Size

**Question** How do I create a table that can grow and shrink in size?

**Answer** Create an example of what you want, save that part, then look at the `abtBuildInternals` method. It shows the code that constructed the part. You can copy or modify it to dynamically add parts. A common mistake is to forget to send `openWidget` to the newly added part (including container detail columns)—it is necessary if the view is already open.

## Table List Part

**Question** Is there a table list part that has capabilities like row selection and programmatic column setting?

**Answer** `EwTableListExample` fullfills these requirements. `EwTableList` is the `CommonWidget` class used by the Container Details View available on the parts palette.

## Reusable Table Part

**Question** How do I create a reusable table part?

**Answer** You should promote the width attribute of each column so it becomes an attribute of the reusable part. They should be able to change the width through the settings of the reusable part or via a script. The width cannot be changed with the mouse because embedded parts are treated as singular primitive objects.

## Changing a Table Cell

**Question** How do I keep track of changes made to a cell in a table?

**Answer** It may be best to track this at the model level, not the view. That is, register interest in your model for the events that are important to you. For example, `self` for an ordered collection dropped on the free form surface will give you notification every time the collection changes. Presumably your model is more interesting than an ordered collection (`person`, `employee`, `company`, whatever), so you should register interest in whatever event is important to you (based on the public interface you defined).
## Selecting Multiple Rows

**Question**

How do I select multiple rows in a table part?

**Answer**

You can do this using the Container Details View. You just go into the settings and specify *Multiple* as the selection type.

## Changing Push Button Activation

**Question**

How can I change push-button enablement when text is entered in a textbox?

**Answer**

There are several ways to go about doing this depending on what you'd like to happen. Here are two examples:

The first example starts off with a text box and a push button that's initialized as disabled. You can disable a push button initially by going into the settings for the push button and removing the check mark next to the enabled box. Disable the push button before making the following connection. Connect the object event of the text box to the enabled action of the push button. Then go into the settings of the connection, select the set parameters button, and set the value to *true* (check the value box). This causes the push button to be disabled until any text is entered in the text box. The push button then remains enabled. If you want the push button to again become disabled for whatever reason, you would have to write script for that. Which leads to the next example...

The second example starts off exactly like the first example. The view contains a textbox and a disabled push button. This push button will remain disabled until text is entered into the text box and the text box loses focus (as when you tab out). As soon as the text box loses focus with text entered into it, the push button becomes enabled. If you then go back to the text box, delete the text, and tab out of it, then the push button becomes disabled again and will remain disabled until text is entered into the text box. This is accomplished by writing a small script that looks something like this:
enableButton

| info |

info := ((self subpartNamed: 'Text') string).

(info empty)

ifTrue: [(self subpartNamed: 'Push Button') enabled: false]

ifFalse: [(self subpartNamed: 'Push Button') enabled: true].

You would connect the losingFocus event of the text box to this script.

## Event Handling in Windows, AIX, and OS/2

Tip

OS/2 does not work the same as Windows and AIX when it comes to event handlers. OS/2 propagates messages up the parent tree. For example, if I have a main window with three text fields, a drop-down list, and a spin button, and I add an event handler to detect key presses to the main window, the child widgets also receive those messages and handle those key press events (on OS/2). However, on Windows and AIX this is not the case; the messages are not propagated to all children. To get around this, you can write Windows- or AIX-specific code to send the message **recursiveDo**: to your main window and set up the same event handler or callback for all the children, the children's children, and so forth. You probably create a resource hog to do this, but it's really the only way to achieve this effect on Windows or AIX.

**Note:** Using **recursiveDo**: will not help you with widgets (controls) that are composites at the operating system level. For example, this will not solve the problem on Windows where you can't get pointer motion notification over certain parts of the combo box control. From Smalltalk's perspective, there is only one view (and hence nothing to recurse) while there are actually two to three window handles at the operating system level.
## Part Validation

**Question** How do I execute an error script every time a user leaves a part to be validated?

**Answer** You must modify the method `primCommitUserInput:` in `AbtTextConverterManager` to handle this or run this script (using `aDateString` as an example) when losing focus:

**Smalltalk**

```
(AbtDateConverter new) primDisplayToObject: aDateString
ifError: [ :error ]
  CwAppContext default asyncExecInUI: aView setFocus.
```

## Moving Icons

**Question** How do I move icons around in a window?

**Answer** If the icons were drawn as a label widget, you would use `CwWidget>>#makeGeometryRequest:replyReturn:` if the label is an attached widget, otherwise `CwWidget>>#moveWidget:y:` (see the comments of these methods for more details). Moving a widget to simulate a spinning effect, for example, probably wouldn't look very smooth. I'd probably go directly to the `Cg` layer, using a variation of the code in the `CgClock` examples (for drawing the wheel points) and perhaps `CgStix` for animating the spinning of the arrow.

## Printing a Form with a Visual Part

**Question** How do I print a form I created that contains a visual part?

**Answer** You create a `CwPrinterShell`, initialize the shell on the map callback, and draw your text during the expose callback. The printer shell has additional APIs to support job and page start and end. You can set fonts and colors by modifying the attributes of the graphics context (GC) for the printer shell. `CwTextPrintingManager` uses `CommonPrinting` to print workspaces; you can see the basics there.
## Text Box Problem

**Question** I have a problem using the `defaultActionRequested` event of a text box. How do I fix it?

**Answer** This is a known problem. You'll need to change the method `postCreationInitialization` in `AbtTextView`. Locate the following piece of code in the method and remove it:

Smalltalk

```
widget addCallback: XmNactivateCallback
```

```
receiver: self
```

```
selector: #defaultAction:clientData:callData:
```

```
clientData: nil.
```

## Reusable Table Part

**Question** How do I create a reusable table part with different widths?

**Answer** Promote the width attribute of each column so it becomes an attribute of the reusable part. You should be able to change the width through the settings of the reusable part or via a script. The width cannot be changed with the mouse because embedded parts are treated as singular primitive objects.

## Trap the Enter Key for Tabbing

**Question** I want to add a callback (XmNactivateCallback) to a toggle button so that I can trap the Enter key to do the tabbing. Would this be the right way to do this?

**Answer** To do this, use an event handler rather than trying to add a callback not supported by the widget. The following example sets up four toggle buttons in a view. Run the following script when the `openedWidget:` event fires:
setupEventHandlers
| tog1 tog2 tog3 tog4 |

tog1 := (self subpartNamed: 'Toggle Button1') yourself.
(tog1 primaryWidget)
    addEventHandler: KeyPressMask
    receiver: self
    selector: #tabTo2:clientData:event:
    clientData: nil.

tog2 := (self subpartNamed: 'Toggle Button2') yourself.
(tog2 primaryWidget)
    addEventHandler: KeyPressMask
    receiver: self
    selector: #tabTo3:clientData:event:
    clientData: nil.

tog3 := (self subpartNamed: 'Toggle Button3') yourself.
(tog3 primaryWidget)
    addEventHandler: KeyPressMask
    receiver: self
    selector: #tabTo4:clientData:event:
    clientData: nil.

tog4 := (self subpartNamed: 'Toggle Button4') yourself.
(tog4 primaryWidget)
    addEventHandler: KeyPressMask
    receiver: self
    selector: #tabTo1:clientData:event:
    clientData: nil.

tabTo1: widget clientData: clientData event: event

event type = KeyPress
ifTrue: [ (event keysym == XKReturn)
    ifTrue: [ (self subpartNamed: 'Toggle Button1') setFocus] ].

tabTo2: widget clientData: clientData event: event

... and so on ...
## Creating an Operation-in-Progress Window

**Question**

I would like to create an In-Progress window that gets displayed while the application is off querying a database. I want to block the user interface so the users won't be able to start queuing up a lot of database queries, which leads to a cache resource error. I have tried opening an in-progress window as a full application modal but I am not satisfied with the ability to hit the Esc key and exit out of the in-progress window. Is there another way of doing this?

**Answer**

The VisualAge for Smalltalk processing window is achieved by:

**Smalltalk**

```
execLongOperation: [ aBlock with your long running stuff ]
message: 'I am thinking, please wait...'.
```

But to be honest, this is only half the story, because the message is implemented by AbtShellView. That means you have to send it to the current window. That in turn leaves the problem how to find the *actual* window (for example, the one having the focus). You could use something like this:

**Smalltalk**

```
CwTopLevelShell allShells reverseDo: [ :sh |
sh hasFocus ifTrue: [ ^ sh userData ].
].
```

This method returns the window having the focus and accepts the `execLongOperation:message:` message. If you don't pick the window having the focus, the focus in your application changes to the window you reference. This is quite confusing for users— at least, so they tell me. The above examples work in Version 3, and have not been tested in any other version.
## Progress Messages

**Question** How are the progress messages in the browsers implemented?

**Answer** The CwProgressDialog implements the *in-progress* indicator (no buttons, just a message and a bar).

## Limiting the Number of Lines in Multiple-Line Editor

**Question** We need to limit user input to 30 lines with 60 characters per line. Is there a way to do this using a multiline editor part? I see only the ability to specify 1800 (30 * 60) characters as the maximum number for the multiline editor part. This won't do because the user could type 1800 new-line characters, much more than the 30 lines maximum we want. If a multiline editor part is not usable, any suggestions?

**Answer** You are correct, there is no way to set the number of lines a user can enter into a multiline editor part, only the total amount of text. You could, however, write a script that does this type of checking and formatting. You would need to invoke the script every time the user presses a key. The script could determine the number of lines in the multi-line editor part by keeping a count of the number of line delimiters entered in the multiline editor part's text. The script could also force a new line if the user has typed in 60 characters but failed to hit the new-line key.

## Disabling a Button

**Question** Suppose you have a text entry part and an add button. How can you disable the add button whenever there is no text in the text entry part?

**Answer** If the text entry part is connected to the selected item in the list part, you can connect the button's *enabled* attribute to the *selectionValid* attribute of the list.

If the button is independent of the list, you have to write a small script and connect a *string* event—*string* in the text entry part has been changed—to the script. You should probably set the button to be disabled initially (from the settings notebook for the button). The sort of script you need is:
```perl
setButtonForString: aString
"Disable the button if the string is empty, otherwise enable it."
```

```perl
(self subpartNamed: Button') enabled: (aString notEmpty)
```

## Accelerator Keys

**Question** I am trying to use accelerator keys for some menus that I would like to have in my application. Is it possible to use accelerator keys for menu items?

**Answer** Defining accelerator keys is not supported for menu items in pop-up menus. They are supported only for menu items in the menu bar. The underlying reason is because pop-up menus are not created until the user clicks the right mouse button, and this would be when the accelerator table gets created. The accelerator table then gets destroyed when the pop-up menu goes away. In effect, if you have defined accelerator keys for a menu item in a pop-up menu, and hit for example Ctrl-V, the menu has not been created so the event does not get signaled. If it would be appropriate in your application, you could design duplicate menus in your menu bar with (accelerator keys defined) for each pop-up menu you have. That is how we have dealt with this in the development environment.

## Hover-Help on Widgets

**Question** Is it possible to get hover-help for push buttons, entry fields, and table cells as well as simple icons? The documentation implies hover-help works for icons only.

**Answer** The underlying support for hover-help is implemented as an extended widget and can be used for all widgets that support mouse move callbacks. Thus, hover-help does work for other than icon push buttons. Working with icon push buttons is the only case where, by default, a hover-help tag is displayed. Entry fields, for example, have no string resource to use as a default hover-help tag. In these cases, you need to hook the pop-up callback and provide the hover-help string to be displayed in the callback data.

The widgets not supported for hover-help are those that do not signal mouse moves; such widgets are platform dependent. For example, on some platforms drop-down list boxes do signal mouse moves when the pointer is
over the drop-down button, but *do not* signal mouse moves when the pointer is over the text portion of the drop-down list. On those platforms, hover-help is not supported for drop-down lists. There currently is no list of unsupported widgets, since whether the widgets signal mouse moves depends entirely on the operating system's implementation of the control.

## Improving Performance

**Tip**

In order to improve performance with our application (which uses many complex notebook objects) and to help with memory utilization, we implemented an approach that hides existing visual objects rather than the *closeWidget* approach. When the application needs to open a notebook, we iterate through existing instances of the visual class and *show* them rather than issuing an *openWidget* event.

This has had a dramatic performance improvement in our application, making it perform as well as or even better than some C++ applications which may display many complex notebook objects. The notebook snaps open and clicking on the notebook pages is immediate.

## Tabbing Order

**Question**

Is there an explanation somewhere of how to set tabbing order in a variety of situations? The simple case is straightforward and one can happily drag the yellow tags around to change the order. But what do the blue tags mean and how are they manipulated? Also, how can you create different traversal groups for separate groups of buttons?

Suppose you have a form which contains a set of buttons plus another group of buttons directly placed on the window. The yellow tags show '3:1' and '3:2' on the directly placed buttons but there is a blue tag showing '3' on the buttons form. The form gets tabbed to first when you want the other buttons to be tabbed to first. Is there a way to change this?

**Answer**

When you see 1, 2, 3 ... (whether it's blue or yellow), that means it is a tab group and you use the tab key to navigate to or from it. In this case, yellow indicates that it is a tab group consisting of one part only. An example would be an entry field. Blue indicates that it is also a tab group, but that it has multiple parts within it. An example would be the form with multiple push buttons in it.

You typically want to navigate between push buttons using the arrow keys, so when you place push buttons directly on the window, it defaults to
traversal only. Consequently, you see numbers like 1.1, 1.2, 1.3, ... It's acting as though it's within a tab group, and will always be added as 1.x.

Since you can change the tab order of parts at the same level only, you have two options. Do not put the push buttons directly onto the window, put them in a form as with the other push buttons. Or, check the tab group option on the individual push buttons. You will have to use the tab key to navigate to and from these push buttons if you choose the latter option.

## Ctrl-Click Events

**Question**

I can set individual button press (ButtonPressMask) and key press (KeyPressMask) event handlers. But how can I detect if a key was pressed at the same time a mouse button was pressed? I am trying to differentiate between a mouse button-Ctrl key event and just a mouse button pressed event.

**Answer**

You will have to process the keyboard key and mouse button events individually. A suggestion is to set a flag when the mouse button has been pressed (but not released). When you process the keyboard key event, check to see if the mouse button flag has been set. If it has and the Ctrl key was pressed, execute your mouse button+Ctrl code. You will need to clear the mouse button flag whenever the mouse button is released.

Here's another, probably easier way, of doing the same. The method that processes the keyboard key event can check the event state. If the state is Button1Mask and the key pressed is Ctrl, execute your mouse button+Ctrl code. Here is what the code would look like:

**Smalltalk**

```
(event state = Button1Mask) & (event keysym = XKControlL)
```

... mouse button+Ctrl logic
## Creating Push Buttons

**Question** How do I create push buttons on the fly?

**Answer** You have two different approaches:

1. You do it in pure Smalltalk: starting from the parent part, such as an AbtFormView, you do:

Smalltalk

```html
(<part> widget createButton: 'myButton' argBlock: nil)
  manageChild.
```

In the *argBlock* you could specify the widget attachments. The disadvantage is that this will leave you without an AbtButtonView part, which may be inconvenient.

2. The other method is adapted from the *abtBuildInternals* method:

Smalltalk

```html
<part> subpartNamed: 'button' put:
      (tVar:= AbtButtonView newPart).
tVar openWidget.
```

The *openWidget* will actually draw the button. To position it properly you might add a *framingSpec* (look into *abtBuildInternals* of a visual part for an idea of how to do that).

If that does not satisfy you, add the maximum amount of buttons in the Composition Editor and use the *hide/show* protocol to dynamically hide and show your buttons. For buttons you need initially invisible, you send a *hide* attached to the *aboutToOpenWidget* event of your window, so they won't show.

## Changing Part Labels

**Question** How do I change the labels on the AbtMessagePrompter part?

**Answer** You can't because AbtMessagePrompter uses CwMessagePrompter which uses the native operating system API (for example, WinMessageBox under OS/2) and that doesn't support button string substitution. I suggest creating your own view with your message, then displaying it as a dialog, such as
Smalltalk

myView openApplicationModalWidget suspendExecutionUntilRemoved.
(myView result == ...) ifTrue: ...

The *result* method is implemented by your view and is the result of the user's selection, probably saved in an instance variable.

## Adding BMP Files to Buttons

**Question**

Does VisualAge support putting BMP files directly onto buttons?

**Answer**

Yes, since VisualAge for Smalltalk Version 3. Good-bye one DLL; hello dozens of .BMP files. Use the following code:

Smalltalk

myPushButtonView graphicsDescriptor:
(AbtlImageDescriptor new moduleName: 'bitmap.bmp')

## Creating a Prompter

**Question**

How do I create my own prompter for a GUI?

**Answer**

Add an instance variable *result* to your view, and implement a *prompt* method:

Smalltalk

prompt

result := nil.
self suspendExecutionUntilRemoved.
^result

You would open the view like this:

Smalltalk

(view := MyView new) openApplicationModalWidget
myResult := view prompt.
## Setting Focus to Next Entry Field

**Question**

How can I automatically move the tab to the next entry field in VisualAge?

**Answer**

You can implement automatic tabbing in VisualAge by writing some script and making a connection to that script. Suppose you have two text entry fields. Go into the settings of field1 and set its text limit to five. If you then connect the object event of the text entry field to the following script, the tabbing will be done automatically.

### Smalltalk

autoTab
| position limit |

position := ((self subpartNamed: Field1') queryCursorPosition).

limit := (self subpartNamed: Field1') textLimit.

(position = limit)

ifTrue: [ (self subpartNamed: Field2') setFocus ].

If the user types five characters in the first text field, focus is automatically set onto the second text field.

## Missing Carriage Return in Multiple-Line Editor

**Question**

I am trying to write a string, which I got from a multiple-line editor, to a stream. It seems that I lose all the carriage returns by executing the following code. Any help would be highly appreciated.

### Smalltalk

writeFile
"Write the contents of a multiple line editor to a stream"

| fileStream, mleData |

fileStream := CfsWriteFileStream openEmpty: temp.txt'.

mleData := (self subpartNamed: Multi-line Edit') string.

fileStream nextPutAll: mleData.

fileStream close.
**Answer**

To solve this problem, the only thing you have to do is change *string* to *object*. This will include a return character at the end of each string from the multiline editor.

## Action on PFkey Pressed

**Question**

I would like to close a window when the PF12 key is pressed. The problem I have is how to see if PF12 gets pressed?

**Answer**

This is not quite as trivial as it seems, but it can be done:

1. Every visual part you attach to your window has a corresponding CwWidget attached to it. It can be accessed via (`self subpartNamed: 'myText'`), `widget`. It is accessible once the window is created, for example, in scripts hooked to `aboutToOpenWidget`.

2. Attach a keyboard message handler to each and every such widget that is capable of getting input focus, something like this:

**Smalltalk**

```
(self subpartNamed: 'myText') widget
addEventhandler: KeyReleaseMask
receiver: self
selector: #keyRelease:clientData:event:
clientData: nil.
```

3. Code the actual event handler corresponding to the selector. Create a method with signature `keyRelease:clientData:event`.

4. Every time a key is released this method will be called. The event is the place to look for specific key information (just `printString` it to the Transcript, it will tell you most everything about the key released). Whenever you think it is appropriate to close the window, just do it.
# Chapter 4. IBM Smalltalk Programming Language

This chapter covers programming tips for the IBM Smalltalk language.

## Smalltalk Books

**Question**

What mass-market Smalltalk books are available?

**Answer**

* *Smalltalk 80, The Language*, Adele Goldberg & David Robson, Addison-Wesley 1989, ISBN 0-201-13688-0

* *Smalltalk 80, The Interactive Programming Environment*, Adele Goldberg, Addison Wesley 1984, ISBN 0-201-11372-4

* *Smalltalk 80, Bits of History, Words of Advice*, Glenn Krasner, Addison Wesley 1984, ISBN 0-201-11669-3

* Inside Smalltalk, Volume I, Wilf Lalonde & John Pugh, Prentice Hall 1990, ISBN 0-13-630070-7

* Inside Smalltalk, Volume II, Wilf Lalonde & John Pugh, Prentice Hall 1991, ISBN 0-13-465964-3

* *Object-Oriented Graphics*, P. Wisskirchen, Springer-Verlag 1990

* *Practical Smalltalk: Using Smalltalk/V*, Dan Shafer and Dean A. Ritz, Springer-Verlag, ISBN 0-387-97394-X

* *Rapid Prototyping for Object Oriented Systems*, Mark Mullen, Addison Wesley 1990, ISBN 0-201-55024-5

* *Object-Oriented Design*, Peter Coad and Ed Yourdon, Yourdon Press 1991

* *Object Oriented Programming for Artificial Intelligence*, Ernest Tello, Addison Wesley 1989, ISBN 0-201-09228-x

* *The Well Tempered Object*, Stephen Travis Pope, MIT Press 1991, ISBN 0-262-16126-5

* *Human-Computer Interface Design Guidelines*, C. Marlin Brown, Ablex Publishing 1989, ISBN 0-89391-332-4

* *Designing Object-Oriented Software*, Rebecca Wirfs-Brock, Brian Wilkerson, and Lauren Wiener, Prentice-Hall 1990, ISBN 0-13-629825-7

* *An Introduction to Object Oriented Programming & Smalltalk*, Lewis Pinson & Richard Wiener, Addison Wesley 1988, ISBN 0-201-19127-x
* Object Oriented Design with Applications, Grady Booch, Benjamin/Cummings 1991, ISBN 0-8053-0091-0

* A Quick Trip to ObjectLand: Object-Oriented Programming with Smalltalk, PTR Prentice-Hall 1993, ISBN 0-13-012550-4

* IBM Smalltalk: The Language, David N. Smith, Benjamin/Cummings 1995, ISBN 0-8053-0908-X

* IBM Smalltalk Programming for Windows and OS/2, Dan Shafer and Dan Herndon, Prima 1995, ISBN 1-55958-749-0

* Smalltalk with Style, Suzanne Skublics, Edward J. Klimas, and David A. Thomas, Prentice Hall 1996, ISBN 0-13-165549-3

**Question**

What books or reports about Smalltalk are available from IBM, besides product documentation?

**Answer**

* *Object-Oriented Design - A Preliminary Approach*, IBM 1990, GG24-3647

* *Developing a CUA Workplace Application*, IBM 1991, GG24-3580

* *Object Oriented Analysis of the ITSO Common Scenario*, IBM 1990, GG24-3566

* *Cooperative Processing in an Object-Oriented Environment*, IBM 1991, GG24-3801

* *A Practical Introduction to Object-Oriented Programming*, IBM 1992, GG24-3641-01

* *Smalltalk Portability: A Common Base*, IBM 1992, GG24-3903

* *Object-Centered Environments for Smalltalk*, IBM 1990, RC 15548

* *The Geometry Browser - A Feature Modeler in Smalltalk*, IBM 1990, RC 15394

## Smalltalk Standardization

**Question**

What is going on with the effort to standardize Smalltalk?

**Answer**

ANSI officially approved the IBM project proposal for Smalltalk. The project name is X3 Project 986-D and the technical committee is X3J20.

*Smalltalk Portability: A Common Base*, document number GG24-3903, contains the proposed ANSI standard.
##() Construct

Question

What does ##() do?

Answer

The ##() construct in IBM Smalltalk is not unlike #define from the C world. It allows you to have objects created at compile time, rather than at run-time. We all use #1 2 3) to create an array at compile time. Well, ##() is no different. It just lets you create objects other than arrays. Writing

Smalltalk

##( expression )

evaluates the expression at compile time, as if it were text selected in a
workspace, but takes the resulting object and places a reference to it in
place of the ##() construct. Thus,

Smalltalk

x := ##( 60 * 60 * 24 )

would return the number of seconds in a day. The expression is evaluated
at compile time. At run time, it acts as if this had been the source code:

Smalltalk

x := 86400

Now, it is possible that the compiler could make this optimization. But how
about this?

Smalltalk

##( | birthdays |
birthdays := Dictionary new.
birthdays at: 'Boris' put: 'Jan 05'.
birthdays at: 'Dennis' put: 'Jul 05'.
birthdays at: 'Leo' put: 'Jan 05'.
birthdays )

The dictionary is created at compile time, and not every time one runs the
method. (Of course, that means there is just one copy around and that may
not be what you want at all!)
**Note!**

The ##() construct is different from the ## construct. The ##() will evaluate whatever is in the parentheses, making it possible for a method to return a constant, such as ##(Date today), which is the date the method was compiled. Note that the answer is an actual Date instance.

The ## construct is an atom (EsAtom). (You can also use ##'' for example, the expression ##hello == ##'hello' is true). There is only one instance of an atom with some name. Once you create an atom, you cannot access or change the data in it. So atoms are really used for state purposes (to avoid using symbols, to make packaging easier in IBM Smalltalk).

**Watch this!**

The ##() construct is not documented in the IBM Smalltalk manuals. Use it at your own risk!

**Question**

But IBM Smalltalk Version 3 does many optimizations automatically, so I don't need ##() for this. Is there a nontrivial example of usage of ##()?

**Answer**

Yes, for example you can use it to take some specific action each time you recompile the class. See the next section, "Taking Actions Automatically at Class Recompilation," for details.

## Taking Actions Automatically at Class Recompilation

**Question**

Typically, the initialize method is run once when a class is loaded (which most systems do automatically when it is filed in). When making changes to the class, it is easy to forget to run the method. Most people put a comment at the top:

**Smalltalk**

" Don't forget to reinitialize me when you make changes:

ThisClassName initialize "

and then select the expression and evaluate it after making a change.
Is there a way to take actions automatically each time when the class is recompiled?

Answer

Yes. In the initialization method, add this line:

Smalltalk

##( System message: self class name asString, 'needs to be initialized.' )

This puts up a dialog at compile time to remind you to initialize the class.

The compiler, being so helpful sometimes, complains that this expression doesn't do anything. So, fake it out:

Smalltalk

| junk |

...

junk := ##( System message: self class name asString, 'needs to be initialized.' )

But you say, why not initialize the class directly, by putting this at the end of the `initialize` method?

Smalltalk

##( ThisClassName initialize )

If you try it, you discover that it indeed does run the method. And you discover after a while that it doesn't contain the latest change, but always the one before. Make a change, and it doesn't show up; make another and the first shows up! It's clear once you realize that:

Smalltalk

##( ThisClassName initialize )

runs the method that is in the system. The new method being compiled, which you'd like to run, has not yet been inserted into the system. Thus you run the last one that was compiled. And the next time, you run this one, and so on.
**Warning!**

I've discovered that writing to the Transcript from within `##()` has some problems.

## Weak Pointers

**Question** What does the term "Weak Pointers" mean? Can I use weak pointers in IBM Smalltalk?

**Answer** Weak pointers are pointers you can have to objects that do not prevent the garbage collector from destroying the objects. In other words, if there are only weak pointers to an object and no other pointers, the garbage collector will destroy the object. You can use weak pointers in IBM Smalltalk, for example:

Smalltalk

| string array |

string := String new: 100.

array := (Array new: 10) makeWeak.

array at: 1 put: string.

string onFinalizeDo: #halt.

You'll get a walkback the next time the finalize cycle runs (when the system goes idle).

## Utility of Weak Pointers

**Question** Do weak pointers have practical importance? Can you give a couple of examples of when I might want to use them, and what they buy me?

**Answer** In VisualAge, a large number of collection classes have the word "weak" in their name. I'll just mention briefly some usages of weak objects here. Below, I will talk only about a simple collection (like Bag, Set, OrderedCollection) and not Dictionary or LookUpTable. Various *WeakKey* collections or *WeakValue* collections have slightly different behaviors that the class names are trying to describe.

A weak collection can be used as a cache to hold cached objects. The cache itself can be assigned to a global variable, a class variable, and so
on. Since the cache is a weak collection, references to the cache objects
are not considered permanent references.

Normally, if I want to use the same object A in several windows, I would
save that value in a global variable, or put that object A in some global
collection. It is especially true if those several windows don't really have
any logical connection to each other. Since the object A is referenced by a
global variable, it is not a candidate for garbage collection. However, if the
global cache collection is a weak collection, every element of that collection
is a candidate for garbage collection if that particular element is no longer
referenced by any object that is live in terms of garbage collection.

Object Finalization

Question

I heard that now finalization is a hot topic. What is it, actually? Does IBM Smalltalk support it? If yes, in what way?

Answer

Finalization is roughly like destructors in C++. Normally, you don't need to take any special actions to free objects. When an object is no longer needed (there are no more references to it), the Smalltalk garbage collector removes it from the object memory.

There are, however, cases when automatic garbage collection (GC) is not
enough, as when you deal with operating system resources. For example,
you can open a file and then leave the stream to GC's mercy:

Smalltalk

myMethod

| f |

f := CfsReadirstream open: 'MYFILE.TXT'.

^self

"In some moment, the GC will destroy the object
and you are probably going to suffer"

In situations like this,you want to be notified when the garbage collector is
going to destroy an object. You can do this, for example, by using weak
pointers. Point two variables to the same object, one in the weak and one
in the hard way, then examine whether the weak pointer is nil. If it is, you
know the garbage collector was trying to get rid of your object and you are
going to do an appropriate action such as closing a file.
In IBM Smalltalk, you have a much easier and stylish way of finalization. For
example, you can say

Smalltalk

myMethod

| f |

f := CfsReadidelStream open: 'MYFILE.TXT'.

f onFinalizeDo: #close.

.....

and don't worry any more about closing the file.

Standard Methods not in API Category

Question

While wandering through the class hierarchy in IBM Smalltalk, I noticed that
a number of what I considered standard Smalltalk APIs were in fact in
non-API categories. For example the *value* messages sent to blocks passed
as parameters are in the category ES-Internal. The method *deepCopy* is
another example. Is there some reason why these messages are not in an
API category?

Answer

The *Smalltalk Programmers Reference* says about *deepCopy*:

"Unlike other Smalltalk implementations, CLDT does not provide a public default version of either deepCopy or shallowCopy in Object protocol. The semantics of both these messages are normally specific to each class, and often to an application."

The categorization for #value has been taken care of for the next release.
Note, also, that Block is an abstract superclass.

Using the Correct Variable Type

Question

If I want many different methods to use a dictionary, should I have the
following code:

Smalltalk

SomeName:=Dictionary new.
and assign the SomeName to be a global variable? Is this the correct way of doing it? I guess the very first time it will ask me if I would like to make SomeName a global variable.

**Answer** If those methods are all instance methods on the same class, then you would store the dictionary in an instance variable. Otherwise, you might want to make it a class variable with a public `get` method. That way, your global name space does not get overloaded.

## Smalltalk printf()-like Formatter

**Question** Is there any code available that does string formatting like `printf()` in C?

**Answer** You might want to check out `EsString>#bindWith`: and all its variants in IBM Smalltalk. It's good for the case where you need to substitute strings at set positions within a source string.

The `bindWith`: family of messages answers with the string formatted under the control of the receiver. The receiver is a character string patterned after the formatting conventions of `printf()` and contains field descriptors used to insert arguments into the format string.

If you use the `bindWith`: family of messages and you have VisualAge for Smalltalk, then you can send each argument the message `#convertToDisplay`, and the conversion will be performed along with the substitution. If you just have IBM Smalltalk, you may want to extend the Object class to have an `asString` method that returns `^self printString`, and you would then be able to use `asString` polymorphically with your arguments.

## Testing Instances and Classes

**Question** It seems strange that I have to create special classes to test my classes and methods. Doesn't it seem that Smalltalk should have a `test method` besides instance and class methods. The idea is that a builder like VisualAge would strip out test methods when the class is packaged. With test methods for both class and instances, I'd be able to keep the tests with the class.
**Answer**

Why don't you code "Example" comments in each method which are the test cases. (I reckon about 30% of my code is such test cases.) You can highlight the example code and execute it to verify the test, but as it's a comment, it's not stored in the image. One day when I have some spare time I'll write a program to automate this testing, though my experience is that there are frequently insignificant changes to the output that would frustrate the automation (I can see the difference is minor, the test program would not).

As an aside, a crucial requirement for such testing to work is to code a decent *printOn*: method in every new class, which prints enough details to identify the result. Merely relying on Object's default "a NewClass" makes testing very hard.

You can always use a naming convention. One that's possible in Digitalk Smalltalk and perhaps elsewhere is to use a capital letter in the method name (Digitalk creates *Doit* methods all over the place), for example: Test or TestInteraction. It's not to hard to strip such methods from the image.

With Visualage for Smalltalk, you should be able to extend your class in a separate test application to hold all the (instance/class) test methods for your class.

## Garbage Collection Rate

**Question**

Can a Smalltalk application accessing many data objects in a short time from a large relational database (via a persistence layer) cause the workstation to page or swap excessively because the rate of object creation exceeds the rate of garbage collection?

**Answer**

The only way to determine this is to try. When (and if) garbage collection runs differs from product to product, release to release.

If you are not happy with the rate of garbage collection, you should be able to override the default interval of garbage collection and force it whenever you want. We noticed that IBM Smalltalk will appear hung sometimes since the garbage collector is invoked only when the system is idle, but if you are running a long-running task that creates a lot of objects, you can run into a situation where you blow the available memory. The way we worked around it is by creating a high-priority background task that wakes up every few seconds and checks if the available memory is running low. If it is, we force the garbage collect ourselves. It seems a patch that should not be necessary, but it made our hang-ups go away.
Inherited Messages

**Question**

How can I see all inherited messages?

**Answer**

The best way to see all messages that instances of your class can understand is to change the value for method visibility on the Class menu of most browsers; this will show inherited methods as well as methods defined on your class itself.

With the class methods, things are a bit more tricky. There are class methods that you don't see in any of your object's superclasses up to Object, but which your class still does understand. For example, suppose YourClass is a subclass of Object; YourClass class does understand the message *new*, but it's not a class method of either YourClass nor Object. How this can be? A look at the following picture makes this clear.

<figure><img src="image_13.png" /></figure>

For example, the method *new* is not a class method of Object, but all classes understand it. That's because the class Object is itself an instance of the metaclass Object (which in turn is an instance of the metaclass). When you execute *YourClass new*, method lookup starts in YourClass class and continues to Object class; but Object class itself is inherited from Class,
and Class is (indirectly) inherited from Behavior, and Behavior has an
instance method *new*. If you look at all public instance methods of
Behavior, then you will see *new*, which basically calls a primitive,
VMprBehaviorBasicNew. I don't know why it doesn't appear in the catalog
of classes, as it is contained in the CLIM-API methods category. You'll see
what I'm talking about by selecting **Browse Class** in your System Transcript
and entering *Behavior*.

File System

Question

How do I get the contents of a directory?

Answer

The contents of a directory can be determined by using an instance of
CfsDirectoryDescriptor. For simplicity, a reusable class named FileManager
can be created to provide higher-level abstractions of the Common File
System API.

The following method evaluates a block with the names of the files in a
directory that match a given pattern:

Smalltalk

filesMatching: pattern on: pathname do: block

"Evalutes block with all files on pathname
which match the provided pattern. Note that only
the names of files are provided (no full paths)."

| directory entry |

directory := CfsDirectoryDescriptor

opendir: pathname

pattern: pattern

mode: FREG.

directory isCfsError ifFalse: [

[(entry := directory readdirName) notNil]

whileTrue: [block value: entry].

directory closedir]

FREG is an entry in the pool dictionary CfsConstants. The *mode* keyword in
the message *opendir:pattern:mode*: uses flags to determine which files to
find. FREG provides the names of all regular files. FDIR provides the names
of subdirectories. To get both the names of files and directories, pass *FREG*
: *FDIR* as the parameter to this keyword.
Use this method to print the names of all text files in the root directory (the following code assumes the above method has been implemented in a class called FileManager).

Smalltalk

FileManager
  filesMatching: '*.txt'
  on: '/'
  do: [:filename | Transcript cr; show: filename]

The root directory can be specified as a forward slash, which is very UNIX. This works in OS/2 and in Windows as well as in AIX. It may be handy to get a collection containing the file names:

Smalltalk

filesMatching: pattern on: pathname

"Answers a collection with all files on pathname which match the provided pattern. Note that only the names of files are provided (no full paths)."

| files |
files := OrderedCollection new.
self
  filesMatching: pattern
  on: pathname
  do: [:filename | files add: filename].
^files

## File Existence

<figure><img src="image_14.png" /></figure>

How do I check in Smalltalk if a file exists?

<figure><img src="image_15.png" /></figure>

Use the methods provided above to determine if a file exists:
Smalltalk

fileExists: file_name on: pathname

"Answers whether or not the file name file
name exists on the path named pathname."

^(self filesMatching: file_name on: pathname) notEmpty

Accessing COM Ports

Question

What is the correct way to access a COM port from Smalltalk? Are there
special classes or do I have to use C for that?

Answer

There are no special classes for that in Smalltalk, but you can directly use
IOctl from Smalltalk without any C code. For example, if you want to know
how many bytes are on the input queue, use a script like this:

Smalltalk

inputQueueCount

| rc fileDescriptor queueLength |

queueLength := ByteArray new: 2.

fileDescriptor := deviceFile fileDescriptor.

rc :=fileDescriptor dosDevIOctl: ioctlAsync

function: AsyncGetinquecount

pParams: nil

cbParmLenMax: 0

pcbParmLen: nil

pData: queueLength

cbDataLenMax: queueLength size

pcbDataLen: nil.

(rc = 0) ifFalse: ^AbtError new.

^(OSType fromBytes: queueLength) asInteger

where you get the deviceFile with:
Smalltalk

open: portName
"Perform the open action."

deviceFile := CfsFileDescriptor
open: 'COM1'
oflag: ORDWR
share: ODENYNONE.

deviceFile isNil ifTrue:
(CwMessagePromptermissMessage: 'Error opening COM1').

You can read from COM1 with something like:

Smalltalk

((queueLength := self inputQueueCount) > 0) ifTrue:
[ deviceFile read: (buf := String new: queueLength)
  startingAt: 1
  nbyte: queueLength.
self incomingData: buf. ]

Catching Errors

Question

How do I catch errors in Smalltalk?

Answer

To catch errors that are difficult or impossible to anticipate, use the
exception handling facilities provided by IBM Smalltalk. The simplest form of
exception handling involves catching errors which occur while attempting to
evaluate a block. Use this:

Smalltalk

[ <do something> ]
when: <error> do: [:signal | <handle the error> ]

The message when:do:, when sent to a block, evaluates the block. If an
error matching the first parameter occurs, the exception handler will be
invoked.
The first parameter describes the kind of error that can be trapped. Potential
values for this parameter can be found in the pool dictionary called
SystemExceptions. They are:

* `ExError` – Any error

* `ExHalt` – A halt has been encountered

* `ExIndex OutOfRange` – An attempt to access a nonexistent array index

* `ExCFSError` – File system error

The second parameter is a block that takes a single argument. That
argument is an instance of class `Signal`. Tell the signal what to do next:

* `exitWith:` – Exit the block with some value

* `retry` – Reattempt evaluation of the block

* `signal` – Pass the responsibility for handling the error to the outer
context

File System Errors

Question

How do I catch file system errors?

Answer

The following method opens the file named by its first parameter. The
second parameter is a block to evaluate in the event of an error.

Smalltalk

`contentsOfFileNamed: file_name ifError: errorBlock`

"Answers the contents of the text file named aString.
If an error occurs, then the result of evaluating
errorBlock is answered."

```
| file contents |
file := CfsReadFilmStream open: file_name.
file isCfsError ifTrue: [^errorBlock value].
contents := [file contents]
    when: ExCFSError do: [:signal | signal exitWith: nil].
file close.
contents notNil ifTrue: [^contents].
^errorBlock value
```
First, the file is opened. If an error occurs during the opening of a file, the result of the *open*: message will be an object that answers true to `isCfsError`.

Second, the attempt to read the contents of the file is wrapped in a block. That block is sent the message `#when:do:`. The first parameter to this message is the kind of error we are interested in (ExCFSError in this case), and the second parameter is a block containing the code to evaluate in the event that this kind of error occurs. The block takes a single parameter, an instance of class `Signal`.

In this case, an error when trying to read a file is considered final. The message `exitWith:`, sent to the `Signal`, will exit the block with the provided value (nil in this case).

The variable *contents* should either be a string or nil. The file is closed and if successful, the contents is answered. Otherwise, the result of evaluating `errorBlock` is answered.

## Catching All Errors

**Question**

How do I catch all errors?

**Answer**

Use `ExError` for the kind of error to catch:

```
Smalltalk
| succeeded |
```

```
succeeded := [ <do something>. true ]
```

```
when: ExError do: [:signal | signal exitWith: false]
```

In this example, the variable *succeeded* is set to *true* if the `<do something>` works without signaling any errors; the variable is set to *false* otherwise.

You should not generally try to catch all errors, because you will also catch programming errors, including messages not understood. Flaws in your code may go unnoticed with unexpected results.
## Exception-Handling Code

**Question** When should I include exception handling code?

**Answer** In general, exception handling should be added after you are convinced your code works. Exception handling should be used to catch unexpected problems— for example, your file server shutting down.

## Fixed Decimal Class

**Question** Is there a fixed decimal class available or any other support that helps with the rounding issues encountered with floating decimals?

**Answer** If you are stuck with a Smalltalk without fixed decimal, don't forget that Smalltalk fractions are true fractions, so 10075/100 is a true representation of 100.75, although it will print as 403/4. Also, Decimal class is part of the base product in Version 3.

## Object Class Identification

**Question** How can I programmatically see if *anObject* belongs to *aClass*?

**Answer** This is actually two separate questions.

*Object->#isKindOf: aClass* answers a Boolean which is true if *aClass* is the class or a superclass of the receiver, and false otherwise.

*Object->#isMemberOf: aClass* answers a Boolean which is true if *aClass* is the class of the receiver, and false otherwise.

## Floating Point Numbers

**Question** I believe there is much oddity with the behavior of floating point numbers:

* (534.92 * 100) is displayed as 53492.0

* 53492.0 truncated is displayed as 53492

* (534.92 * 100) truncated is displayed as 53491

Is this as bug?
Answer

This is not a bug. No matter how odd they look, floats are precisely what scientific and engineering problems need. Those oddities were carefully and specifically designed.

* Floating point numbers are designed for use in the engineering and scientific communities where calculations involve wide ranges of number sizes.

* One basic rule is: **Never compare Floats for equality.**

* It is impossible, in general, to precisely convert decimal numbers to binary, and floats are binary. Thus most numbers are wrong as soon as they are converted. Multiplying them by 100.0 may make a particular calculation look right but just shift the problem to another calculation.

* Certain operations can cause the loss of precision. One famous gotcha involves subtracting two floats that are nearly equal. The precision of the result may be only a digit or two, or even none at all.

To see what is actually going on I used some code that prints floating point numbers to any length. I also coded a method which prints IEEE double-precision floats in hexadecimal. (The method is near the end.) The exponents, in hexadecimal, are the number of bits to shift the fraction.

Lets look at some examples. First, just some plain numbers:

Smalltalk

0.00 printHex '0e00'
1.00 printHex '1.0e0'
10.0 printHex '1.4000000000000e3'
16.0 printHex '1.0e4'

Now, the numbers from the thread, and one number that's 0.01 larger:

Smalltalk

1502.03 printHex '1.7781EB851EB85eA'
1502.04 printHex '1.77828F5C28F5CeA' (Note difference in fifth digit.)
1051.42 printHex '1.6DAE147AE148eA'

The `printStringWidth` method prints numbers to the given character width. The width used here is 30, which means 28 digits (less period and sign). As a result, it may show junk past the end of the number. In the cases below, it shows extra zeros.
Smalltalk

1502.03 printStringWidth: 30
'1502.0299999999999700000000000'

1051.42 printStringWidth: 30
'1051.42000000000000700000000000'

Now, calculating the difference we see that the expected answer 450.61 is not quite what we get:

Smalltalk

(1502.03 - 1051.42) printStringWidth: 30
'450.60999999999990000000000000'

450.61 printStringWidth: 30
'450.610000000000001000000000000'

(1502.03 - 1051.42) printHex '1.C29C28F5C28F4e8'

450.61 printHex '1.C29C28F5C28F6e8'

In fact, the difference is just in the rightmost two bits, but that's enough to make it not equal. Now, what do `roundTo:` and `truncateTo:` do?

Smalltalk

((1502.03 - 1051.42) roundTo: 0.01) printStringWidth: 30
'450.610000000000001000000000000'

((1502.03 - 1051.42) truncateTo: 0.01) printStringWidth: 30
'450.600000000000002000000000000'

Clearly, equality testing is not going to work. But, consider the following:

Smalltalk

(1502.03-1051.42) between: 450.605 and: 450.615

which *does* answer true and will answer true unless and until the real, internal precision gets very much smaller (or the values get much, much larger). The former is not likely when doing currency calculations.

A method which does the between:and: test for floats is:
Smalltalk

| Float publicMethods |

equals: aFloat to: delta

" Compare self (a float) with aFloat to a 'precision' of delta.

Example: 1502.03 equals: 1051.42 to: 0.01 "

| deltah |

deltah := delta / 2.

^ self between: aFloat-deltah

and: aFloat+deltah

Examples:

Smalltalk

(1502.03 - 1051.42) equals: 450.61 to: 0.01 true

(1502.03 - 1051.42) equals: 450.61 to: 0.001 true

(1502.03 - 1051.42) equals: 450.61 to: 0.0000001 true

(1502.03 - 1051.42) equals: 450.61 to: 100.0 true

(1502.03 - 1051.42) equals: 450.62 to: 0.01 false

(1502.03 - 1051.42) equals: 450.60 to: 0.01 false
!Float publicMethods !

printHex

" Answer a string which is the hexadecimal representation of a float.

Assumes IEEE format "

| shifty sign exp fraction str |

shifty := 0.

8 to: 1 by: -1 do: [ :n |

shifty := shifty<<8 + (self basicAt: n) ].

sign := (shifty bitAt: 64).

shifty clearBit: 64.

exp := (shifty >> 52).

fraction := shifty bitAnd: 16r000FFFFFFFFFFFF.

(exp = 0) & (fraction = 0) ifTrue: [ ^ '0e00' ].

str := sign = 0 ifTrue: [ " ] ifFalse: [ '-.' ].

exp := exp - 16r3FF.

str := str, '1.', (fraction printStringRadix: 16 showRadix: false).

str := str,'e', (exp printStringRadix: 16 showRadix: false).

^ str

## Reversing Collections

**Question**

What collections can be reversed?

**Answer**

The answer is all sequenceable collections, that is, SequenceableCollection and all its subclasses implement the reverse method.

## Substrings

**Question**

Something that looks and sounds simple is not turning out to be simple at all. I am dealing with a string in the following format: `last Name, first Name, mid Initial`. From this string I want to create a new string that contains only the `last Name` but I can't figure out how to do this.
**Answer**

There are many ways to unpack a string. One way to get the `last Name` is the following:

Smalltalk

```
| str array last Name initial |

str := 'Doe, John A'.
array := str subStrings.
last Name := array at: 1.
initial := array at: 3.
```

## Implementation of #become:

**Question**

How efficient is *become*: in IBM Smalltalk Version 3? I had thought that it was all done internally by placing a proxy for the new object in the same memory address as the old object, so that the garbage collector then removed these proxies (the added level of indirection is temporary). However, someone has suggested that this may not be true. Apparently, Parkplace does it this way, but Digitalk doesn't, and their implementation is not very efficient. Anyone know anything?

**Answer**

I can't answer your question for sure, but here is some information on *become*:

Once, Smalltalk implementations had an object table. Object pointers were indexes into the table. A *become*: was simply a swap of two pointers in the object table. It was fast, and symmetrical.

But, object tables were of fixed size and one had to know ahead of time how big a table to allocate. Further, each object reference was indirect through the table: calculate the table address given the index and then fetch the real pointer to the object.

So what to do? Without an object table, doing a full-fledged *become*: requires scanning all objects in the world to find pointers to other objects and changing the affected pointers each place they are found. What was a few microseconds suddenly became several seconds. Not good!

So, two schools of wizards developed. One school forbade symmetric *become*: entirely. All *become*: had to be asymmetric, with the second object simply replacing the first. While this still required scanning the world, it was faster than the work required to a full symmetric *become*:
The second school felt that *become*: was too important to go away. They made all object pointers indirect— not through an object table, but through a hidden pointer. While this took more memory, and made object references slower than the other wizard's solution, it was better than using an object table.

But which wizard is which? One can often tell a wizard by the spells they use. In Smalltalk, running some timing code often lets one deduce which spell was used. Below, are tests of the three implementations I have handy: IBM Smalltalk V3 on a 486 under Warp, VisualWorks 2.0 on a Mac Quadra 950 (68040), and Digitalk Smalltalk/V-Mac on the same Quadra. I ran some tests. First is the *become*: test:

### Smalltalk

```
System globalGarbageCollect.
Time millisecondsToRun: [
  1000 timesRepeat: [
    | a b |
    a := 'asdf' copy.
    b := a.
    a become: 'qwer' copy.
    a = b ifFalse: [ self error: 'Whoops!'].
    b ] ]
```

It creates an object, assigns it to two variables (so to speak), and then does a *become*: with a similar object. When done, it tests to see if the two objects have the same value. If not, something went astray. It answers b, which has the same value as a. (Select the innermost block contents and do evaluate it.) A similar test uses assignment instead:

### Smalltalk

```
Time millisecondsToRun: [
  1000 timesRepeat: [
    | a b |
    a := 'asdf' copy.
    b := a.
    a := 'qwer' copy.
    a = b ifTrue: [ self error: 'Whoops!'].
    b ] ]
```
Since it uses assignment, b is unchanged and the test is reversed. If an implementation has an object table, or uses pointer indirection, one would expect the two methods to run with very similar timings. If it has no object table, but has to search the world, the two should be very different. When timing the tests on IBM Smalltalk Version 3, I had the following results: 6230, 6232, 6220, 6264. The results without *globalGarbageCollect* were 13417, 12105, 10348, 14050, 3355. Then I used the second method with the results being 66, 69, 66. The ratio is roughly 6200/66 or roughly 100:1. Now I was timing the code on VisualWorks 2.0. The first method with *become*: resulted in 396, 464, 460, the second method came back with 56, 52. The ratio here is roughly 400/50 or 8:1. Finally, I timed the test on Smalltalk/V-MAC. The result of the first version were 9617, 6917, 8100, 8417. The second method resulted in 183, 183, 183. The ratio is roughly 7000/180 or roughly 40:1. In conclusion, IBM and Digitalk got 100:1 and 40:1 which indicates considerable slowness is involved. VisualWorks gave only 9:1, which is a lot faster. One would suspect the wizards are using different spells, but which ones? Isn't 100:1 too fast for a search of the whole world? Isn't 9:1 too slow for a simple indirection? I don't know...

**#to: Method**

**Question**

What does the `Number class>>to: do? I get to:do:`, and I understand what this does, but what is this plain `to:`?

**Answer**

The `to:` message answers an instance of a collection named `Interval`.

Smalltalk

1 to: 10

is equivalent to:

Smalltalk

Interval from: 1 to: 10

and is equivalent to:

Smalltalk

Interval from: 1 to: 10 by: 1
Intervals act like collections if you read from them, but they cannot be
modified. Further, they are not stored as collections so that (1 to: 1000000)
doesn't take any more space than (1 to: 10). For example, you can write
loops just as with any other kind of collection:

Smalltalk

(Interval from: 1 to: 10) do: [ ...block... ]

For convenience, the *to*: (and *to.by*:) messages of Number answer intervals
so this can be written as:

Smalltalk

(1 to: 10) do: [ ...block... ]

And for convenience, the *to:do*: (and the *to.by:do*:.) messages of Number
make things even easier:

Smalltalk

1 to: 10 do: [ ...block... ]

**Interval>>reverse Method**

**Question**

The comment explaining what reverse does, says: "Answer a object
conforming to the same protocols as the receiver, but with its elements
arranged in reverse order." I can't make head or tail of this. Why not say
simply "Answer an Interval in reverse order?"

**Answer**

Inspect the following code:

Smalltalk

(0 to: 5) reverse

The elements of the result are just as you expected. However, the class of
the result may not be what you expected (notice it's an Array, not an
Interval).
## UpdatingWidgets

**Question**

We have some code that sends messages to a visual part, which is then supposed to display some status information in a text window. The code works fine except that the status messages are showing up asynchronously (that is, none show up at all until they all show up at once in a big flood). I am guessing that what is happening is that the VisualAge part is getting some events queued up, but that these events aren't handled until the user interface process gets control again. Is there some way of forcing these events to be handled right away so that the updates to the status text window will be synchronous?

**Answer**

To do so, try the updateWidget message. For example, here is a sample script for a window with a button, a text part, and a label. This script should be invoked from the button click:

Smalltalk

button Clicked
"Demonstrate how to update text on a widget"

1 to: 100 do: [:i |
(self subpartNamed: 'Label1') object: i printString.
(self subpartNamed: 'Label1') primaryWidget updateWidget.
(self subpartNamed: 'Text1') object: i printString.
(self subpartNamed: 'Text1') primaryWidget updateWidget.
(self subpartNamed: 'Push Button1') object: i printString
].

All of these controls will reflect the changes instantly. The push button does not need to have an updateWidget.

## Incremental Compiler

**Question**

Does IBM Smalltalk come with an incremental compiler?

**Answer**

Yes, IBM Smalltalk does use incremental compilation. Incremental compilation means that when you save a changed Smalltalk program (typically quite short), it is compiled as part of the Save process; you don't have to recompile everything in the Smalltalk application, just what you've changed. You rarely notice the compiler working, it's so fast.
IBM Smalltalk comes with a lot of other features for programmer productivity: the TrailBlazer code browser (unique to IBM), application change management in the IBM Smalltalk Professional version, and a Motif-based GUI widgets that work on all platforms.

## Caching Compiler

**Question**

Is the IBM Smalltalk compiler a caching compiler?

**Answer**

Absolutely. IBM Smalltalk moved from being one of the slowest to being the fastest with Version 3.

## Creation of Blocks at Run-time

**Question**

Is it possible to create and execute blocks of Smalltalk code at run time?
For example, I want to read a block from a file. The string I read should then be converted to a Smalltalk block and this block should be executed.

**Answer**

The basic answer is no, because you need to ship the Smalltalk compiler as part of your application, and that's not allowed in the Smalltalk license agreements.

The fuller answer is to ask why you want to do this. Are you dynamically creating blocks in response to (say) user input, or just selecting one block from a collection (stored on disk)?

If the former, you will need some sort of compiler or interpreter to translate the user's input to the blocks in the first place, so you could instead produce an interpreter that works on the user's input, and store that input on disk instead of the block you would have produced

If you are just selecting a block from a collection, perhaps you should be creating classes that all implement a behavior according to the user's input; the methods that implement these behaviours contain the code that would have been in your blocks.
## Pool Dictionaries

**Question** What is the exact mechanism used by Smalltalk to resolve Pool Dictionaries constant references? Apparently it is not a static substitution of the value at compile time (because pool dictionary entries can be dynamically changed), nor, I believe, is there a complete dictionary lookup.

**Answer** The association (key and value pair), not the value itself, is compiled into the method. Therefore, run-time dictionary lookups are not needed and changes to the value done via the pool dictionary don't require any recompiling of the method.

## Text Color Changes

**Question** While the application is running, I send the message

Smalltalk

(self subpartNamed: 'Text2')
backgroundColor:'yellow';
foregroundColor: 'blue';
show.

to a text subpart. When I put a halt anywhere in the running code, then Text2 shows the changed color. When I don't stop in the code, then the changed color is not displayed. What can I do to have the color change visible with a running application? I need this indication to know what is happening with the application.

**Answer** Sounds like you are not giving the user interface process a chance to run. Either use `updateWidget` to force it to update immediately, or fork your work process at a lower priority (`Processor userBackgroundPriority`) and use `CwAppContext default syncExecInUI:` to update the user interface
# Sorting SortedCollections

**Question**

In Digitalk Smalltalk, SortedCollection includes the method `reSort`. I'm trying to implement my own `reSort` method:

```Smalltalk
reSort
| newColl |

size==0 ifTrue: [ ^self ].
newColl := self species new: size.
newColl sortBlock: self sortBlock.
newColl addAll: self.
elements := newColl elements.
```

However, this method produces random results (the contents of the `SortedCollection` don't get sorted). Am I missing something?

**Answer**

Yes, you get the same result if you evaluate the following code in a Workspace:

```Smalltalk
| newColl coll |

coll := #(
    andi boris vincent
) asSortedCollection.

newColl := coll species new: coll size.
newColl sortBlock: coll sortBlock.
newColl addAll: coll.

coll elements: newColl elements.

^coll.
```

But now, try this:
Smalltalk

| newColl coll |

coll := #( andi boris vincent ) asSortedCollection.

newColl := coll species new: coll size.

newColl sortBlock: coll sortBlock.

newColl sorted: true.

newColl addAll: coll.

coll elements: newColl elements.

^coll.

Now, the resulting collection gets sorted.

## Compiler Severity Level

**Question**

How do I control the compiler warning severity level?

**Answer**

You must have the TrailBlazer loaded and enabled. From the TrailBlazer pulldown menu, select **Options → Compiler Warning Level**.

## Finding the Sender Signature

**Question**

How do I get a hold of the signature (Classсь#method) for the sender of a method? In other words, during the execution of a method, how can I find out who sent me?

**Answer**

To get the sending method, just send:

Smalltalk

Processor activeProcess methodAtFrame: 1.

This will answer the CompiledMethod who sent the method currently executing.

It can be extremely instructive to have a look at EsImageStarUp class >> outputWalkback: on:process:
The debugger itself provides a good clue to information like this, but note that much of this code is development-time only and private. That said, take a look at:

Process>>#receiverAtFrame:
Process>>#stackAtFrame:offset: (good comments in this method)

View the senders of `stackAtFrame:offset:` for lots of examples of how to use it.

## Sender Context

**Question**

How do I find the sender context of a method?

**Answer**

You can use

**Smalltalk**

Process>>contextAtFrame: frameDepth

The following script prints out the top ten stack frames:

**Smalltalk**

| level nFrames |
| :f |
Transcript cr;
    show: (Processor activeProcess methodAtFrame: f) printString;
    show: ' to ';
    show: (Processor activeProcess receiverAtFrame: f) printString.
]
## Pool Dictionary Tips

**Question**

Are there tips to follow when working with pool dictionaries?

**Answer**

Yes. In general, replace pool dictionary values using the `at:` method. If you replace the pool dictionary associations (or the entire pool dictionary) then you need to recompile all the methods that reference its values. When a method uses a pool constant, the association from the pool is stored directly in the compiled method. At execution time, the value is taken from the association and used. If you update the association value (using `#atto` the new pool will not be reflected in the execution of the code until it gets recompiled. It is always best to establish pool dictionaries at load time by using `toBeLoadedCode` for your application. Even if you cannot assign values immediately as they must be computed through the application's logic, you should still build the dictionary with keys and use some form of lazy initialization to enter the values at an appropriate time. This helps not only with import and export, but also for loading your application into fresh images.

## Text Display on Update

**Question**

Why does my text not show up when I update the database?

**Answer**

You can pause a process by using the `Delay` class, but it seems like something you shouldn't have to do. The typical way of coding this is as follows:

1. Put up progress indicator

2. Fork background process: `forkAt: Processor userBackgroundPriority`

3. Background process calls `CwAppContext default asyncExecInUI: <update progress indicator>` occasionally.

4. Background process finishes, calls `CwAppContext default syncExecInUI: <close process indicator>`

Sometimes developers forget step (2) and run off the user interface process. It doesn't halt VisualAge because the database component forks work processes, but they don't get user interface updates as they expect. Alternative approaches to background processing are covered in the *IBM Smalltalk Programmer's Reference*.
## Pool Dictionary

**Question** How do I define a pool dictionary?

**Answer** A pool dictionary is simply a dictionary that is used to declare constants. You can define it with:

Smalltalk

Smalltalk at: #YourPoolDictionaryName put: (Dictionary new).

or:

Smalltalk

Smalltalk declarePoolDictionary: #YourPoolDictionaryName.

## Swapper Error

**Question** Why do I get an error message when loading variable references? It says "swapper error."

**Answer** Sounds like what you've dumped has a reference (possibly a subclass of, extension to, or contains a class variable instance of) a class that was reduced away in the run-time image you are binding to. Was the run-time image you are binding to created by the packager as a reduced image? If so, you must pay careful attention to both what actually exists in that image and what the application files you create require to ensure that the application file does not refer to nonexistent classes, methods, or both.

## Hover-Help Behavior

**Question** Why do I see unpredictable behavior using hover-help?

**Answer** By default, hover-help displays the *labelString* attribute of a graphical label or push button. All other parts, including textual labels and push buttons do not display hover-help. Also if no label string is specified for a graphic label or push button, no hover-help will be displayed. To specify the label string for a graphic push button, open the settings for the part, click on **Text** under **Label type**, specify the label string, click on **Graphic** again under **Label type**, and click **OK**.
## Aborting a Process Stack

**Question** How can I abort the current process stack?

**Answer** Either use exception blocks, such as `at:ifAbsent;`, or exceptions (see the IBM Smalltalk Programmer's Reference). If you are just looking to stop the exceptions from propagating down the stack, you can add a signal `exitWith: nil` to the end of your exception block. If you instead want your entire application to stop, then you can just `System exit`.

## Exiting an Image

**Question** In my application, is there any means to exit the image programmatically?

**Answer** Yes, `EmSystemConfiguration>#exit` exits the image immediately, so try this:

Smalltalk

System exit

## Configured Subsystems

**Question** How do I see what subsystems I am running?

**Answer** You can programmatically see what variant of each basic subsystem you are running, try this:

Smalltalk

System configuredSubsystems

This will answer a *LookupTable*, which on OS/2 may contain something like this:

<table><tr><td>'ABT'</td><td>'VA'</td></tr><tr><td>'ABTVER'</td><td>'V 3.0b'</td></tr><tr><td>'CFS'</td><td>'OS/2'</td></tr><tr><td>'CG'</td><td>'PM'</td></tr></table>
<table><tr><td>'CLDT'</td><td>'ES'</td></tr><tr><td>'CLIM'</td><td>'ES'</td></tr><tr><td>'CP'</td><td>'PM'</td></tr><tr><td>'CPM'</td><td>'ES'</td></tr><tr><td>'CW'</td><td>'PM'</td></tr></table>

## Image Copyright

**Question**

How do I go about getting the image copyright programmatically?

**Answer**

You can get a string with the image copyright programmatically through executing

Smalltalk

System copyright

## Command Line Arguments

**Question**

Do I have access to the command line arguments?

**Answer**

If you want the Smalltalk equivalent of the C variables argc and argv, send the following:

Smalltalk

System commandLine

This will return you an array of strings (including the executable name at index 1).

## Run-Time Image

**Question**

How do I find out whether the current image is a run-time image?
**Answer**

IBM Smalltalk has its own notion of whether the running image is a run-time image. You can get this information by sending

Smalltalk

System isRuntime

## EsWeakSet and Finalization

**Question**

How do I go about synchronizing an EsWeakSet with the real state of objects?

**Answer**

EsWeakSet and finalization do work together; that is, finalization keeps a weak set of objects that could potentially be finalized in the next cycle. The finalization cycle is run when the system is idle.

## Continue Background Process

**Question**

Is there any way for a process to continue execution after `suspendExecutionUntilRemoved` has been issued?

**Answer**

The example below shows that execution of background processing continues during `suspendExecutionUntilRemoved`.

Smalltalk

```shell
| shell widget |
shell := AbtShellView newPart openWidget.
[[ (widget := shell widget) notNil and: [ widget is destroyed not ]]
whileTrue: [ CgDisplay default bell: 100. (Delay forSeconds: 3) wait ]]
forkAt: Processor userSchedulingPriority.
shell suspendExecutionUntilRemoved.
```
## Automatic Log-Off

**Question**

How do I implement a timeout feature that automatically logs off a user after a minute of inactivity?

**Answer**

This is tricky stuff. Our Multimedia parts do something like this for the same purpose. The approach is to replace the handlers in the EventTable for all mouse and keyboard events, and reset a timer each time one of these is hit. See `OsWidget>>mtrTrackAllInputActivity` in the subapplication `AbtMultimediaAuthoringPM/Win`. You have to be careful that the code you invoke in the new handlers is safe for all widgets, and reset the handlers when you are done.

I can also think of another way, although I have not tried it— I suspect if you modified the implementors of `callCalbackList:callData:` to log the time, you'd get a hit whenever there was activity (focus change, keystrokes, mouse active, etc). The drawback of this approach is you'd be modifying the base image. Not a crime, but means you own it.

## Synchronizing a Visual Part

**Question**

How do I synchronize a visual part with the Smalltalk object it is called from?

**Answer**

If you simply want to wait in a script for a window you opened to be closed, the easiest way is to use

Smalltalk

`myWindow openWidget.`

`myWindow suspendExecutionUntilRemoved.`

... "whatever you want to happen after the user closed the window"

The user interface process has the same restrictions as Presentation Manager (PM), that is, you must return to the polling loop or the user interface (UI) will lock. Therefore, you cannot block on a semaphore in the UI process; if you do, you'll lock the UI if the semaphore is not posted quickly. When you execute code from a Workspace with `Execute`, that code is evaluated in the UI process. An example is (`Semaphore new`) `wait`. If I select and execute this, the UI will lock (press and hold Alt+SysRq, or press the **User Break** button on Windows 95/NT, AIX to unlock). However, if I fork around it, it doesn't lock because it is not running on the UI process.
I don't understand why you need to stop the user interface, but if you must,
here's a safe way:

Smalltalk

[ "keep waiting condition" ]
whileTrue: [ CwAppContext default readAndDispatch ].

This is equivalent to going into a peek loop in PM, that is:

Smalltalk

while ("keep waiting condition") [
if (WinPeekMsg(...))
WinDispatchMsg(...);
]

This keeps the UI responsive, but I don't recommend it except for
implementing modality as btShellView>>#suspendExecutionUntilRemoved
does.

Execution Start

Question

How does my VisualAge application start execution?

Answer

In the Smalltalk image, the default packaging specification prompts you for
launch code. This is text that is compiled into a method and called after the
runtime image is started just before dropping into the polling loop. In the
VisualAge image, the default packaging specification doesn't prompt you for
any launch code, it sends runtimeStartUp (don't forget the capital U) to all
resident applications instead. So you either need to supply launch code or
a runtimeStartUp method. If you are in a VisualAge image but your
application is not a VisualAge application, then you can specify
EpStandardRuntimeSpecification which will prompt you for launch code and
may end up with a smaller run-time image.
## Inheritance of Visual Parts

**Tip**

When inheriting visual parts, you don't have the same flexibility as when inheriting scripts. In the case where you override the inherited visual part (or "specialize it"), any subsequent changes to the superclass part are not visible to the subclass, as saving the changes causes the regeneration of the abtBuildInternals and other run-time methods, which are completely overridden by the same run-time methods in the subclass.

Here are scenarios for visual parts:

* Class B is inherited from class A. Class B remains unchanged. Class A is changed. The changes to class A will show up in class B.

* Class B is inherited from class A. Class B is changed or specialized. Class A is then changed. The changes to class A will now *not* show up in class B.

As a result, inheriting visual parts should be thought of as a one-time copy. Therefore, you should be careful to stabilize the visual part class you are inheriting from as much as possible before inheriting.

## Multithreading

**Question**

Does VisualAge support OS/2 multithreading ?

**Answer**

You can create multithreaded-like applications through the use of Smalltalk processes. Although the processes actually run under a single thread, calls to external functions can run on a thread separate from the base Smalltalk. Although the ability to access all OS/2 APIs does exist, some functions such as semaphores are implemented inside Smalltalk to support its scheduling of processes. When you call external code from VisualAge, all of its processing and the external function's processing are executed on a single thread. This means that while the function is being run, processing for the rest of VisualAge is halted, including processing for the normal operation of its user interface. To overcome this problem, VisualAge enables you to reroute the execution of any external functions to a separate thread so that normal processing can continue while the function is running.
## Global Variable

**Question**

How do I create a global variable?

**Answer**

Since the names of global variables are nothing more than keys in the Smalltalk dictionary, a new global variable is added by adding a new key to this dictionary. The global variable should begin with a capital letter. For example, the following statement adds a new global variable called `MyCustomers` with a value of `nil`:

Smalltalk

Smalltalk at: #MyCustomers put: nil.

If you subsequently want the variable, just execute:

Smalltalk

`MyCustomers := <value>.`

Even with this method, you have to be very careful that `MyCustomers` is not already an existing global (for example, a class) or you may break the system.

Avoid the use of global variables in applications, if at all possible. The use of global variables violates the principle of data encapsulation. Many times, adding a new object or adding behavior to an existing object will provide the same function as a global variable.

## Updating Class Attributes in a Run-time Image

**Question**

If a user modifies the value of a class attribute in a runtime image, is the change automatically saved from one execution to the next? In other words, does the run-time image get updated as the user exits the application?

**Answer**

You cannot (normally) update a run-time image. In order to do save changes, you have to choose other techniques, for example, external files (using the CfsFileStream class).
## Class Methods at Run-Time

**Question**

Is there a way to check if a method exists in a class (at run-time); something like `allMethodsNamed: selector`.

**Answer**

The following code returns `true` if my class or a superclass contains a method implementation for the message selector and `false` otherwise:

```
Smalltalk
myClass respondsTo: #myMethod)
ifTrue: [ "method exists" ]
ifFalse: [ "method doesn't exist" ].
```

## Objects's Knowledge of Reference

**Question**

Review the following code:

```
Smalltalk
| a b |
a := SomeClass new.
b := a.
```

When variable `b` is assigned the value pointed to by variable `a`, does the object that variable `a` is pointing to have any knowledge that it is being passed around? Is there a way to inform the object when it is referenced?

**Answer**

The variable `b` (not the object `b`) is assigned the value pointed to by the variable `a`. There are no messages sent and no code is triggered.

One approach to solve this problem is to put a wrapper around the object and let others pass the wrapper around. Your class would look something like this:
Smalltalk

SomeClass class>>new
^ Wrapper holds: self new

SomeClass>>x
^ x

SomeClass>>x: aValue
x := aValue

The Wrapper class would look like this:

Smalltalk

Wrapper class>>holds: anObject
^ self new holds: anObject

Wrapper>>holds: anObject
wrappedObject := anObject

Wrapper>>x
wrappedObject aboutToExecute: #x.
^ wrappedObject x

Wrapper>>x: aValue
wrappedObject aboutToExecute: #x..
^ wrappedObject x: aValue

Then,

Smalltalk

| a b |
a := SomeClass new.
b := a.
b x: 234

causes the object in 'a' to be sent the aboutToExecute: message passing
#x:.
## Smalltalk Class or AbtAppBldrPart

**Question**

What is the difference in using a Smalltalk class as opposed to a nonvisual part when creating business classes and what are the implications?

**Answer**

One of the main differences between a Smalltalk class and a VisualAge nonvisual part is that you have a Composition Editor with the latter. The Composition Editor allows you to do visual programming within the nonvisual part. This means that you can drop parts on the Composition Editor and make connections between them. Obviously you wouldn't put visual parts, for example a *text* part, on the Composition Editor of a nonvisual part, but you could place any nonvisual part or Smalltalk class on the Composition Editor and make connections between anything defined in the public interface for those parts.

When you want to create a nonvisual part for which you don't need composition facilities, you can subclass AbtPart instead of AbtAppBldrPart.

## Cleaning Up Unused File Handles

**Question**

If you get a walkback while you have a file open, that file remains open until you exit the image. Is there a way to clean up all of these open files?

**Answer**

The best way to address this situation is to act defensively. You can set up an exception handler so that when a walkback occurs, the file handles are automatically closed. Here is an example:

### Smalltalk

```text
| inputFile stream tempString |
s := ''.
inputFile := CwFileSelectionPrompter new
title: 'File to open';
prompt.
stream := CfsReadFileStream open: inputFile.
stream isCfsError
    ifTrue: [ self error: stream message ].
[ [ stream atEnd ] whileFalse: [
    tempString := tempString, stream next asString ].
stream close
] whenExceptionDo: [ stream close ].
^tempString
```
Initializing Class Variables

Question

How can you initialize class variables in the Trailblazer? I would like to initialize a class variable with a pool dictionary.

Answer

Probably toBeLoadedCode would be the best place. This string is stored with the application in the manager and is evaluated (compiled) when the application is loaded. Since it is evaluated before any of the application's classes are loaded, you can define pool dictionaries that are referenced in the application's classes.

You can store a code string to be evaluated with *YourApplication toBeLoadedCode: 'yourcode'* or bring up a simple editor with *YourApplication abtEditToBeLoadedCode*. The TrailBlazer can modify these directly by selecting an application (Browse Applications) and changing the lower pane property to *ToBeLoadedCode*.

Forking and Cycles

Question

I have an application in which I display a window containing a graphic that, through the use of a timer, appears to move. That is, the users see an image move across the window to illustrate that information is being downloaded from a database.

To do this, I have used fork, forkAt:;, and a number of other techniques. The problem is that I cannot get the graphic moving smoothly while the domain is initiated. When I run both pieces of code, it appears that the graphics get held up during the actual query call, and the instantiation gets held up by the timer. The resulting behavior is that the graphics appear but don't move until the query has finished. Would this be the right approach to do this?

Answer

Getting a smooth graphic is difficult when you depend on the scheduling algorithm. Instead, it would be better to use signaling from the work process to the status process. For example, for each step through the database table, you signal the status process.

This is often necessary because graphics update runs at the low priority. By forcing graphics updates at regular intervals, you assure your user is seeing true progress, not simply a bouncing ball graphic that indicates passage of time.

Trying to provide a smooth visual with background processes running is difficult because of two factors: user interface processes try to run when
everything is idle, and when they finally do, they run to completion (under the assumption that won't be long). You can try and override this behavior using `yield` and `CwAppContext default syncExecInUI: <>`, but often the results are not smooth and predictable.

## Converting Numbers Using printString

**Question**

In an older version of VisualAge I could perform the following:

Smalltalk

1.02 asDecimal printString

This would produce a string of '1.02'. If I try to do the same in Version 3.0 it would produce the following string: 1.02d16.15'. How can I make Version 3 produce a result similar to that of Version 2?

**Answer**

The `printString` method is really for debug purposes, since it is not sensitive to national language support (NLS) considerations (period vs. comma, negative indicator, and so on). Instead, use the locale classes (IBM Smalltalk) or AbtConverter classes (VisualAge). For example,

Smalltalk

(AbtDecimalConverter new) objectToPrint: 1.02 asDecimal.

or

Smalltalk

| stream |

stream := WriteStream on: (String new: 128).
Locale default lcNumeric printNumber: 1.02 asDecimal on: stream.
stream contents.

Both of these examples answer '1.02' (on a machine where the decimal separator is defined as '.').
Garbage Collection of Instances

Question

Is there a fast way to get rid of unwanted instances? Suppose these
instances are in a linked list so that they are always referenced. You could
use the allInstances method to find all the instances and make them
become: String new. However, this is very slow, so another thing you could
do is create a class variable to store all the instances, then when it is time,
you make them become: String new. Even if you cache the instances in the
class variable, the process of become: String new is still very slow. Now,
how can you quickly remove these instances so they can be garbage
collected?

Answer

The best way by far to solve a problem like this is to find the source. Then
you don't have to try and solve the symptom with things like become:. You
need to determine the critical reference. A linked list is not a problem. The
garbage collector is capable of detecting circular references and will collect
such objects if they are not referenced by anything outside the circular list.
That is, in your case, something else is holding on to something in that
linked list. It is difficult to find out which item in the list is the being
referenced.

You might try running *System abtScrubImage*. If your linked list goes away,
then see which of the steps freed your object by clearing the dependencies,
terminating processes, and so on. If it does not, then you probably have a
reference either in class or class instance variables or a reference in the
Smalltalk dictionary itself.

An object is garbage collected when there are no references to it that
ultimately references something in the global (or old) space. There are two
types of garbage collections: *flips* and *sweeps*. A flip is lightweight— if an
object is referenced by anyone it is included in the flip (called a *flip* because
objects are flipped between two areas of memory). A sweep is more costly
because it starts in the old space and traces references to the end. Sweeps
take 5-10 seconds on my machine, but rarely occur.

The goal is to maximize the recovery of objects in flips, and minimize the
sweeps. It is helpful to eliminate old space types of references such as
globals and class variables, and to avoid communes (circular references).

Objects that survive several flips are tenured to old space under the
assumption that they're going to be around for a long time and it is a waste
to keep copying (flipping) them. In Version 3, there are command-line
options to change or limit the size of the various spaces.
## 4-Digit Years

**Question**

Evaluating the expression *Date today* yields 04-01-96. What I want it to yield is 04-01-1996. Is there a way I can achieve this?

**Answer**

With VisualAge you can do this by specifying it in the settings for an entry field, or programatically like this:

**Smalltalk**

```
(AbtDateConverter new) showFourDigitYear: true;
objectToDisplay: Date today.
```

Or, if you are running IBM Smalltalk, you can also use:

**Smalltalk**

```
IcTime := Locale current IcTime copy.
IcTime d fmt: '%m-%d-%Y'.
IcTime printDate: Date today on: Transcript.
```

They are basically the same. The problem with *Date today printString* is it always tries to go with the current locale. If you want to override the locale, you can add an entry to your NLS.CNF file: `d fmt='%m-%d-%Y'`. This will override the date format returned by the operating system. See `EsNIsImageStartUp>>abtActionTable` for the other possibilities.

## Fixing Date Years

**Question**

When you enter two characters in the year area of a date field, it defaults to 20? Is there a way to get date years to default to the current century rather than the 21st?

**Answer**

The rules for normalization of the year are as follows:

1. $100 <= y <= 9999 \rightarrow$ take as is.

2. $0 <= y <= 79 \rightarrow$ assume 21st century (2000..2079)

3. $80 <= y <= 99 \rightarrow$ assume 20st century (1980..1999)

4. All others are invalid.
You may want to modify the instance method `normalizeYear:` in `AbtDateParse` class to customize the default.

## ABTPATH

**Question**

Is there any way to find out the ABTPATH value (set in `config.sys`) in VisualAge for Smalltalk?

**Answer**

There is a method available to strings that will allow you to scan the environment variables for the path indicated. It is called `abtScanEnv`. For the ABTPATH value, you can evaluate:

Smalltalk

`'abtpath' abtScanEnv`

**Note!**

This method is private, and really shouldn't be used. However, there is no other way to do this.

## Double-Triggering of Changed Events

**Question**

How do I make events work for Smalltalk Classes?

**Answer**

When VisualAge was originally created, it was intended that Smalltalk classes from other environments could be ported directly. To accommodate such an ability, the development staff included some code that automatically triggers the feature connections of a part whenever an attribute changes or an action is performed (presumably, in either case, the attributes of a part might change).

One symptom of this problem is the triggering of attribute-changed events twice whenever any attribute changes or an action is performed. The `signalEvent:with:` code in the setter method for an attribute triggers the event and the special code automatically triggers the event, a second time. Besides being a little inefficient, this has the added problem of signaling all events automatically for us, regardless of the code executed.

To handle all events explicitly, the automatic mechanism can be turned off by overriding the following instance methods for each Smalltalk class:
### Smalltalk

featuresAffectedByAction: actionName

"For objects that do not signal their own change events. Defines the features affected by an action. Do not signal any events, the receiver handles all change events itself."

^#()

### Smalltalk

featuresAffectedByAttributeChange: attributeName

"For objects that do not signal their own change events.

Do not signal any events, the receiver handles all change events itself."

^#()

For both methods, the code has been replaced by the simple return of an empty array (`^#()`), indicating that no change-events need to be signaled. For both methods, answering an array containing `#self` (a Symbol) signals change-events for all the receiver's features.

Be warned that with these methods overridden, you have the responsibility for triggering all events yourself (VisualAge will do nothing for you automatically). If you have an attribute that is an OrderedCollection, for example, and you add an object to that OrderedCollection in a method (or script) you have to trigger the changed event for that collection yourself.

The ToDoList class, subclass of Object, keeps a list of things to do in an OrderedCollection in an attribute named *list*. The action `addToList:` invokes the method `addToList`:

### Smalltalk

addToList: aString

"Adds a string to the receiver's list."

self list add: aString.

self signalEvent: #list with: self list

The last line of the above method explicitly signals the event, telling interested parties that the *list* attribute has changed.
Inheriting Visuals Associated with a View Class

Tip

The visual representation is considered a singular entity. When you create a subclass, you get a one-time snapshot of the visual representation of your superclass, which is then overridden when you save your subclass.

Think of it as a method. You can override the method in a subclass, and you can even copy most of the contents down for tweaking in your subclass. However, depending on how and what you change, you may no longer be able to use superclass, and any changes you make in the superclass implementation will no longer affect the behavior of your subclass.

The reasons you must be very careful are basically the same as the reasons why inheritance is not done automatically. Changes can occur that would leave your view in an inconsistent (or at least confused state). For example:

• View1 has Button1.

• View2 inherits from View1. It adds Button2 whose left edge is attached to the right edge of Button1.

Suppose you now update View1 by removing (or replacing) Button1. What happens to View2? Should it lose Button1 too, or does it still need it? If we dropped it, what does that say about the placement of Button2? This is actually a simplistic scenario. Others can lead to much more severe issues. Connections can be very problematic, especially since all connections are placed in a single method.

Now with the archival code, you can make the decisions. You can override the appropriate methods and keep Button1 in View2, or you can modify the method that creates Button2 and change it so that it does not attach itself to Button1. But be warned, once you start down this path, using the Composition Editor to maintain your views is probably not feasible.

Again, I can't over-emphasize the risks you are taking by doing this. Does this sound like the voice of experience? Yes, unfortunately it is. If you are not fond of or comfortable with scripting today, then this is absolutely not for you!
## Garbage Collector Problems

**Question**

I am having a problem that instances are not removed by the garbage collection process. If I open a class MyView 30 times, then MyView has 30 instances even after I forced garbage collection. I don't expect other objects to reference instances of MyView. Could there be any other reason that instances of MyView are not garbage collected?

**Answer**

A suggestion would be to start doing this:

1. Save your image (so you can come back to it if necessary).

2. Execute System abtScrubImage.

3. Check for instances.

a. If they are still there, you start to suspect class variables or globals in the Smalltalk dictionary.

b. If they are gone, then start the image again (so you can get those instances back) and execute the pieces of abtScrubImage individually to determine what caused them to finally be garbage collected (that is, was it terminating any processes, reinitializing the widgets, or flushing the dependents?) If it was the dependents, then the most common cause is that people send the method `closeWidget` rather than using the action (which actually uses the method `closeWidgetCommand`).

## Integer Representation

**Question**

How can I change the internal representation of Integer from 16 bit to 32 bit?

**Answer**

Smalltalk integers are not stored as 16-bit or 32-bit integers. They're actually 30 bit integers until that's not enough, then they grow as long as you need them to be.

## Method Tracing

**Question**

Has anyone done any method tracing in IBM Smalltalk? I need to count actual method calls by class for a given transaction. The profiler gives me only a percentage of time spent in each method based on samplings. In essence, what I want to do is: just before a method is pushed onto the stack, I'd like to write out a line to a text file with the class and method
name. I currently cannot do this because I get a "source code not available" message.

**Answer**

Yes, it's certainly possible to do this. The easiest way is to act like a debugger and repeatedly step through the code. It's slow, but it works.

The source code to some of the system is missing, but that shouldn't matter, since you don't need source code to find the class name and selector.

## Storing Object of Unlimited Size

**Question**

I am using the Swapper (the class parent of Dumper and Loader) to write my objects to disk. I've heard that you can't write any single object to disk that exceeds 65000 bytes. Is there a workaround to solve this?

**Answer**

The limitation is that no single primitive object can be greater than 64 KB in size. (It's actually a few bytes less because of object headers.) Primitive objects that must be less than 64 KB are Strings, DBStrings, ByteArrays, and Arrays. (Note that each array element is a 32-bit pointer, so that an array with 16\*1024 elements will exceed the limit because the contiguous storage area for the array itself violates the limit.)

The script at the end demonstrates successful storing and retrieving of object collections whose aggregate size is over 4 MB, but no single element violates the 64 KB limit.

If you have a need to store data that contains large primitive objects (such as very large strings), then you may indeed need to use a commercial database package. (Optionally, if you know where these large objects are and if they aren't too prevalent, you could break them up and reglue them yourself. You would be the best judge of the appropriateness of this approach.)

Some objects, such as Classes and BlockContexts, cannot be swapped out. If your object graph contains any of these, then you will have other problems. (I believe that sorted collections often hang on to a sort block—this may be a source of trouble.)
```Smalltalk
| objects dumper totalBytes |
objects := OrderedCollection new.
100 timesRepeat: [
  objects add:
    ((String new: 48 * 1024)
     atAllPut: $x;
     yourself)
].
objects do: [:ea |
  ea at: 40 * 1024 put: $*].
dumper := ObjectDumper new.
totalBytes := dumper totalSizeBeforeUnload: objects.
System message:
  'total bytes in persistend object= ', totalBytes printString.
dumper unload: objects intoFile: 'foo.obj'.
objects := ObjectLoader new loadFromFile: 'foo.obj'.
objects do: [:ea |
  (ea at: 40 * 1024) = $*
  ifFalse: [ self error: 'bad obj']
].
System message: 'Everything went fine.'
```

## Collections and #do:

**Question**

I was trying to find out how the method `do:` works when I send it to an ordered collection. I found out that `AdditiveSequentiableCollection` has the instance variable `implementationCollection` and the method `do:`. This method probably uses `do:` from `SequencableCollection`. Where does `implementationCollection` get initialized and to what?

**Answer**

Collections in IBM Smalltalk aren't the same as the collections in other Smalltalk implementations. That is, their public protocol is the same, but the implementation has been significantly optimized. The implementation changes depending on the size of the collection. The `implementationCollection` variable is the reference to the collection which is created based on size and characteristics.

If you look in `OrderedCollection class>>new`, you'll see that it actually works with an `EsLinearOrderedCollection`. `SortedCollection` is more interesting, since you'll see in `SortedCollection (Class)>>new`: it creates either an `EsInsertionSortedCollection` or an `EsHeapSortedCollection`
depending on if there are 16 or fewer elements. The InsertionSorted
implementation does an insertion sort, where the heap does a Heap sort. For
fewer than 16 elements, the insertion sort is faster than doing a heap.

Thus, the *SortedCollection new* starts life as an insertion-sorted collection, then changes to heap-sorted collection when we get to 17 elements. The *ImplementationCollection* instance variable keeps track of the details of what object is really representing the list, and if I remember right, this is a strategy pattern.

Fixed Object Space

Question

Does IBM Smalltalk have fixed object space?

Answer

Yes. We have a message called *makeFixed* that will protect an object from garbage collection. That is, *makeFixed* relieves the garbage collector from having to flip around lots of long-lived objects (at the cost of manual deallocation).

Parsing Strings with Date/Time

Question

Is there a method for parsing a string to get an instance of Date? That is, to
do something like this:

Smalltalk

'08-23-93' asDate

and receive an instance of Date as a result. The same question applies to
Strings representing Time.

Answer

You might want to write a method (in the String class) using the existing
data converters. Try something like this:

Smalltalk

asDate

^AbtDateConverter new displayToObject: self.
### Smalltalk

`asTime`

`^abtTimeConverter new dispalyToObject: self.`

One point to watch for with this approach, however, is performance. IBM Smalltalk type converters are intended primarily for handling user input. If you peek into the implementation you see that there is a lot of code for error detection, error handling, and locale-specific format support.

If you convert many strings repeatedly, AbtTimeConverter object creation imposes significant overhead. For example, if you implement

### Smalltalk

`String>>asInteger`

`^AbtIntegerConverter new displayToObject: self`

then this will result the following code to take up to 3000 milliseconds:

### Smalltalk

`| a b |`

`a := '66543'.`

`b := '10.7'.`

`Time millisecondsToRun: [ 1000 timesRepeat: [ b asInteger. a asInteger ]]`

For such cases, reusing a cached AbtIntegerConverter will yield a noticeable improvement. You can change your implementation of `String>>asInteger` as follows:

### Smalltalk

`String>>asInteger`

`^self asNumber`

I expect this to be over 30 times faster than the AbtIntegerConverter implementation, but it obviously does not solve your problem with dates and times. If you feel you don't need all the error handling and locale support, and you need performance suitable for loop processing, you might consider writing your own simple parser class, with tokenizing and conversion methods that are optimized for your application.
## Identity Test on String

**Question**

I have noticed an interesting fact on testing the identity of two string instances:

Smalltalk

```
| a b |
a := 'myString'.
b := 'myString'.
```

Given the above script, I thought that `a == b` would result in `false` while executing `a = b` gives you `true` as the result. But I found IBM Smalltalk returns `true` as the result of the identity test (`a == b`) and I am not quite sure why `a` and `b` are identical.

**Answer**

The reason for this behavior is due to compiler optimization. Here's an example. Suppose `A` and `B` are global variables:

Smalltalk

```
A := 'my string'.
B := 'my string'.
A == B
```

If the code above is evaluated as a group, you'll get `true`. If you evaluate each line separately, `A == B` will return `false`.

When you create strings with the single quote, you are creating a literal string. Literal strings cannot be modified so as an optimization the variable `a` and variable `b` actually point to the same object. This would usually create problems, but since it's a literal you can't modify either one of them, so it doesn't really matter that they're the same object.

For example, if you try this code snippet the results will be what you expected.
Smalltalk

| a b |

a := 9 printString.

b := 9 printString.

a = b      → true

a == b     → false

Replacing Character in String

Question

In some other Smalltalk implementations, I can replace characters in a
String by using the method:

Smalltalk

String>>at:put:

In VisualAge, if I try the following:

Smalltalk

'dog' at: 1 put: $D

I get a walkback with the following error: "Store into read-only object."
What is happening? And what is the right approach for replacing characters
in a string?

Answer

In your case, 'dog' is a literal. (Some other examples of literals are 3.14,
#D101, and 1234). You should never try and replace characters in a literal
string. This is one of the most common sources of errors in other Smalltalk
platforms. IBM solves this problem by preventing it altogether. If you want to
do this, make a copy of the string first, like this:

Smalltalk

'dog' copy at: 1 put: $D
Padding Strings

**Question** Is there a method that allows me to pad a string with *n* number of characters to the left or right?

**Answer** EsString>>abtPadWith:upToLength:onRight: is the method you are looking for. Here are a couple of examples of how the method works:

Smalltalk

'1' abtPadWith: $0 upToLength: 5 onRight: false → '00001'

'abc' abtPadWith: $d upToLength: 4 onRight: true → 'abcd'

Trimming a String

**Question** How do I trim a string padded with spaces?

**Answer** If you want to remove only the leading and trailing spaces, use `trimBlanks`. If you want to remove all the white space, use `abrWithoutWhitespace`.

Inhibiting List Selection

**Question** I need to be able to inhibit list selection when users click on specific items within Cw... and Ew... list widgets, but there doesn't seem to be a public interface for doing so. I know, native `aboutToChangeSelection` events exist down on the GUI platforms, I've implemented them on Windows (not sure about OS/2). The documentation I've read make no mention of any callback return values that could be used towards this end. I'd like to avoid subclassing or extending classes in OSwidget layer if possible.

**Answer** The Ew... list widgets (EwList and subclasses) have a `selectionPolicy:` interface (have a look at the comment). This should enable you to do what you want.
## Resizable Table Rows

**Question**

I am using VisualAge Professional for OS/2 and WindowBuilder Pro for OS/2 (3.0) and am having difficulty trying to use the multiline text edit policy within an EwTableList widget. I hope someone can come up with a simple solution for what I am trying to do.

We have an interface that is supposed to look and work much like a contemporary spreadsheet. However, we intend to display information in cells that may be several lines long. I have created an EwTableList widget. Within one of the columns, I use an EwTextEditPolicy, passing the `editMode` as multiple lines. Everything works great! I can enter as many lines as I wish.

The problem I have is what occurs when I leave the cell. The cell displays only a single line of text. Ideally, I would like to expand the edited row to a size capable of displaying the complete text. Alternatively, I would like to allow users to resize rows in the same way they can resize columns. I have tried messing with `itemHeight` settings, but they appear to affect every row within the table.

**Answer**

I am told that you can create dynamic row heights via setting the `itemHeight` to `nil` (do this in `preInitWindow`). This feature is undocumented, but I have it on good authority that it works. Setting `itemHeight` to `nil` causes the table to base each row height on the data in that row. I don't think it allows you to have user-resizable rows. That would probably require subclassing `EwTableList` itself. You might want to trace through the code in `EwTableList` (and its superclasses) that deal with `itemHeight`. It is very illuminating.

If you set the `itemHeight` to `nil`, the `EwTableList` will send the `ewHeightUsing:` method to the value in each of the cells. Your contents are `EsStrings`, therefore they should already pick up the implementation there where for each line feed the height is increased by the size of the font.

## Adding `wmUser` Messages

**Question**

How do I add a `wmUser` message? The C DLL that I'm interfacing to sends `wmX` messages to my Smalltalk image for processing. I've figured out how to add missing Presentation Manager `wmX` messages via the `OSWidget` method `eventTableAt:put:with:`, but not `wmUser` messages.
I could subclass OSWidget, add my new event and then reimplement
`windowProc:with:with:` to check for my event and process it. Is this the
correct or preferred way?

**Answer** When you say reimplement `windowProc:with:with:` you mean in your subclass, right? This is certainly the most efficient way of doing this. The other option would be to add an entry in the event table and extend OSWidget to add the new event. However, the event table is currently a 1023 element array and arrays can't be grown, so in order to get `WM_USER` (4096) in there, you'd need to replace the current array with an all-new one.

## New Operating System Event

**Question** How do I register a new operating system event?

**Answer** To register a new event use: `OSWidget method eventTableAt: anInteger put: anObject` where `anInteger` is the event number and `anObject` is a symbol (that is, your selector name).

## Class Instance Variables

**Question** Are there class instance variables in IBM Smalltalk?

**Answer** Yes, they are there. Here is a sample:

Smalltalk

Object subclass: #AbtNLSCoordinator
classInstanceVariableNames: 'currentCodePage '
instanceVariableNames: ''
classVariableNames: 'CharacterSet CurrentLocaleMapping
LocaleMappingCharacters '
poolDictionaries: 'AbtConstants CfsConstants AbtPrimitiveNLSStrings
AbtMsgBase '
Class Naming

**Question**

Are there any performance considerations for the length Smalltalk class names and instance variable names? In other words, will a system with a bunch of 40-character names run slower than a system with a bunch of 4-character names. In DB/2, shorter table names relate to faster response time because of more table entries in the hash table.

**Answer**

First you need to understand one of the very important concepts in Smalltalk, the difference between instance identity and equality. Two instance are “==” if they are the same object, which is to say they occupy the same memory location. But “=” may be different. An expression *a* == *b* answers *true* if the method for “=” in the receivers class answers *true*. That method may be redefined as appropriate for each class. The default method for “=” is the one in *Object* which is the same method as “==.” But for *Strings* you will find a different method that checks that the characters are the same.

Symbol is a subclass of String that maintains a SymbolTable as a class variable. It is designed so that only one instance of Symbol has a given spelling. This means that “=” can be redefined (again) to be the test for object identity. The names of classes are Symbols and all the method selectors are Symbols. All the lookups, and the like, can use object identity comparison, just checking the address rather than comparing all the characters. So the length of the names doesn’t matter at all.

Instance variable names are Strings, but they are used only by the compiler. Once compiled, the methods refer to instance variables by slot number rather than by name, so the strings are not compared at run time. There is obviously some size impact that may affect performance to some degree, but only if there is an issue of total available memory.

There is an optimization in IBM Smalltalk that can fool you into thinking that part of what I wrote above is wrong. We would expect that

Smalltalk

’abc’ = ’abc’

answers *true*, but
Smalltalk

'abc == 'abc'

should answer *false*. It answers *true* instead?

In IBM Smalltalk, the compiler creates literal strings as read-only objects and makes an optimization to use the same instance for any strings with the same spelling which are compiled in the same method or workspace expression. To get the right answer, we need to make a copy

Smalltalk

'abc' == 'abc' copy → false

but

Smalltalk

#abc == #abc copy → true

Anyway, trying to place any sort of naming restriction on Smalltalk to meet database limitations is not the right approach.

## Reusing the Settings View

**Question**

Is it possible to reuse the VisualAge template for the settings view? I am creating custom parts and would like my settings to have the same look and feel as other VisualAge parts.

**Answer**

Are you asking if it's technically possible, or legally possible? I believe the answer to be "yes" to either question. For the technical side, you can generate archival code and do a find or replace to change the class name to your settings view, and then file that code in.
Exception: #doesNotUnderstand

Question

I need to know the IBM Smalltalk way of specifying an exception handler for
*doesNotUnderstand*. In Digitalk Smalltalk, it used to look like this:

Smalltalk

[self foo]
on: MessageNotUnderstood
do: [ self doesNotUnderstandHandler ]

What is the IBM Smalltalk equivalent of this?

Answer

If you look at the method *doesNotUnderstand*: in Object, you see:

Smalltalk

doesNotUnderstand: aMessage
"Report to the user that the receiver class
for superclasses do not implement any methods
for the message selector contained within the
argument aMessage."
^self error: (self doesNotUnderstandError: aMessage)

The upshot of this is there is no exception specifically for the
*doesNotUnderstand*: method. You would have to catch it by catching all
errors, as in this code snippet:

Smalltalk

| i |

[ i do: [ :each | each become: nil ] ]
when: ExError
do: [ :signal |
System message: signal argument.
signal exitWith: nil ]

This code is interesting in many ways. You may want to play with it for
some time; for example, try to initialize *i* to something that does or does not
understand *do:*, and also try to *exitWith*: something a little more interesting
than *nil*.
Of course, instead of catching all exceptions, you can create the new exception for `doesNotUnderstand:`, and change the method to signal that exception instead.

## Creating Classes from Smalltalk Script

**Question**

What's the proper way to create a class in Smalltalk code (the name is entered in an entry field) and adding a few methods? I'm running in the team environment. I've tried various combinations of `Compiler>>#evaluate:` and `Compiler>>#compile:in:` but have the following problems:

1. The class I create has no owner. No biggie, but I thought that `EmUser currentUser` would own classes created with `evaluate:`.

2. Methods I compile seem to lose their source code. I stole the code from the SubApplication class method for creating the method for starting run-time views (don't remember the method name) so I don't see what I'm doing differently. Could have something to do with the ownership question though.

**Answer**

I see you enjoy this kind of fooling with the environment. Anyway, you can try this after calling `Compiler class>>#compile:inClass`:

```
Smalltalk
compiledMethod methodClass
install: compiledMethod
asPrivate: asPrivateBoolean
withSource: sourceString
ifNewAddTo: compiledMethod methodClass controller
categorizeIn: #('all' 'the' 'categories' 'you' 'want').
```

However, I suggest you instead call `compile:notifying:ifNewAddTo:categorizeIn:` or `compileAsPrivate:notifying:ifNewAddTo:categorizeIn:`, which is the preferred method.
Keyboard Event Handler

Question

I need to be able to capture the following key pressed events:

• Shift + F10 Activate Pop-up Menu

• Alt + F6 Switch between associated windows

I'm able to capture single key pressed events but not multiple ones. Is there a way to use IBM Smalltalk to capture multiple key-pressed events other than menu accelerator keys? Does VisualAge provide a mechanism for capturing multiple key pressed events?

Answer

Yes it is possible to capture multiple key pressed events. See below for a technique to do this.

As to Shift+F10 and Alt+F6, on the Windows 95 version of VisualAge, these two particular events are not trappable; that is, they do not generate Cw eventHANDLER callbacks. I suspect this is because the native widget is trapping these or they have operating system significance. There is some interesting protocol with interceptEvents: and CwOverride shells but with the lack of any good documentation I am in the dark on this one.

For the multiple key-pressed events, I assume you are using a method along the lines

Smalltalk

aWidget
addEventHandler: KeyPressMask
receiver: receiver
selector: #key Pressed:clientData:callData:
clientData: nil.

This will get you a callback each time a key is pressed for aWidget.
Implementing the three keyword method keyPressed:clientData:callData on
the receiver object results in calling it each time a key is pressed. If you
look at the callData object (the third argument to the message), it is an
instance of a CwKeyEvent. CwKeyEvent has a state that can indicate
whether keys such as Alt, Shift, or Ctrl were pressed together with the
original key character. It is a little esoteric, but the state is an integer that
represents a single byte, bits of which are set on or off depending on which
key was pressed. Fortunately, CwConstants contains pool dictionary entries
that identify the masks and the best thing to do is to hide this complexity on
an extension of CwKeyEvent:
Smalltalk

CwKeyEvent>>#isAltPressed
^( self state & Mod1Mask ) ~ ~ 0

CwKeyEvent>>#isShiftPressed
^( self state & ShiftMask ) ~ ~ 0

CwKeyEvent>>#isCtrlPressed
^( self state & ControlMask ) ~ ~ 0

In your callback method, if you want to see whether Shift and F10 are pressed together, the code would be along the lines

Smalltalk

keyPressed: aWidget clientData: clientData: callData: callData
( callData isShiftPressed and: { callData keysym = XKF10 } )
ifTrue: [ ... ].

This assumes you can see the pool dictionary CwConstants in your class.

## Changing Object Class

**Question**

Does IBM Smalltalk provide a way to change the class of an object, something equivalent to ObjectWork's `changClassToThatOf`?

**Answer**

There is an undocumented primitive to do this, but you have to write your own method. Try something like this:

Smalltalk

Object>>changeToClass: aBehavior
"Change the Class of the receiver to aBehavior"
"Note -- does not verify compatible class shape"
<primitive: VMprObjectClassColon>
^self primitiveFailed
## Cleaning Up the Image

**Question**

During development, my image has grown far too big. Is there an easy way for me to clean up the image?

**Answer**

The image has probably grown for two reasons:

1. You have loaded a lot of applications in it, or

2. You have a lot of instances alive in it.

I would first consider unloading applications you are not working with or starting with a clean image (the one you originally started from) and loading only the applications you need. In the second case, if you know the class of the instances that are bothering you, you could try

**Smalltalk**

```ruby
aClass allInstances do: [ :i | i becomes: nil ]
```

That would free the memory used by these instances.

## Finding Methods Containing a String

**Question**

How would one locate a string within a given class or application in IBM Smalltalk? I thought this would be trivial, given the rich set of text comparison tools, but I can't find any tools or menu selections to make this easy. For example, I want to search through application A to find all methods that contain the text string B. Does anyone have a swatch of code I could use for this? I'd like to extend the Envy browsers to make this function accessible, but code that one can evaluate in a workspace would be wonderful.

**Answer**

If you are looking for methods referencing a given literal, sending

**Smalltalk**

```ruby
System allMethodsReferencingLiteral: 3.14
```

will open a References browser listing all methods referencing 3.14.

The following code searches for a literal string in source of all the methods of all classes. (Change Object allSubclasses.... to something more meaningful to reduce time and hits):
```Smalltalk
| str pat methods |
methods := OrderedCollection new.
str := 'Elephant' "Search for this string"
pat := Pattern new: str.
Object allSubclasses do: [ :cls |
    cls selectors do: [ :sel |
        (pat match: (cls sourceCodeAt: sel) index: 1) notNil
        ifTrue: [ methods add: (cls compiledMethodAt: sel)]
    ].
    cls class selectors do: [ :sel |
        (pat match: (cls class sourceCodeAt: sel) index: 1) notNil
        ifTrue: [ methods add: (cls class compiledMethodAt: sel)]
    ]
].

MethodBrowser new
    label: 'References to: ', str;
literal: str;
openOn: methods
```

## Free Disk Space

**Question**

Does anybody know how to retrieve free disk space information on Windows platforms?

**Answer**

The GetDiskFreeSpace function call returns the following information:

1. Number of sectors per cluster

2. Number of bytes per sector

3. Number of free clusters on the disk

4. Total number of clsuters on the disk

Pointers to variables where the above information can be returned must
must be passed to the GetDiskFreeSpace function. To get the total amount
of free disk space, you must multiply the sectors per cluster by the bytes per
sector by the number of free clusters.

Listed below is code that will call the GetDiskFreeSpace function, calculate
the amount of free space on C;, and display that value in a message
prompter.
```
| oscall freeSpace sectorsPerCluster bytesPerSector
freeClusters totalClusters rc |
```

```
oscall := OSCall new.
```

```
sectorsPerCluster := Array new: 4.
```

```
bytesPerSector := Array new: 4.
```

```
freeClusters := Array new: 4.
```

```
totalClusters := Array new: 4.
```

```
rc := oscall getDiskFreeSpace: 'C:'
  IpSectorsPerCluster: sectorsPerCluster
  IpBytesPerSector: bytesPerSector
  IpFreeClusters: freeClusters
  IpClusters: totalClusters.
```

```
freeSpace := (sectorsPerCluster abtAsInteger) *
  (bytesPerSector abtAsInteger) *
  (freeClusters abtAsInteger).
```

```
CwMessagePrompter message: 'Free space on disk C: is ',
freeSpace printString.
```

## Using LookupTable Instead of Dictionary

### Tip

I just did some timings of LookupTable and Dictionary. LookupTable is faster, typically about 15% to 20%, but the difference is greatly influenced, sometimes dwarfed, by the selection of the key class.

The table below shows the test code run with both Dictionary and LookupTable and four kinds of keys. In each case a random number between 0.0 and 1.0 is selected. The number is used, sometimes after is is transformed, as a key.

<table><thead><tr><td></td><td>Strings</td><td>Floats (0..1)</td><td>Nice Ints 1..1000</td><td>Bad Ints 1..huge</td></tr></thead><tbody><tr><td>Dictionary</td><td>136</td><td>22500</td><td>60</td><td>61</td></tr><tr><td>LookupTable</td><td>120</td><td>18600</td><td>50</td><td>51</td></tr></tbody></table>

The keys are formed like this:
**Strings** A printString of the random number

**Floats** The raw random number in the 0.0-1.0 range

**Nice Ints** An integer in the 1-1000 range; 1000 is the collection size.

**Bad Ints** An integer in the 1-7654000 range (arbitrary range)

Here are some observations:

* Integers happen to be extra nice keys because they are their own hashes and seem to distribute well over the dictionary and table size.

* Strings hash quickly to a nice integer.

* Floats hash by truncating to an integer and answering that integer. That is always zero for the selected keys. (A fact I didn't know until I tried to explain the awful results.)

* (Note that the integer tests actually run with approximately 640 keys, because of the way random keys are generated, whereas the float and string tests have 1000 keys. Cases with 100 integers run with a result of about 100 and are thus not twice as good as strings as might be assumed from the raw data in the table.)

* Symbols also make great dictionary keys, because each has an associated unique integer hash. However, it is not good practice to create a large number of new symbols; use symbols only for method names.

The following test routine is almost the same for all tests. It generates up to 1000 keys and inserts them into either a dictionary or a table. It also builds a set that contains the keys. The timing test consists of accessing each key twice, once to fetch the value and once to set the value.
Smalltalk

| randy coll set n slot key |
n := 1000.
coll := Dictionary new. " ← THIS LINE CAN CHANGE "
randy := EsRandom new.
set := Set new.
n timesRepeat: [
key := randy next.
slot := key printString. " ← THIS LINE CAN CHANGE "
coll at: slot put: randy next.
set add: slot ].
^ Time millisecondsToRun: [
set do: [ :e |
coll at: e put: (coll at: e) ]
]
136 137 " ← This line shows one or more timing results "

In the following, the example above would be shown as:

Smalltalk

coll := Dictionary new.
slot := key printString.
136 137

Comparison with Random Strings As Keys

Smalltalk

coll := Dictionary new.
slot := key printString.
136 137
coll := LookupTable new.
slot := key printString.
119 121

Comparison with Floating Point Numbers As Keys