Drucken der Endsumme der Gruppe im Gruppenkopf

Navigation:  »No topics above this level«

Drucken der Endsumme der Gruppe im Gruppenkopf

Return to chapter overview

Dieser oft durchgeführte Schritt benötigt die Verwendung eines Scriptes. In einem Standardreport ist die Summe erst zugänglich nachdem alle Einträge der Gruppe bearbeitet wurden. Um diese im Gruppenkopf darzustellen (bevor die Gruppe bearbeitet wird) verwendet man folgenden Algorithmus:

- der Report muss Zweipass aktiviert haben

- beim ersten Durchgang wird die Summe jeder Gruppe ermittelt und in irgendeinem Datenfeld gespeichert

- beim zweiten Durchgang wird diese aus dem Datenfeld geholt und im Gruppenkopf dargestellt.

 

Demonstrieren wir die Lösung dieser Aufgabe auf zwei Arten. Als erstes erstellen wir ein neues Projekt in Delphi und legen auf die Seite die Komponenten TQuery, TfrxReport, TfrxDBDataSet. Die Einstellungen sind wie folgt:

 

Query1:

DatabaseName = 'DBDEMOS'

SQL =

select * from customer, orders

where orders.CustNo = customer.CustNo

order by customer.CustNo, orders.OrderNo

 

frxDBDataSet1:

DataSet = Query1

UserName = 'Group'

 

Jetzt gehen wir in den Designer und verknüpfen unsere Datenquelle mit dem Report. In den Einstellungen des Reports (Menüpunkt "Report|Einstellungen...") aktivieren wir Zweipass. Zwei Bänder werden eingefügt: "Gruppenkopf" und "Daten 1. Ebene". Im Editor des Bandes "Gruppenkopf" fügen wir die Bedingung Datenfeld Group.CustNo ein: Das Datenband verknüpfen wir mit der Datenquelle und ordnen die Objekte folgendermaßen an:

 

clip0197

 

 

Das markierte Objekt in der Grafik (der Name: Memo8) benutzen wir um die Summe anzuzeigen.

 

Möglichkeit 1.

 

Wir verwenden als Datenfeld für die Aufbewahrung der Summen "TstringList". Die Summe soll in Form von Zeilen gespeichert werden. Dabei soll die erste Zeile die Werte der ersten Gruppe darstellen usw. Die Gruppennummer soll eine ganzzahlige Variable sein, die sich mit jeder folgenden Gruppe erhöht.

 

Unser Script sieht in diesem Fall so aus:

 

PascalScript:

 

var

 List: TStringList;

 i: Integer;

 

procedure frxReport1OnStartReport(Sender: TfrxComponent);

begin

 List := TStringList.Create;

end;

 

procedure frxReport1OnStopReport(Sender: TfrxComponent);

begin

 List.Free;

end;

 

procedure Page1OnBeforePrint(Sender: TfrxComponent);

begin

 i := 0;

end;

 

procedure GroupHeader1OnBeforePrint(Sender: TfrxComponent);

begin

if Engine.FinalPass then

   Memo8.Text := 'Sum: ' + List[i];

end;

 

procedure GroupFooter1OnBeforePrint(Sender: TfrxComponent);

begin

ifnot Engine.FinalPass then

   List.Add(FloatToStr(SUM(<Group."ItemsTotal">,MasterData1)));

 Inc(i);

end;

 

begin

 

end.

 

 

C++ Script:

 

TStringList List;

int i;

 

void frxReport1OnStartReport(TfrxComponent Sender)

{

 List = TStringList.Create();

}

 

void frxReport1OnStopReport(TfrxComponent Sender)

{

 List.Free();

}

 

void Page1OnBeforePrint(TfrxComponent Sender)

{

 i = 0;

}

 

void GroupHeader1OnBeforePrint(TfrxComponent Sender)

{

if (Engine.FinalPass)

   Memo8.Text = "Sum: " + List[i];

}

 

void GroupFooter1OnBeforePrint(TfrxComponent Sender)

{

 List.Add(FloatToStr(SUM(<Group."ItemsTotal">,MasterData1)));

 i++;

}

 

{

 

}

 

