## Introduction to System Classes

### Overview

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:

          dlg.caption
    My first window

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

          dlg.Show

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:

          dlg.Lst1.list„NAMES

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

          dlg.Lst1.value
    2

### 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:

          MyWin.MyButton.onClick„'HITME'

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:

          dlg.Delete
          dlg
    [Ś:UNKNOWN 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'
    2

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'
    Cancel

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.self
    SYSOBJ-1
          dlg.Lst1.New 'List'
          dlg.Lst1.self
    SYSOBJ-1.Lst1
          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 ]