⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 frxengine.pas

📁 报表源码 FastReport 3 is new generation of the report generators components. It consists of report engin
💻 PAS
📖 第 1 页 / 共 4 页
字号:
      end;

      if b.FGroup<>nil then
        ShowGroupFooters(TfrxGroupHeader(b.FGroup), 0);

      if not FirstTime then { some bands have been printed }
      begin
        RemoveFromVHeaderList(b.FHeader);
        if not b.FooterAfterEach then
          ShowBand(b.FFooter);
      end;

      if Report.Terminated then break;
    end;
  end;

begin
  FVMasterBand:= HBand;
  FVMasterBand.FOriginalObjectsCount:= FVMasterBand.Objects.Count;
  FVMasterBand.AllowSplit:= False;

  FVHeaderList.Clear;
  FVPageList.Clear;
  FVPageList.Add(Pointer(0));

  CurVColumn:= 0;
  ShowBandTree(TfrxReportPage(HBand.Page).FVSubBands);
  FVPageList.Add(Pointer(FVMasterBand.Objects.Count));
end;

procedure TfrxEngine.InitPage;
begin
  { fill in the header/footer lists }
  FHeaderList.Clear;
  if FPage.TitleBeforeHeader then
  begin
    FHeaderList.AddItem(FindBand(TfrxReportTitle), 0, False);
    FHeaderList.AddItem(FindBand(TfrxPageHeader), 0, False);
  end
  else
  begin
    FHeaderList.AddItem(FindBand(TfrxPageHeader), 0, False);
    FHeaderList.AddItem(FindBand(TfrxReportTitle), 0, False);
  end;

  FFooterList.Clear;
  FFooterList.Add(FindBand(TfrxColumnFooter));
  FFooterList.Add(FindBand(TfrxPageFooter));

  { calculating the page/footer sizes }
  PageHeight:= FPage.PaperHeight * fr01cm-FPage.TopMargin * fr01cm-
    FPage.BottomMargin * fr01cm;
  PageWidth:= FPage.PaperWidth * fr01cm-FPage.LeftMargin * fr01cm-
    FPage.RightMargin * fr01cm;

  { reset the current position }
  CurX:= 0;
  CurY:= 0;
  CurColumn:= 1;
  FPageCurX:= 0;

  FIsFirstPage:= True;
  FIsLastPage:= False;

  if (PreviewPages.Count = 0) or not FPage.PrintOnPreviousPage then
    AddPage
  else
  begin
    PreviewPages.CurPage:= PreviewPages.Count-1;
    CurY:= PreviewPages.GetLastY;
    ShowBand(TfrxReportTitle);
  end;

  if FFirstReportPage then
    PreviewPages.FirstPage:= PreviewPages.CurPage;
  FColumnTop:= CurY;
  ShowBand(TfrxColumnHeader);
  FHeaderList.AddItem(FindBand(TfrxColumnHeader), 0, False);
  RemoveFromHeaderList(FindBand(TfrxReportTitle));
  OutlineRoot;
  AddPageOutline;
end;

function TfrxEngine.FooterHeight:Extended;
var
  i:Integer;
begin
  Result:= 0;
  for i:= 0 to FFooterList.Count-1 do
    if FFooterList[i]<>nil then
      Result:= Result+TfrxBand(FFooterList[i]).Height;
end;

function TfrxEngine.FindBand(Band:TfrxBandClass):TfrxBand;
begin
  Result:= FPage.FindBand(Band);
end;

procedure TfrxEngine.ShowBand(Band:TfrxBand);
var
  chBand:TfrxBand;
begin
  if Band<>nil then
  begin
    if Band.KeepChild then
      StartKeep(Band);
    DoShow(Band);
    chBand:= Band.Child;
    if (chBand<>nil) and (Band.Visible or Band.PrintChildIfInvisible) then
      ShowBand(chBand);
    if Band.KeepChild then
      EndKeep(Band);
    if Band is TfrxDataBand then
      FAggregates.AddValue(Band);
  end;
end;

procedure TfrxEngine.ShowBand(Band:TfrxBandClass);
begin
  ShowBand(FindBand(Band));
end;

procedure TfrxEngine.AddToHeaderList(Band:TfrxBand);
begin
  { only header bands with "Reprint on new page" flag can be added }
  if ((Band is TfrxHeader) and TfrxHeader(Band).ReprintOnNewPage) or
     ((Band is TfrxGroupHeader) and TfrxGroupHeader(Band).ReprintOnNewPage) then
    FHeaderList.AddItem(Band, FPageCurX, FKeeping);
