To get a sense of how everything fits together, imagine a report of students grouped by grade, with the total number of students in each grade.

The report has a query that accesses the table of students, named students1; a StreamSource object, by default named streamSource1, to stream the data from the query; and a PageTemplate object, by default named pageTemplate1, that describes the physical attributes of the page, such as its dimensions, background color, and margins.

pageTemplate1 contains one StreamFrame object, by default named streamFrame1, where the data stream will be rendered. It occupies most of the space inside pageTemplate1’s margins. The rest of the space is used by Text components that display the report title, date, and page.

streamFrame1 has a streamSource property that identifies its StreamSource object. It is assigned streamSource1.

streamSource1 has a rowset property that identifies the StreamSource object’s rowset. It is assigned students1.rowset.

students1.rowset and streamFrame1 are now linked. To fill streamFrame1 with data, the report engine will traverse students1.rowset, from the first row to the last row. But at this point, no data will be displayed, because there are no visual components in any Band objects.

Text components are assigned to streamSource1.detailBand. The text properties of these components are expression codeblocks that refer to the value properties of the fields of the rowset of the StreamSource object. For example, the text of the Text component that displays the student’s last name is

{||this.form.students1.rowset.field[ "Last name" ].value}

When a visual component is placed in a report, its form property refers to the report.

To group the data, a Group object, named group1 by default, is assigned to streamSource1. Its groupBy property contains the name of the group field, "Grade". The report engine will watch the value of this field in the rowset, that is:

students1.rowset.field[ "Grade" ].value

and whenever the value of the field changes, a new group begins. Therefore, it’s important that the data is sorted by grade. If the report’s autoSort property is true, all of the report’s queries will automatically be sorted to match the groups in the StreamSource objects.

group1 has two Band objects of its own: a header band and a footer band, assigned to the headerBand and footerBand properties respectively. The headerBand is currently empty, and the footerBand displays the count of the students in that grade.

The Group object’s agCount( ) method counts the number of rows in the group. To display that number, the text of the Text component in the footerBand is set to the following expression codeblock:

{||"Count: " + this.parent.parent.agCount({||this.parent.rowset.fields["ID"].value})}

The expression codeblock concatenates the text label with the return value of the Group object’s agCount( ) method. To get to that method from a component in the footerBand,

this is the component.

The component’s parent is the footerBand.

The footerBand’s parent is the Group.

The agCount( ) method expects a code reference as a parameter that it can evaluate. If the return value is not null, the count is incremented. The code reference here is another expression codeblock that uses dot operators:

this is the Group object group1.

group1’s parent is streamSource1.

streamSource1’s rowset is students1.rowset, the rowset that the report engine is traversing to fill streamFrame1.

That’s all the objects that go into a report of students, grouped by grade, with the number of students in each grade. There are two final details that are needed to make the report work.

Because a report can have multiple PageTemplate objects, a Report object has a firstPageTemplate property that refers to the PageTemplate object to use for the first page. It is assigned pageTemplate1.

Each PageTemplate object has a nextPageTemplate property that refers to the PageTemplate object to use when the current page is done. For pageTemplate1, it is assigned a reference to itself. This means that the same page layout is used for every page in the report.

Everything described in this sample report can be handled automatically by the Report Wizard. To run the report, call the Report object’s render( ) method.