trainer notes
TRANSCRIPT
PML2 Training Notes
What’s New in PML2
Objects and Object methods
Form names are now preceded with !!
i.e. setup form _fredfollowed by : setup form !!fredresults in an error because !!fred was already defined in the previous assignment
Forms are now loaded dynamically
return error noalert allows an error to be returned without any messages
What to avoid in PML2
Commands with dollars in $m- $m+ $W25Numbered variables $v1-120The var command var !x name var !x readSynonymsGlobal variables
What to avoid in forms and menus
Dots in gadget namesselector gadgetsUserdataPixmap viewsAlert gadgetsRadiogroupsSimple Textin gadgetsNumbers at the beginning of gadget namesWaiton to show formsDo list/pane/sel
What’s not changed in PML2
In theory, all old PML should work in PDMS11.1. Very little of the old appware has been converted because this would be a waste of resources. Cadcentre policy on converting appware to use new facilities is to only upgrade appware when modifications are being made in that area.
The only exception to this, is where new facilities in core code supersede or improve functionality and it is necessary to write new code to use the extra functionality.
New Environment Variables
PMLLIB /DIRECTORYNAME
This is a directory which is searched when the system looks for functions and forms
PMLTRACE ON/OFF
When set to ON, PMLTRACE will display a trace of all macros called in the unix command shell. This can also be switched on or off on the command line, so it is probably better to set the variable to off and use commands to control trace as before.
The command in PDMS is - PML TRACE ON/OFF
PMLCOMPILE ON/OFF
Environment variable PMLDEBUG ON will write a trace file
Available variable types
$v1 old style not recommended!a Named variables both global and local !!global !localNOTE: !a is evaluated as text automatically by using $!A (early evaluation)
Named variables are now typed variables as one of the following
STRING ‘Text in quotes or vertical bars up to a Max of 254? char’REAL Any numberBOOLEAN TRUE,FALSE These are not text i.e. ‘TRUE’,’FALSE’ARRAY Any type including arrays of arrays of anythingOBJECTS A collection of different variables under a user defined type
Variables can be predefined as a particular type or revert to type when they are set
There are two ways of setting variables
Var !a (25) !a is a string
2
!a = 25 !a is a real
!a = ‘xyz’ !a is a string
!a[1] = 75 !a[1] is a real element of array !a Note: other elements in the same array can be of any type
!a = TRUE !a is BOOLEAN
Beware Pre version 11 the var command was used to set all variables and it produced a string. Now we don’t use var apart from collections.
Variables may also be created before they are used using Methods
!!Answer = real()!textline = String()!test = boolean()!squares = array()
All of the above have the value ‘unset’
There are various ways of testing whether a variable exists or is set:
If(undefined(!x))thenIf(defined(!x))then
If(unset(!x))thenIf(!x.unset())thenIf(set(!x))thenIf(!x.set())then
To make a variable undefined i.e. empty it.
!x.delete()var !x delete
Arrays
arrays may be sparse i.e. you can set in index order Negative subscripts are not permittedA subscript of zero can be used but is not adviseddo loop from and to variables can now include expressions and even functions
Array methods
!arraysize = !arraything.size() Replaces var !arraysisze (arraysize(!arraything))
3
Sets the variable arraysize to the number of elements in the array
!testarray.clear() Deletes all elements from !testarray
!test.removefrom(5, 20) Removes 20 elements from element number 5
!new = !test.removefrom(5,20) Removes 20 elements as above and creates a new
array with the 20 elements inside.
!myarray.append(!newdata) acts like var !array append ‘fhjffj’
!myarray.[27].delete() Deletes element 27 of the array the array still exists
!myarray.delete() Deletes the array entirely
!line = ‘ this is a line of text with some funny spaces ‘!line = !line.trim(‘lrm’)
trims the spaces from the variable called !line!line = ‘ this is a line of text with some funny spaces ‘!lines = !line.split(!line)
Splits the string !line into an array of strings called !lines.Note: we could not use the same variable name because it is a different type
!a = !lines.size() gives the number of elements in the array!a = !lines.width() gives the number of characters in the longest word of the array
No result methods.
!lines.sort() sorts the array !lines and returns the array in its sorted form!lines.invert() inverts the array order first to last etc. These methods work only
on the original array. Attempts to set another array results in an error.
i.e. !new = !lines.sort() Gives an error
The old method.
!ind = !lines.sortedindices() Produces a sorted index without changing the original array. This can be used to sort parallel arrays in the same way as before.
!lines = !lines.relindex(!ind) Re-orders an array according to the order of array !ind
4
If applied to the original array, it would have the same effect as a simple sort, its use is to sort parallel arrays.
The Current Element variable
There is one global variable which is always set by the system to be the element you are positioned at in the database - this is called !!CE. !!CE is an object of type DBREF. Its attributes are described as members of the object. e.g.
!tem = !!ce $* creates a variable which is a copy of !!ce1q var !tem $* Queries the attributes of the DBREF pointed to by !item
<DBREF> =8196/8 NAME <DBATTT> -> <STRING> ‘DA/2000’ TYPE <DBATTT> -> <STRING> ‘SITE’ LOCK <DBATTT> -> <BOOLEAN> FALSE OWNER <DBATTT> -> <DBREF> =8196/0 DESC <DBATTT> -> <STRING> ‘MAIN REACTOR AREA’ FUNC <DBATTT> -> <STRING> ‘’ PURP <DBATTT> -> <STRING> ‘’ NUMB <DBATTT> -> <REAL> 0 AREA <DBATTT> -> <REAL> 0 POS <DBATTT> -> <POSITION> E 0mm N 0mm U 0mm WRT /* ORI <DBATTT> -> <ORIENTATION> Y is N AND Z is U WRT /* MODU <DBATTT> -> <STRING> ‘’ ORRF <DBATTT> -> <DBREF> Unset STMF <DBATTT> -> <DBREF> Unset :MATERIAL <DBATTT> -> <STRING> ‘Carbon Steel’
q var !item $* gives/DA/2000 $* without all of the other stuff
!item $* as a command, does nothing
$!item $* navigates to /DA/2000
Querying attributes
q var !item.pos $* gives
<POSITION> E 0mm N 0mm U 0mm WRT /* ORIGIN <DBREF> =8196/0 UP <REAL> 0 EAST <REAL> 0 NORTH <REAL> 0
5
q var !item.e $*query the east position<REAL> 0
q var !item.pos.origin $* gives all of the attributes of =8196/0 q var !item.pos.origin.lock $* gives the lock of =8196/0
q var !item.pos.wrt(=8196/32) $* uses the method WRT(DBREF) to extract a $*position relative to some other database
$*reference
METHODS/FUNCTIONS
Different data types in pml have associated built in ‘methods’ which may be used to convert or read data in a particular way. Some methods are similar to the built in functions pre version 11.1 as in the example below:
!NCHARS = !MYSTRING.LENGTH() $* THIS IS A METHOD
!NCHARS = LENGTH(!MYSTRING) $* THIS IS A FUNCTION CALL
The pre version 11.1 syntax for the function call would have been as follows:
VAR !NCHARS LENGTH(|$!MYSTRING|) $* THIS IS A 10.5 FUNCTION CALL
The difference between the 10.5 example and the 11.1 example is that version 11 now returns a typed variable (REAL) where version 10.5 would have returned a string.
Methods are built in for various data types and are listed in appendix A of the Customisation guide.
Block evaluation of arrays
Block evaluation is a method of stepping through each element of an array and performing some action. In effect, it is like a single command do loop.
To perform block evaluation, there are two stages:
First you need to define the expression which will operate on the array elements Second, you need to apply the expression to an array
The expression is stored in a variable and is defined as follows:
!EXPRESSIONVAR = OBJECT BLOCK (‘!!ARRAYNAME[!EVALINDEX] * 2’)
6
the !!arrayname[!evalindex] bit is effectively the name of the variable being operated on by the expression. In the example above, the result would be to multiply all of the numbers in the input array by 2. The variable !evalindex is a special variable used in block evaluation. Any other variable name will not work!
To apply the expression is as follows:
!!newarray = !!arrayname.evaluate(!expressionvar)
This creates an array called !!newarray containing the numbers of the original array multiplied by 2. The original array can also be modified using this method:
!!arrayname = !!arrayname.evaluate(!expressionvar)
Here are some simple examples
!text = 'this is a line of text'!myarray = !text.split()
This creates an array called !!myarray with six elements
!myarray[1] = ‘this’!myarray[2] = ‘is’!myarray[3] = ‘a’!myarray[4] = ‘line’!myarray[5] = ‘of’!myarray[6] = ‘text’
Now we can define some blocks
!extractchar1 = object block ('subs(!myarray[!evalindex],1,1)')!new = !myarray.evaluate(!extractchar1)
This extracts the first character of each word into and array called !newgiving the following:
!new[1] = ‘t’!new[2] = ‘i’!new[3] = ‘a’!new[4] = ‘l’!new[5] = ‘o’!new[6] = ‘t’
!extractchar1 = object block ('upcase(subs(!myarray[!evalindex],1,1))')!new = ! myarray.evaluate(!!extractchar1)
This does the same as before, but also changes the letters to upper case
!new[1] = ‘T’
7
!new[2] = ‘I’!new[3] = ‘A’ !new[4] = ‘L’!new[5] = ‘O’!new[6] = ‘T’
!extractchar1 = object block ('upcase(subs(!myarray[!evalindex],1,1)) & |fred|')!new = !myarray.evaluate(!extractchar1)
This does as before, but uses the & character to append the string fred to the result
!new[1] = ‘Tfred’!new[2] = ‘Ifred’!new[3] = ‘Afred’!new[4] = ‘Lfred’!new[5] = ‘Ofred’!new[6] = ‘Tfred’
!extractchar1 = object block ('!!testfunc(!myarray[!evalindex])')!myarray.evaluate(!extractchar1)
This example passes the evaluation into a function called !!testfunc, resulting in the function being run on each element of the array. More on functions later!
8
Objects
define object COMPONENT member .detail is string member .material is string member .bore is real member .position is positionendobject
To use this object
!x = object COMPONENT()!x.detail = !!ce.dtxr!x.material = !!ce.mtxx!x.bore = !!ce.pbor1!.pos = !ce.pos
External Functions
The new environment variable PMLLIB points to an area where both forms and functions(macros) can be dynamically loaded according to name. PML functions are macros which may or may not return a value. They must be named with a suffix of “.pmlfrm” , “pmlobj” & “pmlfnc” and they are called as follows:
Officially:
call !!functionname()
Unofficially:
!!functionname()
e.g a function definition
define function !!dir_to_next(!comp is dbref) $!comp -- go to component passed dir to next next if (!!ce.type eq ‘ELBO’)then back dir to next endif nextforwreturn
To run this function on the current element, type:
9
!!dir_to_next
or
call !!dir_to_next
This would result in the system searching for a file called “dir_to_next.pmlfnc” and if found, running it as a macro.
To get all of the text of the selected elements in a list would require a simple function as follows:
-- Function to get all selected text items in a list gadget-- Pass the name of the list gadget is the input parameterdefine function !!textlist(!input is gadget)is array!selected = !input.val!expression = object block(‘!input.rtext[!selected[!evalindex]]’)!x = !selected.evaluate(!expression)return !xendfunction
to run this
!!text = !!textlist(!!myform.members)
Alert Views
Alert views are slightly different to pre version 11. They are treated as functions and called in the same way
!!Alert.Error(‘This is an error message’)
!!Alert.warning(‘This is a warning message’)
!!Alert.Message(‘This is a message’)
!answer = !!Alert.confirm(‘Do you want to savework’)
This returns ‘YES’ or ‘NO’
!answer = !!alert.question(‘ok to delete world’)
This returns ‘YES’ ‘NO’ or ‘CANCEL’
10
Forms and Menus
setup form !!myform Paragraph .message text ‘Press goodbye button to close’ button .goodbye okexit!!myform.show()
by convention, all form definition macros have the extension .frmto load the form type $m/myform.frm
In the above example the button has no display text. In fact the display text is taken from the name and made upper case.
The method !!myform.show() is the equivalent of show _myform
Querying the form
q var !!myform would give something like the following:
<FORM> MYFORM GOODBYE <GADGET> MESSAGE <GADGET> Press goodbye button to close AUTOCALL <FMPROP> -> <STRING> ‘ ‘ CALLBACK <FMPROP> -> <STRING> ‘ ‘ USERDATA <GADGET> FORMTITLE <FMPROP> -> <STRING> ‘ ‘ ICONTITLE <FMPROP> -> <STRING> ‘ ‘ FORMREVISION <FMPROP> -> <STRING> ‘ ‘ KEYBOARDFOCUS <FMPROP> -> <GADGET> Unset
The important form properties are :
AUTOCALL
What is autocall?
CALLBACK
This is in fact the initialisation callIt can be set as follows
!!MYFORM.CALLBACK = ‘$$P ABOUT TO SHOW MYFORM’
or as part of the original macro
INIT ‘$$P ABOUT TO SHOW MYFORM’
11
USERDATA
Userdata seems to work as before i.e. VAR USER _MYFORM ADD |FRED|
Adds the text FRED to the userdata area of the form
NOTE: userdata is sort of superseded by new variables called form members which will be discussed later
FORMTITLE
FORMTITLE is a text string which is shown across the top border of the form
it can be set in two ways as before:
as part of the form definition
TITLE | My Demonstration Form|
Or as a change to an existing form
!!MYFORM.FORMTITLE = | My Demonstration Form|
ICONTITLE
This is the text displayed on the forms icon. It is set in the same way as above but the keyword ICONTITLE replaces TITLE and FORMTITLE in the syntax
FORMREVISION
this is an optional revision text which again is set in a similar way
KEYBOARDFOCUS
Keyboardfocus is meant to set the focus point to one of the form gadgets so that the user is positioned in the right place when a form is shown. The syntax is as follows:
!!myform.keyboardfocus = !!myform.textpane!!myform.show
If the form is visible on the screen, the focus will not changeCurrently, Focus only applies to text input gadgets, textpanesand alpha displays
12
General Form features
Only one OK button allowed per form
Pressing OK on a parent form actions the OK gadgets of all child forms (youngest first)
Pressing Cancel on a parent form effectively presses cancel on all child forms as well.
In both cases the parent and child forms are removed from the screen
This “Form Family” effect does not apply to RESET and APPLY buttons
Each form has a show/hide method associated with it. these are slightly enhanced on what went before.
!!MYFORM.SHOW() shows the form in its default state
!!MYFORM.SHOW(‘AT’,0.5,0.5) positions the form origin half way across the screen and half way down
!!MYFORM.SHOW(‘CEN’,0.5,0.5) positions the form centre point half way across the screen and half way down
If a form is shown by some other form, it joins the form family of the parent. Exceptions to this are:
The form is shown in an explicit positionThe form is shown by an OK or CANCEL gadgetThe parent form is a FREE form
To show a form as a FREE form use
!!MYFORM.SHOW(‘FREE’)
Forms can still be setup as blocking or resizable using:
SETUP FORM !!MYFORM BLOCKING
SETUP FORM !!MYFORM RESIZABLE
to hide a form use:
!!MYFORM.HIDE()
13
Gadgets
Gadgets are stored in a similar way to forms. The command:
Q VAR !!MYFORM.MESSAGE
results in the following:
<GADGET> Press goodbye button to closeVAL <FMPROP> -> <STRING> ‘Press goodbye button to close’ACTIVE <FMPROP> -> <BOOLEAN> TRUECALLBACK <FMPROP> -> <STRING> ‘’BACKGROUND <FMPROP> -> <REAL> 255
All of these values can be changed by a function or macro although on this gadget, callback seems to be a little pointless.
To set the variables is as follows:
!!MYFORM.MESSAGE.VAL = ‘This is a different piece of text’
sets the text part - using the old syntax is as follows:
var !! MYFORM.MESSAGE ‘This is a different piece of text’
!!MYFORM.MESSAGE.ACTIVE = FALSE
Makes the gadget inactive (greys it out)
!!MYFORM.MESSAGE.BACKGROUND = 22Sets the text background colour to colour number 22 (RED). The text changes colour to be a suitable contrast if necessary
14
Members of forms
Instead of assigning userdata to forms, it is now possible to set a series of dedicated form variables for use by the appware writer. These can be any variable type including arrays. To define form member variables is as follows:
SETUP FORM !!MYFORM . .MEMBER .MYNUMBER IS REALMEMBER .MYTEXT IS STRINGMEMBER .MYARRAY IS ARRAYMEMBER .MYOBJECT IS POSITION . .EXIT
These variables can be used and set in exactly the same way as any other global variables.
!!MYFORM.MYARRAY.APPEND(‘THIS IS SOME TEXT’)!!MYFORM.MYARRAY.APPEND(53)!!MYFORM.MYARRAY.APPEND(TRUE)
!!MYFORM.MYOBJECT = !!CE.POS
To query what the form contains:
Q VAR !!MYFORM.MEMBERS()
Paragraph Gadgets
examples
PARAGRAPH .MESSAGE TEXT ‘This is some text’PARAGRAPH .MESSAGE AT X2 Y2 TEXT ‘Optional starting text’ WIDTH 16 LINES 2PARAGRAPH .MESSAGE TEXT AT X2 Y2 BACKGROUND 22 TEXT ‘This is some text’PARAGRAPH .MESSAGE TEXT PIXMAP /FILENAMEPARAGRAPH .MESSAGE TEXT PIXMAP /FILENAME WIDTH 256 ASPECT 2
15
Button Gadgets
Button gadgets are defined as follows:
BUTTON .BUTTON1 ‘SHOW DATA’ FORM !!DATAFORM
This is a simple button which shows a form when pressed
BUTTON .OK ‘OK’ AT X2 Y3 CALBACK ‘!!MYOKCALLBACK()’ OK
This is a button which runs a function when pressed. It is also an OK button which means the form will automatically be removed from the screen when the button is pressed.
There are 5 types of button which have different effects on how the button behaves:
OK As described aboveCANCEL Removes the form from the screen and resets the form variables to the
state when the form was shown or the status after the last APPLY. APPLY This activates the callback, but the form is not hiddenRESET This works like CANCEL but the form is not hiddenHELP Invokes form specific help
BUTTON .BUTTON2 AT Y2 X4 PIXMAP /FILENAME FORM !!DATAFORM
This is a button which contains a single pixmap view. In fact, a button may have up to three pixmaps associated with it. These represent three possibilities:
The button is in it’s normal stateThe button is pressedThe button is inactive(greyed out)
The syntax for defining these is as follows:
BUTTON .BUTTONNAME PIXMAP UNSELECTED /PIX1 WIDTH 26 HEIGHT 26 SELECTED /PIX2 INACTIVE /PIX3 CALLBACK ‘CALLBACK TEXT’
Frame Gadgets
Frame gadgets are new gadgets which produce an enclosing frame around other gadgets. They are used to group gadgets together and are described by a title text in the top left corner.
16
They are defined as follows:
frame .framename ‘Title’ at x2 y4 width 10 height gadget1 gadget2exit
Gadgets within a frame are positioned relative to the frame origin.If you wanted to put in a four line paragraph gadget, specifying the text during definition has the effect of resizing the frame to suit the text. To get a paragraph gadget to fit into the frame, the text must be specified afterwards.
Toggle Gadgets
Toggle gadgets are now very simple. They have two states true or false and are treated as a simple boolean variable.
TOGGLE .INSULATION ‘INSULATION’TOGGLE .GRID PIXMAP /FILENAME WIDTH 64 HEIGHT 64 CALLBACK ‘ ‘
to set toggle gadgets
!!MYFORM.INSULATION.VAL = TRUE
to use
IF(!!MYFORM.INSULATION.VAL)THEN....
Rgroup Gadgets
Rgroup gadgets are a new type of radio group. It is defined as follows:
RGROUP .STYLE ‘STYLE’ AT X2 Y3 CALLBACK ‘ ‘ VERTICAL ADD TAG ‘Bold Text’ SELECT ‘BOLD’ ADD TAG ‘Italic Text’ SELECT ‘ITALIC’ ADD TAG ‘Underline’ SELECT ‘UNDERLINE’EXIT
When the group appears, item one is selected.The text in the RGROUP line is the title of the rgroup
To select any other item it is done by number
!!MYFORM.STYLE.VAL = 2
17
This selects item 2 in the group
Two other methods are available to operate on rgroup gadgets
!STYLETEXT = !!MYFORM.STYLE.SELECTION()
This gets the text of the gadget - in this case ‘BOLD’
!!MYFORM.STYLE.SELECTI(‘UNDERLINE’)
This sets the toggle by selecting the toggle with the select text equal to ‘UNDERLINE’
Querying:
Q VAR !!MYFORM.STYLE
<GADGET> BOLD VAL <FMPROP> -> <REAL> 1 ACTIVE <FMPROP> -> <BOOLEAN> TRUE CALLBACK <FMPROP> -> <STRING> ‘ ‘
$P $!!MYFORM.STYLE BOLD
Option Gadgets
Option Gadgets are compact lists which look like buttons. they have two sets of text:Display text which what appears on the gadget and replacement text which is stored in the background.
OPTION .COLOPT ‘Text Colour’ AT X6 Y6 CALL ‘!!function()’
Setting the options is simply an array assignment using a method.
!!MYFORM.COLOPT.DTEX = !COLARRAY
!!MYFORM.COLOPT.DTEX = !NUMARRAY
Both arrays must be STRINGS
Options can also use pixmap views whose file names are inserted into the display text of the option. All of the pixmap views must be the same size and the width and height must be part of the declaration.
OPTION .COLOPT ‘Text Colour’ CALL ‘ ‘ PIXMAP WIDTH 64 HEIGHT 64
18
List Gadgets
List Gadgets are either single or multiple choice gadgets which again use display and replacement texts like option gadgets. The list area is defined as an area on a form but the text in a list can be very large.
LIST .MEMBERS AT X5 Y6 MULTIPLE WIDTH 20 LENGTH 6
LIST .MEMBERS AT X5 Y6 SINGLE WIDTH 20 LENGTH 6
Assigning values to a list is a matter of setting the dtext and rtext fields as in options
!!MYFORM.MEMBERS.DTEXT = !VARNAME!!MYFORM.MEMBERS.RTEXT = !OTHERVARNAME
Note: Setting the DTEXT only causes the RTEXT to have the same value.
List Gadget Manipulation
There are a number of ways of extracting and manipulating the data from a list:
To get the list positions of any currently selected elements
!SELECTED = !!MYFORM.MEMBERS.VAL
For a multiple form, !SELECTED would be an array of real. For a single choice list it would be a single real.
to get all of the text of the selected elements in a list would require a simple command as follows:
!NEWARRAY = !!MYFORM.MEMBERS.SELECTION
To get all of the text of a list:
!NEWARRAY = !!MYFORM.MEMBERS.RTEXT
copies all of the replacement text into !newarray
!NEWARRAY = !!MYFORM.MEMBERS.DTEXT
does the same for the display text
to clear all selections
19
!!MYFORM.MEMBERS.CLEARSELECTION()
to select items in the list
!!MYFORM.MEMBERS.SELECT(‘DTEXT’,’/FRED’)
Note: There are no facilities to match just part of the string.
to select all items in a list
!!MYFORM.MEMBERS.SELECT(‘DTEXT’,!!MYFORM.MEMBERS.DTEXT)
to clear selections
!!MYFORM.CLEARSELECT()
to clear the list entirely
!!MYFORM.CLEAR()
Text Input Gadgets
Text input gadgets allow text to be entered into a variable. The width of the text is described by the width command the maximum text size is determined by the scroll command
to create a text gadget
TEXT .MYTEXT AT X2 Y 2 ‘NAME’ CALLBACK | | WIDTH 10 SCROLL 20 IS STRING
The types of variable now available are: IS STRINGIS REALIS BOOLEANIS word ?
to maintain compatibility with old PML
ISOUNITNAMENUMERICINTEGERSTRINGISOBORE
To set an initial value
20
!!myform.mytext.val = |insert text here|
T0 set focus
!!myform.mytext.focus()
NOTE: it is only possible to set the focus to text gadgets
To enable the entry of passwords into a gadget, it is possible to set NOECHOon a text input gadget so that the input is not shown to the screen.
It is also possible to set the format of a gadget to be in a format which can be defined by a FORMAT object.
TEXT .MYTEXT AT X2 Y 2 ‘NAME’ WIDTH 10 FORMAT IS !!FORMATBORE
Where !!FORMATBORE is a FORMAT object
These are defined as follows:
!!FORMATBORE = FORMAT()!!FORMATBORE.UNITS = ‘FINCH’!!FORMATBORE.FRACTION = TRUE!!FORMATBORE.DENOMINATOR = 16
Textpanes
Textpanes are like editable notepads the occupy an area on the screen and can have text associated with them. TEXTPANES HAVE NO CALLBACK
they are defined as follows:
TEXTPANE .TEXTP AT X3 Y4 WIDT 20 HEIGHT 5
You can add text by typing it in or it can be inserted from an array as follows:
!!MYFORM.TEXTP = !ARRAYNAME
There are methods for making the text editable or not
!!MYFORM.TEXTP.SETEDITABLE(TRUE)
!!MYFORM.TEXTP.SETEDITABLE(FALSE)
21