Topic: APLX Help : System Classes : Introduction to System Classes
[ Next | Contents | Index | APL Home ]

Introduction to System Classes


Built in to all versions of APLX (excluding console-only versions) is a rich set of System Classes, which implement windows, dialogs, graphics, movies, and other user-interface components which you can use from your APL applications. They also include more advanced components, such as a chart-drawing class for business and scientific graphs, an image-manipulation class, and some non-visual classes for networking, e-mail and web access. As far as possible, these classes work cross-platform, so that, with a few exceptions, the same APL user-interface code will run under APLX for Windows, MacOS or Linux.

The syntax for using these System Classes is similar to the syntax for user-defined classes (which you write yourself in APL), or external classes (for example, classes written in C# or Java). There is also an alternative syntax (based on the ⎕WI system function) which is retained for compatibility with other APL interpreters and with earlier versions of APLX, and which is sometimes useful in itself.

The workspaces 10 HELPSYSCLASS and 10 SAMPLESSYSCLASS contain examples of using System Classes. If you take a look at these examples, you will see that the basic steps which you typically need to carry out are as follows:

1. Create a top-level object (for example, a Dialog, Form, Window, or Document), using ⎕NEW.

2. Create controls such as edit boxes, buttons, or rectangles on the top-level object, using the New or Create method which is implemented for all System Classes.

3. Provide APL functions known as callbacks which get run when certain events occur (such as when a Button is pressed).

4. Call the ⎕WE system function which waits for events, and where appropriate executes your callback functions.

Each object you create is an instance of a pre-defined class of objects which are built into APLX (or accessible as an external OCX class). You tailor the appearance and behavior of an object by setting properties for it, and you find out about an object's current state by reading its properties. Properties include things like the size and position of an object, its title, its color and font, the current text displayed in it, and so on. In most cases, when you set a property, the object immediately reacts accordingly (for example, if you change its size property, it is immediately re-sized). Some properties (such as the data property, an arbitrary APL array associated with the object) are valid for all objects. Many properties (such as size) are valid for several classes of object, and a few (such as the text property) for certain specific classes only. Most properties can be both set and read by your program, but some are read-only.

You can also call built-in functions associated with objects from APL (these are known as methods). These carry out operations such as hiding or closing the object.

Creating instances of System Classes using ⎕NEW

The first stage in using System Classes is to create a top-level object (i.e. an instance of a class such as Window, GetMail or Image) using ⎕NEW. The right argument is the name of the class, and the left argument should be '⎕' to indicate that this is a System Class (rather than a user-defined or external class).

For example, you might create a window with the standard Dialog border and appearance:

      dlg←'⎕' ⎕NEW 'Dialog'

This has created a new object, and returned a reference to that object which has been placed in the variable dlg.

You can then set and read properties, or call methods, of this new object using dot notation, where you refer to the property or method using a compound name in the form ObjectRef.PropertyName or ObjectRef.MethodName. For example, to set the caption property of the window (which sets the title of the window):

      dlg.caption←'My first window'

Reading the value of a property is similar:

My first window

To call a method which takes no arguments, you simply refer to the object and method:


To call a method which takes arguments:

      dlg.Clienttoscreen 8 12
158 180

Not all System Classes can be created as top-level objects. For example, a Button can be created only as the child of a Window or similar container, as described below. The classes which can be top-level objects are either windows, pre-defined dialogs, or invisible classes. The full list is:

APL ChooseColor ChooseDir ChooseFont Dialog Document Form GetMail HTTPClient Image ImageList Menu MsgBox OpenFile Printer SaveFile SendMail Socket System Timer Window OLE (COM) Server

Creating Child controls

Once you have a top-level object (such a window or form), you can typically create child controls (such as buttons, list boxes, and so on) on it. Because these controls cannot exist independently of the parent object, you cannot use ⎕NEW to create them. Instead, you use the New or Create methods. These take a right argument which is the name of the System Class which you want to create. The name of the control is specified using dot notation.

for example, to create an object called Lst1, of class List, on the window which we have just defined, you would enter:

      dlg.Lst1.New 'List'

When you create a control in this way, the system chooses defaults for properties such as size and position. You can change these using dot notation in the normal way. For example, to set the size property of the list you just created to be 5 standard rows high and 30 columns wide (the object will immediately be re-sized):

      dlg.Lst1.size←5 30

Put a set of choices (contained in the variable NAMES) into the list box by setting its list property:


Read back the selection which the user has made by reading the value property of the list box:


Rules for Object Names

As can be seen in the above examples, the dot-notation syntax is hierarchical in that the first part (up to the first dot) represents the reference to the top-level object, created using ⎕NEW. The next part represents the child object name (created using the New or Create method of the System Class sub-system), if there is one. Potentially there may be further levels of hierarchy separated by further dots - for example, a menu item may be a child of a sub-menu which is a child of a menu-bar item. The maximum length of each part of an object's name is 32 characters. Apart from the special significance of dots, names follow the normal APL symbol-naming rules. Object names are case-sensitive.

Finally, the last part of the dot-notation sequence is the property or method name. The valid property, method, and class names are pre-assigned and are documented separately. APLX ignores case when searching for these pre-assigned names, but it is recommended that you enter them as shown for future compatibility with other systems.

Responding to events

The processing of events which occur in your program (such as a button being pressed) is handled by the system function ⎕WE in conjunction with callback properties which you set. These callback properties tell the system 'If this event occurs for this object, then you should execute the following APL expression'. For example, if you want to run a function called HITME when a button is pressed, you would set the onClick handler for that button as follows:


The actual execution of the HITME function takes place during an event loop, invoked by the function ⎕WE. This is described in detail separately.

Drawing pictures, shapes and text

As well as placing controls and text or graphic objects on your windows, you can also use the Draw method to display text, geometric shapes such as polygons and ellipses, and pictures or bitmaps.

Implementing Drag-and-Drop

If you want to use drag-and-drop for specific functionality in your application, you can do this very simply. In outline, all you need to do is the following. First define the sourceformats property for the control which can be dragged. Then define the targetformats property for the control or controls on to which it can be dragged. If the two formats match, the user will now be able to drag the source control on to the target control. Your program will be notified when a drag-drop occurs using the onDragDrop callback for the target, and the onDragEnd callback for the source control.

Note: Under Windows, APLX Edit and RichEdit controls have built-in drag-and-drop capability for text editing, and you do not need to do anything for users of your application to take advantage of this.

Deleting objects

In order to free up memory used by an object, you must make sure it is deleted when you are finished with it. As with user-defined APL classes, a top-level object will be deleted when the last reference to it is deleted from the workspace. Thus, if the variable dlg in the above example was erased (either explicitly, or because the name was localized in a function header, and the function completed), then the window would be closed (if it were still open), and it would be deleted. All child objects on the window are automatically deleted when the parent is deleted.

You can also delete an object explicitly using the Delete method (note that this is not the same as closing the object). This closes the object (and any children it has), and frees up any memory which it was using. However, this does not erase any references to the object in your workspace, if it is a top-level object:


As a convenience, windows which have no onClose callback defined are automatically deleted if the user closes the window.

Alternative syntax using ⎕WI

As an alternative to using ⎕NEW and dot-notation, you can interface to System Classes by means of the system function ⎕WI. This syntax usually less readable than dot-notation, but is retained for compatibility with earlier versions of APLX and with some other APL interpreters. In a few cases, it is preferable to dot-notation.

When you use ⎕WI to create objects, there is no object reference held in the workspace. Instead, you provide a name for the object, which is held in the System Class sub-system, and you use a character vector to identify the object.

The left argument of ⎕WI is the name of the object, and the right argument names the property or method you wish to access, and if appropriate also provides the value you wish to assign to the property or pass to the method. When you create an object, you can optionally set properties at creation time, otherwise the system chooses defaults. You can use the New or Create methods to create a new object. The following examples show how this works:

Create a top-level object called Example, in this case a window with the standard Dialog border and appearance:

      'Example' ⎕WI 'New' 'Dialog'

Create an object called Lst1, of class List Box, on the window Example (the system chooses defaults for things like size and position):

      'Example.Lst1' ⎕WI 'New' 'List'

Set the size property of the list you just created to be 5 standard rows high and 30 columns wide (the object will immediately be re-sized):

      'Example.Lst1' ⎕WI 'size' 5 30

Create an object called Lst1, as above, but this time set the size property at the time you create it:

      'Example.Lst1' ⎕WI 'New' 'List' ('size' 5 30)

Put a set of choices (contained in the variable NAMES) into the list box by setting its list property:

      'Example.Lst1' ⎕WI 'list' NAMES

Read back the selection which the user has made by reading the value property of the list box:

      'Example.Lst1' ⎕WI 'value'

The exact syntax of ⎕WI for the three possible cases is as follows:

Setting a property:

     ObjectName ⎕WI PropertyName Value

ObjectName and PropertyName are character vectors, and Value can be any APL array valid for the particular property in question. The right argument to ⎕WI is thus a two-element nested vector. However, as a convenience ⎕WI accepts any length of nested array vector and treats the first element as the property name and the rest of the argument as the property value, so that the following two statements are both valid and do exactly the same thing:

      'Win1.But' ⎕WI 'where' (12 20 3 8)       ⍝ Two-element vector
      'Win1.But' ⎕WI 'where' 12 20 3 8         ⍝ Five-element vector

(You can also use the New, Create and Set methods to set multiple properties in one line.)

Reading a property:

      Value ← ObjectName ⎕WI PropertyName

ObjectName and PropertyName are character vectors as before, and the current value for the property is returned as the explicit result of ⎕WI. For example:

      'Win1.But' ⎕WI 'where'
12 20 3 8
      'Win1.But' ⎕WI 'caption'

Invoking a method:

      {Result ← } ObjectName ⎕WI MethodName {Argument}

ObjectName and MethodName are character vectors, and Argument is an optional argument to the method. It can be any APL array valid for the particular method in question. Again, ⎕WI accepts any length of nested array vector and treats the first element as the method name and the rest as the argument to the method. In addition some methods return a result.

      'Win1.Movie' ⎕WI 'Rewind'               ⍝ Method with no argument
      'Win1.But' ⎕WI 'New' 'Button'           ⍝ Argument is 'Button'
      'Win1.RichEdit' ⎕WI 'Linelength' 4      ⍝ Argument is 4
17                                            ⍝ Method returns result

Mixing dot-notation and ⎕WI

If you create a top-level object using ⎕WI, you cannot access it using dot notation because there is no reference to the object held in the workspace. However, if you create a top-level object using ⎕NEW, then you can access it (and its children, if any) using ⎕WI. When an object is created using ⎕NEW, APLX automatically assigns a name in the form SYSOBJ-NNN to the object, and you can use this name in the left argument to ⎕WI. The easiest way of doing this is to reference the self property, which gives the fully-qualified name:

      dlg←'⎕' ⎕NEW 'Dialog'
      dlg.Lst1.New 'List'
      dlg.Lst1.self ⎕WI 'List' ⎕W

This is particularly useful for a few cases where ⎕WI provides an easier syntax than dot-notation. These include accessing array properties in OCX/ActiveX controls, and dynamically determining the source of an event using ⎕WSELF.

Converting ⎕WI syntax to dot-notation

If you have written code using ⎕WI syntax in previous versions of APLX, it will continue to work. However, if you wish, you can convert the syntax to use ⎕NEW and dot-notation. The workspace 10 CONVERTQWI helps to automate this.

Special considerations for Client-Server versions of APLX

In Client-Server implementations of APLX, the front-end which implements the user-interface (the "Client") runs on one machine, and the APLX interpreter itself (the "Server") can run on a different machine. The two parts of the application communicate via a TCP/IP network. Typically, the Client will be the APLX front-end built as a 32-bit Windows application running on a desktop PC, and the Server will be a 64-bit APLX64 interpreter running on a 64-bit Linux or Windows server. Alternatively, the Client and the Server may run on the same physical machine (this is the case if you are running APLX64 on a 64-bit desktop machine).

In this environment, it is important to bear in mind that the whole of the System Class sub-system runs on the Client machine as a 32-bit application. This is nearly always transparent to your application, so for example a workspace originally written for a 32-bit Windows desktop machine should continue to work unchanged in a Client-Server configuration where the Client executes on a 32-bit Windows desktop and the APLX interpreter (Server) executes on a 64-bit server machine. However, you should be aware that any file or path names used in your objects always relate to the Client machine, never to the Server.

In such an environment, when you make a ⎕WI call, the parameters are passed over the network from the Server to the ⎕WI sub-system on the Client machine. If the Server is a 64-bit APLX64 interpreter, the data will be converted to 32-bit form before it is sent over the network. (This means that any data you associate with an object using the data property or a 'delta' variable will be held on the Client machine, and must be representable as a 32-bit variable).

See also the description of the APL (Child Task) object for special considerations applying to multiple tasks in a Client-Server environment.

Topic: APLX Help : System Classes : Introduction to System Classes
[ Next | Contents | Index | APL Home ]