An dem Namen der Prozedur kann man sehen, welches Ereignis wir verwendet haben: Report.OnStartReport, Report.OnStopReport, Page1.OnBeforePrint, GroupHeader1.OnBeforePrint, GroupFooter1.OnBeforePrint. Was die beiden ersten Ereignisse angeht, so werden diese am Anfang und am Ende eines Reports aufgerufen. Um die Bearbeiter für diese Ereignisse zu erstellen, markieren wir das Objekt "Report" im Fenster "Reporttree". Die Eigenschaften erscheinen dadurch im Objektinspektor. Den Rest erledigen wir wie gewohnt, indem wir auf den Tab "Ereignisse" des Inspektors gehen und die Bearbeiter erstellen.

 

Wieso haben wir für die Erstellung der Liste List nicht die Hauptprozedur benutzt, sondern haben es im Ereignis OnStartReport gemacht? Weil das erstellte Objekt nach dem Vollenden des Reports befreit werden muss. Logischerweise ist es besser die Objekte im Ereignis OnStartReport zu erstellen und im OnStopReport zu befreien. In anderen Fällen (wenn der Speicher nicht befreit werden muss) kann man die Hauptprozedur verwenden um Variablen zu initialisieren.  

 

Das  Erstellen und das Befreien des Objektes "List" haben wir geklärt. Lassen Sie uns nun die Arbeitsweise des Scripts betrachten. Am Anfang der Seite wird der Zähler der laufenden Gruppe (Variable i) auf 0 gesetzt und wird um 1 erhöht nach jeder neuen Gruppe (im Ereignis GroupFooter1.OnBeforePrint). Ebenfalls wird in diesem Ereignis die Summe in die Liste eingefügt. Das Ereignis GroupHeader1.OnBeforePrint funktioniert beim ersten Durchgang nicht (Überprüfung Engine.FinalPass). Beim zweiten Durchgang (wenn die Liste List mit Werten gefüllt ist), wird dieses Eeignis den Wert der aktuellen Gruppe anzeigen und in den Text des Objektes Memo8 eintragen. Der Text zeigt die Summe in der Kopfzeile der Gruppe. Im fertigen Report sieht es so aus:

 

_img239

 

Wie man sieht ist der Algorithmus relativ einfach. Man kann ihn aber noch einfacher gestalten.

 

Möglichkeit 2.

 

Wir verwenden als Datenfeld zum Speichern der Summen die Liste der Reportvariablen. Der Bezug auf diese Variablen läuft mit den Funktionen Get und Set. Dadurch müssen wir nicht neue Objekte erstellen und der Speicher muss nicht gelöscht werden. Das Script sieht dann so aus:

 

PascalScript:

 

procedure GroupHeader1OnBeforePrint(Sender: TfrxComponent);

begin

if Engine.FinalPass then

   Memo8.Text := 'Sum: ' + Get(<Group."CustNo">);

end;

 

procedure GroupFooter1OnBeforePrint(Sender: TfrxComponent);

begin

 Set(<Group."CustNo">,

   FloatToStr(SUM(<Group."ItemsTotal">,MasterData1)));

end;

 

begin

 

end.

 

 

C++ Script:

 

void GroupHeader1OnBeforePrint(TfrxComponent Sender)

{

if (Engine.FinalPass)

   Memo8.Text = "Sum:" + Get(<Group."CustNo">);

}

 

void GroupFooter1OnBeforePrint(TfrxComponent Sender)

{

 Set(<Group."CustNo">,

   FloatToStr(SUM(<Group."ItemsTotal">,MasterData1)));

}

 

{

 

}

 

Wie man sieht ist das Script wesentlich einfacher geworden. Der Code im Bearbeiter GroupFooter1.OnBeforePrint stellt den Wert der Variablen mit dem Namen des Kunden (der Gleich der Kundennummer ist) dar. Man kann ein beliebiges Identifizierungszeichen verwenden, das den Kunden eindeutig  identifiziert z. B. seinen Namen <Group."Company">. Gibt es eine solche Variable nicht, so wird sie erstellt. Gibt es sie, so wird deren Wert geändert. Im Bearbeiter GroupHeader1.OnBeforePrint wird der Wert der Variablen mit der Nummer der aktuellen Gruppe angezeigt.