end;

procedure TfrxEngine.AddToVHeaderList(Band:TfrxBand);
begin
  { only header bands with "Reprint on new page" flag can be added }
  if ((Band is TfrxHeader) and TfrxHeader(Band).ReprintOnNewPage) or
     ((Band is TfrxGroupHeader) and TfrxGroupHeader(Band).ReprintOnNewPage) then
    FVHeaderList.Add(Band);
end;

procedure TfrxEngine.RemoveFromHeaderList(Band:TfrxBand);
begin
  if Band<>nil then
    FHeaderList.RemoveItem(Band);
end;

procedure TfrxEngine.RemoveFromVHeaderList(Band:TfrxBand);
begin
  if Band<>nil then
    FVHeaderList.Remove(Band);
end;

function TfrxEngine.FreeSpace:Extended;
begin
  Result:= PageHeight-FooterHeight-CurY;
end;

procedure TfrxEngine.Stretch(Band:TfrxBand);
var
  i:Integer;
  h, maxh:Extended;
  c:TfrxView;
  HaveSub, NeedShift:Boolean;

  procedure DoSubReports;
  var
    i:Integer;
    SaveCurX, SaveCurY, SavePageCurX:Extended;
    Sub:TfrxSubReport;
    MainBand:Boolean;
    AllObjects:TList;
    c:TfrxComponent;
  begin
    { create a band which will accepts all subsequent output }
    MainBand:= False;
    if FOutputTo = nil then
    begin
      Band.FOriginalObjectsCount:= Band.Objects.Count;
      FOutputTo:= TfrxNullBand.Create(nil);
      MainBand:= True;
    end;

    { save the current position }
    SaveCurX:= CurX;
    SaveCurY:= CurY;
    SavePageCurX:= FPageCurX;

    { looking for subreport objects }
    for i:= 0 to Band.Objects.Count-1 do
      if TObject(Band.Objects[i]) is TfrxSubReport then
      begin
        Sub:= TfrxSubReport(Band.Objects[i]);
        if not Sub.Visible or not Sub.PrintOnParent or not MainBand then continue;

        { set up all properties... }
        FPageCurX:= SavePageCurX+Sub.Left;
        CurX:= SaveCurX+Sub.Left;
        CurY:= Sub.Top;
        { ...and run the subreport }
        RunPage(Sub.Page);
      end;

    { restore saved position }
    CurX:= SaveCurX;
    CurY:= SaveCurY;
    FPageCurX:= SavePageCurX;

    if MainBand then
    begin
      { copy all output to the band }
      AllObjects:= FOutputTo.AllObjects;

      for i:= 0 to AllObjects.Count-1 do
      begin
        c:= AllObjects[i];
        if (c is TfrxView) and not (c is TfrxSubReport) then
        begin
          c.Left:= c.AbsLeft;
          c.Top:= c.AbsTop;
          c.Parent:= Band;
        end;
        if c is TfrxStretcheable then
          TfrxStretcheable(c).StretchMode:= smDontStretch;
      end;

      { Clear the FOutputTo property. Extra objects will be freed
        in the Unstretch method. }
      FOutputTo.Free;
      FOutputTo:= nil;
    end;
  end;

  procedure ShiftObjects(Parent:TfrxReportComponent; Amount:Extended);
  var
    i:Integer;
    v:TfrxView;
    diff:Extended;
  begin
    for i:= 0 to Parent.FShiftChildren.Count-1 do
    begin
      v:= Parent.FShiftChildren[i];
      if v.ShiftMode = smAlways then
      begin
        v.Top:= v.Top+Amount;
        ShiftObjects(v, Amount+v.FShiftAmount);
      end
      else if v.ShiftMode = smWhenOverlapped then
      begin
        if v.Top < Parent.Top+Parent.Height then
        begin
          diff:= Parent.Top+Parent.Height-v.Top;
          v.Top:= Parent.Top+Parent.Height;
          ShiftObjects(v, diff);
        end;
      end
    end;
  end;

begin
  FCurBand:= Band;
  HaveSub:= False;
  NeedShift:= False;
  PrepareShiftTree(Band);

  { it is not necessary for vertical bands }
  if Band<>FVMasterBand then
  begin
    { firing band OnBeforePrint event }
    Report.CurObject:= Band.Name;
    Band.BeforePrint;
    Report.DoBeforePrint(Band);
  end;

  { firing OnBeforePrint events, stretching objects }
  for i:= 0 to Band.Objects.Count-1 do
  begin
    c:= Band.Objects[i];
    if (c is TfrxSubReport) and TfrxSubReport(c).PrintOnParent then
      HaveSub:= True;

    { skip getdata for vertical bands' objects }
    if Band<>FVMasterBand then
    begin
      Report.CurObject:= c.Name;
      c.BeforePrint;
      if Band.Visible then
      begin
        Report.DoBeforePrint(c);
        if c.Visible then
        begin
          c.GetData;
          Report.DoNotifyEvent(c, c.OnAfterData);
        end;
      end;
    end;
    if not Band.Visible or not c.Visible then continue;

    if (c is TfrxStretcheable) and (TfrxStretcheable(c).StretchMode<>smDontStretch) then
    begin
      h:= TfrxStretcheable(c).CalcHeight;
      if h > c.Height then
      begin
        c.FShiftAmount:= h-c.Height; { needed to shift underlying objects }
        c.Height:= h; { stretch the object }
        NeedShift:= True;
      end
      else
        c.FShiftAmount:= 0;
    end;
  end;

  if not Band.Visible then Exit;

  { shift objects }
  if NeedShift then
    ShiftObjects(Band, 0);

  { check subreports that have PrintOnParent option }
  if HaveSub then
    DoSubReports;

  { calculate the max height of the band }
  maxh:= 0;
  for i:= 0 to Band.Objects.Count-1 do
  begin
    c:= Band.Objects[i];
    if c.Top+c.Height > maxh then
    begin
      maxh:= c.Top+c.Height;
      if (c is TfrxDMPMemoView) and (ftBottom in TfrxDMPMemoView(c).Frame.Typ) then
        maxh:= maxh+fr1CharY;
    end;
  end;
  if Band.Stretched then
    Band.Height:= maxh;

  { fire Band.OnAfterCalcHeight event }
  Report.CurObject:= Band.Name;
  Report.DoNotifyEvent(Band, Band.OnAfterCalcHeight);

  { set the height of objects that should stretch to max height }
  for i:= 0 to Band.Objects.Count-1 do
  begin
    c:= Band.Objects[i];
    if (c is TfrxStretcheable) and (TfrxStretcheable(c).StretchMode = smMaxHeight) then
    begin
      c.Height:= maxh-c.Top;
      if (c is TfrxDMPMemoView) and (ftBottom in TfrxDMPMemoView(c).Frame.Typ) then
        c.Height:= c.Height-fr1CharY;
    end;
  end;
end;

procedure TfrxEngine.UnStretch(Band:TfrxBand);
var
  i:Integer;
  c:TfrxView;
begin
  { fire OnAfterPrint event }
  if Band.Visible then
    for i:= 0 to Band.Objects.Count-1 do
    begin
      c:= Band.Objects[i];
      Report.CurObject:= c.Name;
      Report.DoAfterPrint(c);
    end;

  { restore state }
  for i:= 0 to Band.Objects.Count-1 do
  begin
    c:= Band.Objects[i];
    c.AfterPrint;
  end;

  Report.CurObject:= Band.Name;
  Report.DoAfterPrint(Band);
  Band.AfterPrint;

  { remove extra band objects if any }
  if Band.FOriginalObjectsCount<>-1 then
  begin
    while Band.Objects.Count > Band.FOriginalObjectsCount do
      TObject(Band.Objects[Band.Objects.Count-1]).Free;
    Band.FOriginalObjectsCount:=-1;
  end;
end;

procedure TfrxEngine.AddPage;
var
  i:Integer;
  SaveCurX:Extended;
  SaveCurLine, SaveCurLineThrough:Integer;
  Band:TfrxBand;
begin
  PreviewPages.AddPage(FPage);
  CurY:= 0;

  Band:= FindBand(TfrxOverlay);
  if (Band<>nil) and not TfrxOverlay(Band).PrintOnTop then
    ShowBand(Band);

  CurY:= 0;
  SaveCurX:= CurX;
  HeaderHeight:= 0;

  for i:= 0 to FHeaderList.Count-1 do
  begin
   { use own CurX-we may be inside subreports now }
    CurX:= FHeaderList[i].Left;
    Band:= FHeaderList[i].Band;

    if FIsFirstPage and (Band is TfrxPageHeader) and
      not TfrxPageHeader(Band).PrintOnFirstPage then
      continue;

    if Band<>nil then
      if not FKeeping or not FHeaderList[i].IsInKeepList then
      begin
        Band.Overflow:= True;
        SaveCurLine:= CurLine;
        SaveCurLineThrough:= CurLineThrough;
        CurLine:= Band.FLineN;
        CurLineThrough:= Band.FLineThrough;
        FCallFromAddPage:= True;

        { fix the stack overflow error if call NewPage from ReportTitle }
        if Band is TfrxReportTitle then
          FHeaderList[i].Band:= nil;
        if Band is TfrxPageHeader then
          HeaderHeight:= Band.Height;

        ShowBand(Band);

        FCallFromAddPage:= False;
        Band.Overflow:= False;
        CurLine:= SaveCurLine;
        CurLineThrough:= SaveCurLineThrough;
      end;
  end;

  CurX:= SaveCurX;
end;

procedure TfrxEngine.EndPage;
var
  i:Integer;
  Band:TfrxBand;

  procedure ShowBand(Band:TfrxBand);
  begin
    if Band = nil then Exit;

    Stretch(Band);
    try
      if Band.Visible then
      begin
        Band.Left:= 0;
        Band.Top:= CurY;

        if Band is TfrxPageFooter then
          if (FIsFirstPage and not TfrxPageFooter(Band).PrintOnFirstPage) or
             (FIsLastPage and not TfrxPageFooter(Band).PrintOnLastPage) then
          Exit;

        if not PreviewPages.BandExists(Band) then
          PreviewPages.AddObject(Band);
        CurY:= CurY+Band.Height;
      end;
    finally
      UnStretch(Band);
    end;

    FAggregates.Reset(Band);
  end;

begin
  if FPage.Columns > 1 then
  begin
    EndColumn;
    CurX:= FPageCurX;
    CurColumn:= 1;
    FColumnTop:= 0;
  end;

  for i:= 0 to FFooterList.Count-1 do
  begin
    Band:= FFooterList[i];
    if Band is TfrxPageFooter then
      CurY:= PageHeight-Band.Height;
    ShowBand(Band);
  end;

  Band:= FindBand(TfrxOverlay);
  if (Band<>nil) and TfrxOverlay(Band).PrintOnTop then
  begin
    CurY:= 0;
    ShowBand(Band);
  end;

  FIsFirstPage:= False;
end;

procedure TfrxEngine.AddColumn;
var
  i:Integer;
  DontShow:Boolean;
  AddX:Extended;

  procedure DoShow(Band:TfrxBand);
  begin
    Band.Overflow:= True;
    Stretch(Band);

    try
      if Band.Visible then
      begin
        Band.Left:= CurX;
        Band.Top:= CurY;
        if not DontShow then
          PreviewPages.AddObject(Band);
        CurY:= CurY+Band.Height;
      end;
    finally
      UnStretch(Band);
      Band.Overflow:= False;
    end;
  end;

  procedure ShowBand(Band:TfrxBand);
  begin
    while Band<>nil do
    begin
      DoShow(Band);
      if Band.Visible or Band.PrintChildIfInvisible then
        Band:= Band.Child else
        break;
    end;
  end;

begin
  CurColumn:= CurColumn+1;
  AddX:= frxStrToFloat(FPage.ColumnPositions[CurColumn-1]) * fr01cm;
  CurY:= FColumnTop;

  { if FColumnTop = 0, we need to calculate the column position if page header
    band exists. Elsewhere, we skip the page header }
  for i:= 0 to FHeaderList.Count-1 do
  begin
    CurX:= FHeaderList[i].Left+AddX;
    DontShow:= FHeaderList[i].Band is TfrxPageHeader;
    if not DontShow or (CurY = 0) then
      ShowBand(FHeaderList[i].Band);
  end;

  CurX:= FPageCurX+AddX;
end;

procedure TfrxEngine.EndColumn;
var
  Band:TfrxBand;
begin
  Band:= FindBand(TfrxColumnFooter);
  if Band = nil then Exit;

// CurY:= PageHeight-FooterHeight;
  Stretch(Band);
  try
    if Band.Visible then
    begin
      Band.Left:= CurX-FPageCurX;
      Band.Top:= CurY;
      PreviewPages.AddObject(Band);
    end;
  finally
    UnStretch(Band);
  end;

  FAggregates.Reset(Band);
end;

procedure TfrxEngine.NewPage;
begin
  if FKeeping then
    PreviewPages.CutObjects(FKeepPosition);
  EndPage;
  AddPage;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -