FWH 18.08: Gets with loop variable as array subscript
Posted: Thu Sep 27, 2018 6:26 am
There are occassions when we need to Get values of array elements like, aValue[ 1 ], aValue[ 2 ], ... , aValue[ n ]. If they are not many we can write code something like this:
Code-1: (Correct)
This works well.
But where there are many values, we would like to create the Says and Gets in a loop we may write code something like this:
Code-2: (Wrong)
But this does not work. We get a runtime error.
Reason: For every Get, its bSetGet codeblock is assigned with
{ |u| If( PCount() == 0, aValues[ n ], aValues[ n ] := u ) }.
During runtime this codeblock is evaluated with the value of 'n', which is always nLen+1 and array bound error occurs.
To overcome this problem, we need to create the Gets in a separate function using the concept of detatched locals. Here is a working sample using this principle.
Code-3: (Correct working sample)
Enhacement in FWH 18.08:
It is no more necessary to create the Gets in a separate function. We can create the gets straight away in the loop iteslef in a single command. This is a working sample, using the new clause SUBSCTIPT:
Syntax:
@ r, c GET aArray SUBSCRIPT n // where n is the loop variable
Code-4: ( Correct FWH 18.08 )
Let us now consider a bit more complex case of a multi dimentional array consisting of Prompts in the first column, variables in the second column and pictures in the third column. Here the get variable is aData[ n, 2 ] where n is the loop variable.
In this sample, let us also try using the recently introduced syntax:
@ r, c SAY ...GET ...
Code-5 (Working sample FWH 1808)
This enhancement in FWH 1808 makes programming Gets of arrays using loop variables.
This new syntax is not applicable to gets from resources as such gets are not generally redefined in a loop.
Code-1: (Correct)
Code: Select all
@ 40, 20 SAY aPrompts[ 1 ] SIZE 80,24 PIXEL OF oDlg
@ 40,110 GET aGets [ 1 ] VAR aValues[ 1 ] SIZE 120,28 PIXEL OF oDlg
@ 70, 20 SAY aPrompts[ 2 ] SIZE 80,24 PIXEL OF oDlg
@ 70,110 GET aGets [ 2 ] VAR aValues[ 2 ] SIZE 120,28 PIXEL OF oDlg
@ 100, 20 SAY aPrompts[ 3 ] SIZE 80,24 PIXEL OF oDlg
@ 100,110 GET aGets [ 3 ] VAR aValues[ 3 ] SIZE 120,28 PIXEL OF oDlg
@ 130, 20 SAY aPrompts[ 4 ] SIZE 80,24 PIXEL OF oDlg
@ 130,110 GET aGets [ 4 ] VAR aValues[ 4 ] SIZE 120,28 PIXEL OF oDlg
But where there are many values, we would like to create the Says and Gets in a loop we may write code something like this:
Code-2: (Wrong)
Code: Select all
nRow := 40
for n := 1 to nLen
@ nRow, 20 SAY aPrompts[ n ] SIZE 80,24 PIXEL OF oDlg
@ nRow,110 GET aGets[ n ] VAR aValues[ n ] ;
SIZE 120,28 PIXEL OF oDlg
nRow += 30
next
Reason: For every Get, its bSetGet codeblock is assigned with
{ |u| If( PCount() == 0, aValues[ n ], aValues[ n ] := u ) }.
During runtime this codeblock is evaluated with the value of 'n', which is always nLen+1 and array bound error occurs.
To overcome this problem, we need to create the Gets in a separate function using the concept of detatched locals. Here is a working sample using this principle.
Code-3: (Correct working sample)
Code: Select all
#include "fivewin.ch"
function Main()
local oDlg
local aPrompts := { "First", "Second", "Third", "Fourth" }
local aValues := { Space( 10 ), Space( 10 ), Space( 10 ), Space( 10 ) }
local aGets[ 4 ], n, nRow
DEFINE DIALOG oDlg SIZE 400,250 PIXEL TRUEPIXEL
nRow := 40
for n := 1 to 4
@ nRow, 20 SAY aPrompts[ n ] SIZE 80,24 PIXEL OF oDlg
aGets[ n ] := CreateGet( nRow, 110, aValues, n, oDlg )
nRow += 30
next
@ nRow, 20 BUTTON "Close" SIZE 100,30 PIXEL OF oDlg ACTION oDlg:End()
ACTIVATE DIALOG oDlg CENTERED
XBROWSER aValues // Ceck the values
return nil
function CreateGet( nRow, nCol, aArray, nEle, oDlg )
local oGet
@ nRow, nCol GET oGet VAR aArray[ nEle ] SIZE 120,24 PIXEL OF oDlg
return oGet
It is no more necessary to create the Gets in a separate function. We can create the gets straight away in the loop iteslef in a single command. This is a working sample, using the new clause SUBSCTIPT:
Syntax:
@ r, c GET aArray SUBSCRIPT n // where n is the loop variable
Code-4: ( Correct FWH 18.08 )
Code: Select all
#include "fivewin.ch"
function Main()
local oDlg
local aPrompts := { "First", "Second", "Third", "Fourth" }
local aValues := { Space( 10 ), Space( 10 ), Space( 10 ), Space( 10 ) }
local aGets[ 4 ], n, nRow := 40
DEFINE DIALOG oDlg SIZE 400,250 PIXEL TRUEPIXEL
nRow := 40
for n := 1 to 4
@ nRow, 20 SAY aPrompts[ n ] SIZE 80,24 PIXEL OF oDlg
@ nRow,110 GET aGets[ n ] VAR aValues SUBSCRIPT n ;
SIZE 120,28 PIXEL OF oDlg
nRow += 30
next
@ nRow, 20 BUTTON "Close" SIZE 100,30 PIXEL OF oDlg ACTION oDlg:End()
ACTIVATE DIALOG oDlg CENTERED
XBROWSER aValues
return nil
In this sample, let us also try using the recently introduced syntax:
@ r, c SAY ...GET ...
Code-5 (Working sample FWH 1808)
Code: Select all
function ArrayGets
local oDlg
local aData := { { "First ", Space( 10 ), nil }, ;
{ "Second ", Space( 10 ), "@!" }, ;
{ "Third ", DATE(), "@D" }, ;
{ "Fourth ", 0, "99,999.99" } }
local aGets[ 4 ], n, nRow
DEFINE DIALOG oDlg SIZE 400,250 PIXEL TRUEPIXEL
nRow := 40
for n := 1 to 4
@ nRow, 20 SAY aData[ n, 1 ] GET aGets[ n ] VAR aData SUBSCRIPT n, 2 ;
PICTURE aData[ n, 3 ] SIZE 240,28 PIXEL OF oDlg
nRow += 30
next
@ nRow, 20 BUTTON "Close" SIZE 100,30 PIXEL OF oDlg ACTION oDlg:End()
ACTIVATE DIALOG oDlg CENTERED
XBROWSER aData // Check
return nil
This new syntax is not applicable to gets from resources as such gets are not generally redefined in a loop.