Add a Generic List to a Page
- Last UpdatedJul 13, 2023
- 6 minute read
You can add a generic list to a page using the following Genies:
-
Generic List Genie — creates a list with a header row and scroll bars.
-
Generic List Vertical Genie — creates a list with no header row and just a vertical scroll bar.
To apply formatting to the list rows and enable on-click commands, you can also add the .
Add a list Genie
To add a list Genie ("genericlist" or "genericlist_v") to a page:
-
Open a page in Graphics Builder.
-
Click the Paste Genie button in the objects toolbox.

Or, select Paste Genie from the Edit menu.
-
In the Paste Genie dialog, select the Library "sa_controls".
-
Select one of the following from the Genie list and click OK.
-
genericlist = Generic List Genie
-
genericlist_v = Generic List Vertical Genie
The Genie is pasted onto the graphics page. A dialog box will open, prompting you to configure the parameters for the Genie.
The Generic List Vertical Genie dialog box will show the following parameters:
-
AN — the number that is displayed is the ANvalue that was automatically applied to the Genie when it was pasted on the page.
-
GenericListFillFunction — this field specifies the user Cicode function to be called at runtime to populate the list. The function needs to retrieve the data to be displayed.
In the example below, "Test_GenericListFill" has been entered. To view the custom Cicode that this function calls, see the Cicode examples below.

The Generic List Genie dialog box will include some additional parameters that enable runtime interaction with the header row. By default, the OnColumnReorderedFunction will display "ArrayView_SetFormat()". This is a system function that allows an operator to rearrange the header row columns at runtime.

-
-
Click OK to close the parameters dialog box.
To load data into the list at runtime, you need to call the required Cicode function as an On Page Entry command in the Page Properties dialog.
-
In Graphics Builder, right-click on the page and select Page Properties from the menu that appears.
Or:
From the File menu, select Properties.
The Page Properties dialog box will appear.
-
On the Events tab, select the On page entry event.
-
In the On page entry command field, enter the required expression.
For this example, the "Test_GenericListCreate" function is entered. To view the custom Cicode that this function calls, see the Cicode examples below.
-
On the Events tab, select the On page exit event.
-
In the On page exit command field, enter an expression to destroy the list that has been created. For an example, search locate "Test_GenericListDestroy" in the example Cicode below.
-
Click OK, and Save your page.
Add the List Row Genie
-
In Graphics Builder, open the page that includes the list to which you want to add a List Row Genie.
-
Click the Paste Genie button in the objects toolbox.

Or, select Paste Genie from the Edit menu.
-
In the Paste Genie dialog, select the Library "sa_controls".
-
Select one of the following from the Genie list, based on the approximate size of the list your require.
-
list_row_x5 – use this to create a list with up to 5 rows.
-
list_row_x10 – use this to create a list with up to 10 rows.
-
list_row_x40 – use this to create a list with up to 40 rows.
-
list_row_x80 – use this to create a list with up to 80 rows.
The Genie is pasted onto the graphics page. A dialog box will open, prompting you to configure the parameters for the Genie.

Note: There is no need to adjust the size of the List Row Genie on a graphics page to fill an area. The required space will be determined at runtime by the size of the list with which it is associated.
-
-
In the ArrayAN field, enter the AN value for the associated list.
You can use the Cicode function DspGetAnFromName to retrieve the AN. For example:
DspGetAnFromName("GenericList").
-
To enable on-click commands, go to the LeftClickCommand and/or RightClickCommand fields and enter the required Cicode.
See the Cicode example Test_GenericListRightClick below.
-
Click OK, and Save your page.
You can now run your project and view the alarms list.
Cicode Examples
The following Cicode provides an example of how to create the following generic list using Plant SCADA's Array Functions. The list displays random numbers with column and row identifiers.

Test_GenericListCreate
FUNCTION Test_GenericListCreate(INT hAn)
INT bDrawHeader = 1; // Draw the header row
INT hFontRow = DspFontHnd("SA_AlmRow");
INT hFontHeader = DspFontHnd("SA_AlmRow");
INT nColumn = 1;
INT nColumns = 5;
INT nRows = 10;
INT nRowHeight = 20; // pixels
INT nHeight = (nRows + 1) * nRowheight;
INT nWidth = 280; // pixels
INT nWidthTotal = 0; // Pixels, sum of column widths
INT nDataColumns = 10; // Maximum possible number of data columns
INT nDataRows = 40; // Maximum possible number of data rows
INT hArray = ArrayCreateByAn(hAn , nColumns + 1, nRows + 1, ARRAY_ZINDEX_MAX);
// +1 for Column0 (hidden), +1 for Row0 (hidden)
STRING sMapName = ArrayGetMapNameByAn(hAn);
.
// Set up array attributes
.
ArraySetIntByAn(hAn, nWidth, ARRAY_INFORMATION_COLUMN, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_ARRAY_XMAX);
ArraySetIntByAn(hAn, nHeight, ARRAY_INFORMATION_COLUMN, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_ARRAY_YMAX);
ArraySetIntByAn(hAn, nRowHeight, ARRAY_INFORMATION_COLUMN, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_ARRAY_ROWHEIGHT);
ArraySetIntByAn(hAn, bDrawHeader, ARRAY_INFORMATION_COLUMN, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_ARRAY_DRAWHEADER);
ArraySetIntByAn(hAn, hFontRow, ARRAY_INFORMATION_COLUMN, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_ARRAY_FONTROW);
ArraySetIntByAn(hAn, hFontHeader, ARRAY_INFORMATION_COLUMN, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_ARRAY_FONTHDR);
// Set up column headers
FOR nColumn = 1 TO nColumns DO
ArraySetStringByAn(hAn, "Column" + nColumn:#, nColumn, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_COLUMN_VALUE);
ArraySetIntByAn(hAn, 70, nColumn, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_COLUMN_WIDTH);
ArraySetIntByAn(hAn, ARRAY_COLUMN_TYPE_STRING, nColumn, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_COLUMN_TYPE);
nWidthTotal = nWidthTotal + 70;
END
.
ArraySetIntByAn(hAn, nWidthTotal, ARRAY_INFORMATION_COLUMN, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_ARRAY_XTOTAL);
ArraySetIntByAn(hAn, 0, ARRAY_INFORMATION_COLUMN, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_ARRAY_YTOTAL);
INT hDataArray = ArrayCreate("Test_Data", nDataColumns, nDataRows, 1);
// Data Array; 10 fields x 40 rows
MapValueSet(sMapName, "DataArray", hDataArray);
MapValueSet(sMapName, "DataColumns", nDataColumns);
MapValueSet(sMapName, "DataRows", nDataRows);
MapValueSet(sMapName, "Offset", -1);
.
TaskNew("Test_Task_GetData", hAn:#, 1 + 8);
END
FUNCTION Test_GenericListDestroy(INT hAn
INT hDataArray = -1;
STRING sMapName = "";
IF (ArrayExistsByAn(hAn)) THEN
sMapName = ArrayGetMapNameByAn(hAn);
hDataArray = MapValueGet(sMapName, "DataArray");
ArrayDestroy(hDataArray);
GenericListDestroy(hAn);
END
END
.
FUNCTION Test_Task_GetData(STRING sArg);
INT hAn = StrToInt(sArg);
INT nDataColumn = 0;
INT nDataRow = 0;
INT nDataColumns = 0;
INT nDataRows = 0;
INT hDataArray = -1;
STRING sMapName = "";
STRING nRandom = 0;
STRING sValue = "";
WHILE (TRUE) DO
IF (ArrayExistsByAn(hAn)) THEN
sMapName = ArrayGetMapNameByAn(hAn);
hDataArray = MapValueGet(sMapName, "DataArray");
nDataColumns = MapValueGet(sMapName, "DataColumns");
nDataRows = MapValueGet(sMapName, "DataRows");
ArraySetIntByAn(hAn, nDataRows, ARRAY_INFORMATION_COLUMN, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_ARRAY_YTOTAL);
FOR nDataRow = 1 TO nDataRows DO
FOR nDataColumn = 1 TO nDataColumns DO
nRandom = Rand(99);
sValue = "C" + nDataColumn:# + "R" + nDataRow:# + ">" + nRandom:#;
ArraySetString(hDataArray, sValue, nDataColumn - 1, nDataRow -1, 0);
END
END
END
SleepMS(30000);
END
END
Test_GenericListFill
FUNCTION Test_GenericListFill(INT hAn)
INT nRow = 0;
INT nRows = 10;
INT nColumn = 0;
INT nColumns = 5;
INT nOffset = 0;
INT nOffset_Previous = 0;
INT nDataColumns = 0;
INT nDataRows = 0;
INT hDataArray = -1;
STRING sMapName = "";
STRING sValue = "";
IF (ArrayExistsByAn(hAn)) THEN
_ArrayView_Header_Run(hAn);
_ArrayView_VScroll_Run(hAn);
_ArrayView_HScroll_Run(hAn);
sMapName = ArrayGetMapNameByAn(hAn);
hDataArray = MapValueGet(sMapName, "DataArray");
nOffset_Previous = MapValueGet(sMapName, "Offset");
nOffset = ArrayGetIntByAn(hAn, ARRAY_INFORMATION_COLUMN, ARRAY_INFORMATION_ROW, ARRAY_ZINDEX_ARRAY_YOFF);
hDataArray = MapValueGet(sMapName, "DataArray");
IF ((ArrayIsDirty(hDataArray)) OR (nOffset <> nOffset_Previous)) THEN
nDataColumns = MapValueGet(sMapName, "DataColumns");
nDataRows = MapValueGet(sMapName, "DataRows");
FOR nRow = 1 TO nRows DO
FOR nColumn = 1 TO nColumns DO
sValue = ArrayGetString(hDataArray, nColumn - 1, (nOffset + nRow) - 1, 0);
ArraySetStringByAn(hAn, sValue, nColumn, nRow, ARRAY_ZINDEX_CELL_VALUE);
END
END
MapValueSet(sMapName, "Offset", nOffset);
ArraySetIsDirty(hDataArray, FALSE);
END
END
END
FUNCTION Test_GenericListRightClick(INT hAn)
Message("TestGenericListRightClick", "Add context menu code here", 0);
END
Test_GenericListRightClick
FUNCTION Test_GenericListRightClick(INT hAn)
Message("TestGenericListRightClick", "Add context menu code here", 0);
END