Search Results for

    Show / Hide Table of Contents

    グループ ヘッダーでのグループの合計の出力

    この手法はかなり頻繁に使用されるものですが、スクリプトの使用を必要とします。なぜなら、グループ合計の値は、そのグループ内のすべてのレコードが処理された後にしかわからないからです。グループ ヘッダー(つまり、グループがレポートに出力される前)に合計を表示するために、次のアルゴリズムが使用されます。

    • レポートのダブル パス オプションをオンにする([レポート]>[オプション]メニュー項目)

    • 最初のパスで、各グループの合計を計算し、それらを配列に保存する

    • 第 2 パスで、その配列から値を抽出し、グループ ヘッダーにそれらを表示する

    このタスクを実行するための 2 つの方法を見てみましょう。初めに、Delphi で新しいプロジェクトを作成し、フォーム上に TQuery、TfrxReport、および TfrxDBDataSet コンポーネントを置いて、次のように設定します。

    Query1:
    DatabaseName = 'DBDEMOS'
    SQL = 
      select * from customer, orders
      where orders.CustNo = customer.CustNo
      order by customer.CustNo, orders.OrderNo
    
    frxDBDataSet1:
    DataSet = Query1
    UserName = 'Group'
    

    デザイナーを開いて、データ ソースをレポートに接続します。レポートの設定で、ダブル パスを有効にします([レポート]>[オプション]メニュー項目)。グループ ヘッダーとマスター データの 2 つのバンドをレポートに追加します。グループ ヘッダー バンドのエディターで、Group."CustNo" データ フィールドを入力します。データ バンドを Group データ ソースに接続し、いくつかのオブジェクトを次のように配置します。

    合計を表示するために、図のデザイン内で矢印の付いているオブジェクトを使用します(この例では、"Memo8" という名前のオブジェクトです)。

    1 つ目の方法

    合計を格納する配列として TStringList クラスを使用します。つまり、数値を文字列として格納します。StringList 内の最初の項目は最初のグループの合計に対応し、2 番目の項目は 2 番目のグループの合計に対応する、という具合になります。整数値の変数(各グループの出力後に増加させる)は、グループのインデックス番号を求めるために使用されます。

    したがって、スクリプトは次のようになります。

    Pascal スクリプト:

    var
      List: TStringList;
      i: Integer;
    
    procedure frReport1OnStartReport(Sender: TfrxComponent);
    begin
      List := TStringList.Create;
    end;
    
    procedure frReport1OnStopReport(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
      if not Engine.FinalPass then
        List.Add(FloatToStr(SUM(<Group."ItemsTotal">,MasterData1)));
      Inc(i);
    end;
    
    begin
    end.
    

    C++ スクリプト:

    TStringList List;
    int i;
    
    void frReport1OnStartReport(TfrxComponent Sender)
    {
      List = TStringList.Create();
    }
    
    void frReport1OnStopReport(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++;
    }
    
    {
    }
    

    スクリプト内のプロシージャ名は、使用したイベントを示しています。それらは、Report.OnStartReport、Report.OnStopReport、Page1.OnBeforePrint、GroupHeader1.OnBeforePrint、および GroupFooter1.OnBeforePrint です。最初の 2 つのイベントは、それぞれレポートの最初と最後に呼び出されます。

    これら 2 つのイベントのハンドラーを作成するには、オブジェクト インスペクターのドロップダウン リストで Report オブジェクトを選択します。そうすると、そのプロパティがオブジェクト インスペクターに表示されます。その後、オブジェクト インスペクターの[イベント]タブに切り替えて、ハンドラーを作成します。

    スクリプトのメイン プロシージャで List 変数を作成しなかったのはなぜでしょうか?作成した変数はレポート完成後に動的に破棄する必要があるため、この変数は OnStartReport イベントで作成しました。OnStartReport イベントで動的変数を作成し、OnStopReport イベントでそれらを破棄するのは、理にかなっています。ほかの場合(スクリプトの完了時にメモリを空にする必要がないとき)には、スクリプトのメイン プロシージャを使用して変数の初期化を行えます。

    List 変数の作成と破棄はごく簡単です。では、スクリプトがどのように働くか見てみましょう。

    • ページの先頭で、現在のグループのカウンター(変数 "i")がゼロにリセットされ、各グループの出力後にカウンター値が増分されます(GroupFooter1.OnBeforePrint イベント)。
    • 計算された合計の値は、カウンター値が増分される前に、このイベントで List に追加されます。
    • GroupHeader1.OnBeforePrint イベントは、最初のパス(If Engine.FinalPass 条件)の間は何もしません。第 2 パス(List に値が入れられるとき)の間に、現在のグループに対応する合計が List から取り出され、グループ ヘッダーに合計を表示するための "Memo8" オブジェクトに出力されます。

    完成したレポートでは、次のように表示されます。

    このアルゴリズムは非常に簡単です。それでもなお、簡略化することができます。

    2 つ目の方法

    グループ合計を格納する配列として、レポート変数のコレクションを使用します。レポート変数には、Get 関数および Set 関数によってアクセスするということを思い出してください。これらの関数を使用すると、変数を明示的に作成して破棄する手間も省かれます。スクリプトは次のようになります。

    Pascal スクリプト:

    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++ スクリプト:

    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)));
    }
    
    {
    }
    

    ご覧のように、このスクリプトは割に簡単です。GroupFooter1.OnBeforePrint ハンドラーのコードでは、クライアント番号から派生した名前を持つ変数(あるいは、明確にクライアントを識別する任意の識別子、たとえば、<Group."Company"> などを使用できます)の値を設定します。

    そのような名前の変数が存在しない場合は、スクリプトが自動的に変数を作成します。存在する場合は、その値が更新されます。GroupHeader1.OnBeforePrint ハンドラーでは、適切な変数の値が取得されます。

    Back to top © Copyright Fast Reports Inc.