📄 frxengine.pas
字号:
if b2 is TfrxHeader then { if top band is header, connect it }
begin
b1.FHeader := b2;
Bands[i - 1] := nil;
end;
end;
if i < Bands.Count - 1 then { if bottom band is footer, connect it }
begin
b2 := Bands[i + 1];
if b2 is TfrxFooter then
begin
b1.FFooter := b2;
Bands[i + 1] := nil;
end;
end;
end;
end;
ClearNils;
{ now all headers/footers must be connected. If not, add an error }
for i := 0 to Bands.Count - 1 do
begin
b1 := Bands[i];
if (b1 is TfrxHeader) or (b1 is TfrxFooter) then
begin
ErrorList.Add(frxResources.Get('enUnconnHeader') + ' ' + b1.Name);
Bands[i] := nil;
end;
end;
ClearNils;
end;
procedure ConnectGroups;
var
i, j: Integer;
b1, b2: TfrxBand;
begin
{ connect group headers }
i := 0;
while i < Bands.Count do
begin
b1 := Bands[i];
if b1 is TfrxGroupHeader then
begin
b1.FSubBands.Add(b1);
Inc(i);
{ add all subsequent headers to the first header's FSubBands }
while (i < Bands.Count) and (TfrxBand(Bands[i]) is TfrxGroupHeader) do
begin
b1.FSubBands.Add(Bands[i]);
Inc(i);
end;
{ search for databand }
while (i < Bands.Count) and not (TfrxBand(Bands[i]) is TfrxDataBand) do
Inc(i);
{ now we expect to see the databand }
if (i = Bands.Count) or not (TObject(Bands[i]) is TfrxDataBand) then
ErrorList.Add(frxResources.Get('enUnconnGroup') + ' ' + b1.Name)
else
TfrxBand(Bands[i]).FGroup := b1;
end
else
Inc(i);
end;
{ connect group footers }
for i := 0 to Bands.Count - 1 do
begin
b1 := Bands[i];
if b1 is TfrxGroupFooter then
for j := i - 1 downto 0 do
begin
b2 := Bands[j];
if b2 is TfrxGroupHeader then { connect to top-nearest header }
begin
b2.FFooter := b1;
Bands[i] := nil;
Bands[j] := nil;
break;
end;
end;
end;
{ remove header bands from the list }
for i := 0 to Bands.Count - 1 do
begin
b1 := Bands[i];
if b1 is TfrxGroupHeader then
Bands[i] := nil;
end;
{ looking for footers w/o corresponding header }
for i := 0 to Bands.Count - 1 do
begin
b1 := Bands[i];
if b1 is TfrxGroupFooter then
begin
ErrorList.Add(frxResources.Get('enUnconnGFooter') + ' ' + b1.Name);
Bands[i] := nil;
end;
end;
ClearNils;
end;
begin
SortBands := TStringList.Create;
SortBands.Sorted := True;
{ align all objects with Align property <> baNone }
FPage.AlignChildren;
{ clear all page SubBands }
if PrepareVBands then
FPage.FVSubBands.Clear
else
FPage.FSubBands.Clear;
for i := 0 to FPage.Objects.Count - 1 do
begin
t := FPage.Objects[i];
if t is TfrxBand then
begin
b := TfrxBand(t);
if b.Vertical <> PrepareVBands then
continue;
PrepareShiftTree(b);
b.FSubBands.Clear;
b.FHeader := nil;
b.FFooter := nil;
b.FGroup := nil;
b.FHasVBands := False;
if b is TfrxDataBand then
if (TfrxDataBand(b).DataSet = nil) and (TfrxDataBand(b).RowCount > 0) then
begin
TfrxDataBand(b).DataSet := TfrxDataBand(b).VirtualDataSet;
TfrxDataBand(b).DataSet.Initialize;
end;
{ connect objects to vertical bands }
if (not PrepareVBands) and not (b is TfrxOverlay) then
for j := 0 to FPage.Objects.Count - 1 do
begin
t := FPage.Objects[j];
if (t is TfrxBand) and TfrxBand(t).Vertical then
begin
k := 0;
while k < b.Objects.Count do
begin
c := b.Objects[k];
if (c.Left >= t.Left - 1e-4) and
(c.Left + c.Width <= t.Left + t.Width + 1e-4) then
begin
b.FHasVBands := True;
c.Parent := t;
THackComponent(c).FOriginalBand := b;
c.Left := c.Left - t.Left;
end
else
Inc(k);
end;
end;
end;
end;
end;
{ sort bands by position }
for i := 0 to FPage.Objects.Count - 1 do
begin
t := FPage.Objects[i];
if t is TfrxBand then
begin
b := TfrxBand(t);
if b.Vertical <> PrepareVBands then
continue;
if b.BandNumber in [4..13] then
if b.Vertical then
SortBands.AddObject(Format('%9.2f', [b.Left]), b)
else
SortBands.AddObject(Format('%9.2f', [b.Top]), b);
end;
end;
{ copy sorted items to TList - it's easier to work with it }
Bands := TList.Create;
for i := 0 to SortBands.Count - 1 do
begin
t := TfrxComponent(SortBands.Objects[i]);
Bands.Add(t);
end;
SortBands.Free;
ConnectGroups;
ConnectHeaders;
MakeTree(FPage, 0);
ClearNils;
for i := 0 to Bands.Count - 1 do
begin
t := Bands[i];
ErrorList.Add(frxResources.Get('enBandPos') + ' ' + t.Name);
end;
Bands.Free;
end;
procedure TfrxEngine.PrepareShiftTree(Band: TfrxBand);
var
i, j, k: Integer;
c0, c1, c2, top: TfrxReportComponent;
allObjects: TStringList;
diff: Extended;
Found: Boolean;
begin
if Band.FShiftChildren.Count <> 0 then
Exit;
allObjects := TStringList.Create;
allObjects.Duplicates := dupAccept;
{ temporary top object }
top := TfrxMemoView.Create(nil);
top.SetBounds(0, -2, Band.Width, 1);
{ sort objects }
for i := 0 to Band.Objects.Count - 1 do
begin
c0 := Band.Objects[i];
allObjects.AddObject(Format('%9.2f', [c0.Top]), c0);
c0.FShiftChildren.Clear;
end;
allObjects.Sort;
allObjects.InsertObject(0, Format('%10.2f', [top.Top]), top);
for i := 0 to allObjects.Count - 1 do
begin
c0 := TfrxReportComponent(allObjects.Objects[i]);
{ find an object under c0 }
for j := i + 1 to allObjects.Count - 1 do
begin
c1 := TfrxReportComponent(allObjects.Objects[j]);
diff := c1.Top - (c0.Top + c0.Height);
if (diff > -1e-4) and (c0.Left < c1.Left + c1.Width - 1e-4) and
(c1.Left < c0.Left + c0.Width - 1e-4) then
begin
Found := False;
{ check if there is no other objects between c1 and c0 }
for k := j - 1 downto i + 1 do
begin
c2 := TfrxReportComponent(allObjects.Objects[k]);
if (c2.Top + c2.Height < c1.Top + 1e-4) and
(c2.Top > c0.Top + c0.Height - 1e-4) and
(c2.Left < c1.Left + c1.Width - 1e-4) and
(c1.Left < c2.Left + c2.Width - 1e-4) then
begin
Found := True;
break;
end;
end;
if not Found then
c0.FShiftChildren.Add(c1);
end;
end;
end;
{ copy children from the top object to the band }
for i := 0 to top.FShiftChildren.Count - 1 do
Band.FShiftChildren.Add(top.FShiftChildren[i]);
allObjects.Free;
top.Free;
end;
function TfrxEngine.CanShow(Obj: TObject; PrintIfDetailEmpty: Boolean): Boolean;
var
i: Integer;
Bands: TList;
b: TfrxDataBand;
res: Boolean;
begin
if Obj is TfrxReportPage then
Bands := TfrxReportPage(Obj).FSubBands else
Bands := TfrxBand(Obj).FSubBands;
Result := True;
{ Check all subdetail bands to ensure they all have records }
if not PrintIfDetailEmpty then
begin
Result := False;
if (Bands.Count = 0) and not (Obj is TfrxPage) then
Result := True;
for i := 0 to Bands.Count - 1 do
begin
b := Bands[i];
if b.DataSet <> nil then
begin
Report.DoNotifyEvent(b, b.OnMasterDetail);
b.DataSet.First;
while not b.DataSet.Eof do
begin
res := CanShow(b, b.PrintIfDetailEmpty);
if res then
begin
Result := True;
break;
end
else
b.DataSet.Next;
end;
end;
end;
end;
end;
procedure TfrxEngine.ResetSuppressValues(Band: TfrxBand);
var
i: Integer;
begin
for i := 0 to Band.Objects.Count - 1 do
if TObject(Band.Objects[i]) is TfrxCustomMemoView then
THackMemoView(Band.Objects[i]).FLastValue := Null;
end;
procedure TfrxEngine.InitGroups(Band: TfrxBand; Index: Integer; ResetLineN: Boolean = False);
var
i: Integer;
b: TfrxGroupHeader;
begin
for i := Index to Band.FSubBands.Count - 1 do
begin
b := Band.FSubBands[i];
if ResetLineN then
begin
b.FLineN := 1;
b.FLineThrough := 1;
ResetSuppressValues(b);
end
else
begin
Inc(b.FLineN);
if i < Band.FSubBands.Count - 1 then
TfrxBand(Band.FSubBands[i + 1]).FLineN := 0;
Inc(b.FLineThrough);
end;
CurLine := b.FLineN;
CurLineThrough := b.FLineThrough;
Report.CurObject := b.Name;
b.FLastValue := Report.Calc(b.Condition);
if b.KeepTogether then
StartKeep(b);
ShowBand(b);
AddBandOutline(b);
if b.Vertical then
AddToVHeaderList(b)
else
AddToHeaderList(b);
end;
end;
procedure TfrxEngine.ShowGroupFooters(Band: TfrxGroupHeader; Index: Integer;
Master: TfrxDataBand);
var
i: Integer;
b: TfrxGroupHeader;
begin
for i := Band.FSubBands.Count - 1 downto Index do
begin
b := Band.FSubBands[i];
if b.FFooter <> nil then
if not TfrxGroupFooter(b.FFooter).HideIfSingleDataRecord or (Master.FLineN > 2) then
ShowBand(b.FFooter)
else
FAggregates.Reset(b.FFooter);
OutlineUp(b);
if b.Vertical then
RemoveFromVHeaderList(b)
else
RemoveFromHeaderList(b);
if b.KeepTogether then
EndKeep(b);
end;
end;
procedure TfrxEngine.CheckGroups(Master: TfrxDataBand; Band: TfrxGroupHeader;
ColumnKeepPos: Integer; SaveCurY: Extended);
var
i: Integer;
b: TfrxGroupHeader;
NextNeeded: Boolean;
begin
for i := 0 to Band.FSubBands.Count - 1 do
begin
b := Band.FSubBands[i];
Report.CurObject := b.Name;
if Report.Calc(b.Condition) <> b.FLastValue then
begin
Master.CurColumn := Master.Columns;
CheckBandColumns(Master, ColumnKeepPos, SaveCurY);
{ avoid exception in uni-directional datasets }
NextNeeded := True;
try
Master.DataSet.Prior;
except
NextNeeded := False;
end;
ShowGroupFooters(Band, i, Master);
if NextNeeded then
Master.DataSet.Next;
InitGroups(Band, i);
Master.FLineN := 1;
ResetSuppressValues(Master);
break;
end;
end;
end;
procedure TfrxEngine.CheckBandColumns(Band: TfrxDataBand; ColumnKeepPos: Integer;
SaveCurY: Extended);
begin
if Band.Columns > 1 then
begin
{ collect max position in b.FMaxY }
if CurY > Band.FMaxY then
Band.FMaxY := CurY;
{ all columns have been printed }
if Band.CurColumn >= Band.Columns then
begin
{ need page break }
if Band.FMaxY > PageHeight - FooterHeight then
begin
if FKeeping then { standard keep procedure }
NewColumn
else
begin
PreviewPages.CutObjects(ColumnKeepPos);
NewColumn;
PreviewPages.PasteObjects(CurX, CurY);
CurY := CurY + Band.FMaxY - SaveCurY;
end;
end
else
CurY := Band.FMaxY; { start the new band from saved b.FMaxY }
end
else
CurY := SaveCurY; { start the new band from saved SaveCurY }
if Band.Visible then
Band.CurColumn := Band.CurColumn + 1;
end;
end;
procedure TfrxEngine.NotifyObjects(Band: TfrxBand);
var
i: Integer;
c: TfrxComponent;
begin
for i := 0 to NotifyList.Count - 1 do
begin
c := NotifyList[i];
if c <> nil then
c.OnNotify(Band);
end;
end;
procedure TfrxEngine.RunPage(Page: TfrxReportPage);
{ "Null" band contains all free-placed objects that don't have a parent band }
procedure ShowNullBand;
var
i: Integer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -