1

I have code that creates summary footers at runtime for numeric columns, but I can't get the group summary results to show. I've looked at How to create group summaries at runtime and How to set group summary values and How can create summary footer on runtime? but I'm hitting runtime error:

EcxInvalidDataControllerOperation with message 'RecordIndex out of range'

when the grid is rendering.

This code accepts any TcxGridDBTableView so it would be very easy to put into an existing Delphi form.

procedure SummaryGroup(ASummary: TcxDataSummary; AColumn: TcxGridDBColumn;
  AKind: TcxSummaryKind; AFormat: string);
var
  sumGroup: TcxDataSummaryGroup;
  link: TcxGridTableSummaryGroupItemLink; //TcxDataSummaryGroupItemLink;
  item: TcxGridDBTableSummaryItem;
begin
  AColumn.Summary.FooterKind := AKind;
  AColumn.Summary.FooterFormat := AFormat;
  sumGroup := ASummary.SummaryGroups.Add;
  link := sumGroup.Links.Add as TcxGridTableSummaryGroupItemLink;
  link.Column := AColumn;
  item := sumGroup.SummaryItems.Add as TcxGridDBTableSummaryItem;
  item.Column := AColumn;
  item.Kind := AKind;
  item.Position := spGroup;
  item.Format := AColumn.Summary.FooterFormat;
end;

procedure AutoAwesum(AView: TcxGridDBTableView);
var
  summary: TcxDataSummary;
  summing: Boolean;
  i: Integer;
  dc: TcxGridDBDataController;
  col: TcxGridDBColumn;

begin
  dc := AView.DataController;
  summing := False;
  summary := dc.Summary;
  summary.BeginUpdate;
  try
    summary.SummaryGroups.Clear;
    dc.BeginFullUpdate;
    try
      dc.GridView.ClearItems;
      dc.CreateAllItems;
      for i := 1 to AView.ColumnCount - 1 do
      begin
        col := AView.Columns[i];
        case col.DataBinding.Field.DataType of
          ftSmallint, ftInteger, ftWord, ftLargeint, ftAutoInc,
          ftLongWord, ftShortint:
            begin
              summing := true;
              SummaryGroup(summary, col, skSum, '#');
            end;
          ftFloat, ftBCD, ftFMTBcd, ftExtended, ftSingle:
            begin
              summing := true;
              SummaryGroup(summary, col, skSum, '#.##');
            end;
          ftCurrency:
            begin
              summing := true;
              SummaryGroup(summary, col, skSum, '$#.##');
            end;
        end;
      end;
      dc.DataModeController.GridMode := not summing;
      AView.OptionsView.Footer := summing;
      AView.OptionsView.GroupFooterMultiSummaries := summing;
      AView.OptionsView.GroupFooters := gfVisibleWhenExpanded;
    finally
      dc.EndFullUpdate;
    end;
  finally
    summary.EndUpdate;
  end;
end;

What am I missing? Thanks.

Community
  • 1
  • 1
John Kaster
  • 2,509
  • 1
  • 33
  • 40
  • Which line is generating the exception? – Ken White Oct 03 '14 at 23:22
  • it's not happening in my code. It's in the cxGrid runtime, on TcxCustomDataController.CheckRecordRange. – John Kaster Oct 03 '14 at 23:51
  • Then look at the stack trace, and figure out where in *your* code the exception is being triggered. If the exception is indeed not traceable to your own code, then you need to file a bug report with the vendor instead. – Ken White Oct 03 '14 at 23:55
  • Thanks for the reply, Ken. As I said in my original question, the error occurs when the grid is rendering. This is after my code has set the properties on the grid (without errors). I was hoping that by providing complete, generic code that would work for any TcxGrid I could get specific pointers on what properties of the grid might be missing, rather than general advice on how to debug a problem in Delphi. – John Kaster Oct 04 '14 at 00:31
  • Hmmm. OK, but that again appears to be something that should be asked at the vendor's forums (isn't that a Developers Express component?) rather than here. It's pretty difficult to debug a third-party vendor's component without the code that's using that component, unless you're extremely familiar with the internal workings of that component. Can you provide a MVCE that sets the properties at runtime that produces the error? Or include the text from a DFM that sets the properties as you have them? – Ken White Oct 04 '14 at 00:36
  • I've seen many other responses to TcxGrid questions here, so I thought perhaps I would encounter someone familiar with it. My code can be added to any Delphi form that has a TcxGrid and be called once the datasource is established for the grid, but debugging is of limited utility. I'll open a ticket Monday if I don't have an answer by then. I was hoping someone had already solved this problem. In the meantime I'll continue to debug it myself to see if I can navigate the code labyrinth successfully. – John Kaster Oct 04 '14 at 00:51
  • John: if I were you I'd ask support, but just in case I'll flag them to come take a look here. I'd also note you don't mention version numbers of the DevExpress VCL product nor of which compiler you are using, both of which might be germane. – jmbucknall Oct 06 '14 at 19:02
  • @boyetboy thanks Julian. It'x XE4 and ExpressQuantumGrid Suite 12.1.6. I was going to ask support this week if I didn't get an answer here. FWIW, I could also use XE7 for it, but I think it would still be the same grid quite version unless we've taken an update for it. (This is a utility for me to use at WideOrbit.) – John Kaster Oct 06 '14 at 20:31

1 Answers1

1

Finally had a chance to get back to this. As expected, the changes were few and simple. Here's the code that generically creates group summary headers for each numeric column in a grid. I've left some options commented out in the code that you may want to use.

uses
  cxGridDBDataDefinitions;

procedure Summarize(ASummary: TcxDataSummary; AColumn: TcxGridDBColumn;
  AKind: TcxSummaryKind; AFormat: string);
var
  sumGroup: TcxDataSummaryGroup;
  link: TcxGridTableSummaryGroupItemLink;
  item: TcxGridDBTableSummaryItem;
begin
  AColumn.Summary.FooterKind := AKind;
  AColumn.Summary.FooterFormat := AFormat;
  AColumn.Summary.GroupKind := AKind;
  AColumn.Summary.GroupFormat := AFormat;
  AColumn.GroupIndex := -1;
  sumGroup := ASummary.SummaryGroups.Add;
  link := sumGroup.Links.Add as TcxGridTableSummaryGroupItemLink;
  link.Column :=  AColumn;
  item := sumGroup.SummaryItems.Add as TcxGridDBTableSummaryItem;
  item.Column := AColumn;
  item.Kind := skSum;
  item.Position := spGroup;
  item.Format := AColumn.Summary.FooterFormat;
end;

procedure AutoAwesum(AView: TcxGridDBTableView);
var
  summary: TcxDataSummary;
  summing: Boolean;
  i: Integer;
  dc: TcxGridDBDataController;
  col: TcxGridDBColumn;

begin
  dc := AView.DataController;
  summing := False;
  summary := dc.Summary;
  summary.BeginUpdate;
  try
    summary.SummaryGroups.Clear;
    dc.BeginFullUpdate;
    try
      dc.GridView.ClearItems;
      dc.CreateAllItems;
      for i := 1 to AView.ColumnCount - 1 do
      begin
        col := AView.Columns[i];
        case col.DataBinding.Field.DataType of
          ftSmallint, ftInteger, ftWord, ftLargeint, ftAutoInc,
          ftLongWord, ftShortint:
            begin
              summing := true;
              Summarize(summary, col, skSum, ',0');
            end;
          ftFloat, ftBCD, ftFMTBcd, ftExtended, ftSingle:
            begin
              summing := true;
              Summarize(summary, col, skSum, ',.00');
            end;
          ftCurrency:
            begin
              summing := true;
              Summarize(summary, col, skSum, '$,0.00');
            end;
        end;
      end;
//      dc.DataModeController.GridMode := not summing;
//      AView.OptionsView.Header := summing;
      AView.OptionsView.Footer := summing;
//      AView.OptionsView.GroupFooterMultiSummaries := summing;
//      AView.OptionsView.GroupFooters := gfVisibleWhenExpanded;
    finally
      dc.EndFullUpdate;
    end;
  finally
    summary.EndUpdate;
  end;
end;
John Kaster
  • 2,509
  • 1
  • 33
  • 40