📄 fr_cross1.pas
字号:
f: TfrTField;
v: Variant;
d: Double;
begin
Result := '';
for i := 0 to sl.Count - 1 do
begin
s := PureName(sl[i]);
f := TfrTField(FDataSet.FindField(CurReport.Dictionary.RealFieldName[s]));
v := f.Value;
if (TVarData(v).VType = varOleStr) or (TVarData(v).VType = varString) then
Result := Result + f.AsString + ';'
else
begin
if v = Null then
d := 0
else
begin
d := v;
if sl = FRowFields then
FRowTypes[i] := v
else if sl = FColFields then
FColTypes[i] := v;
end;
s := Format('%2.6f', [d]);
n := 32 - Length(s);
for j := 1 to n do
s := ' ' + s;
Result := Result + s + ';';
end;
end;
if Result <> '' then
Result := Copy(Result, 1, Length(Result) - 1);
end;
procedure FormGroup(NewGroup, OldGroup: String; Direction: Boolean);
var
i, j: Integer;
sl1, sl2: TStringList;
procedure FormGroup1(Index: Integer);
var
i: Integer;
s: String;
begin
s := '';
for i := 0 to Index - 1 do
s := s + sl1[i] + ';';
s := s + sl1[Index] + '+;+';
if Direction then
begin
if HasTotal(FColFields[Index]) then
Cell[Rows[0], s, 0] := 0
end
else
if HasTotal(FRowFields[Index]) then
Cell[s, Columns[0], 0] := 0;
end;
begin
sl1 := TStringList.Create;
sl2 := TStringList.Create;
frSetCommaText(OldGroup, sl1);
frSetCommaText(NewGroup, sl2);
for i := 0 to sl1.Count - 1 do
if (NewGroup = '') or (sl1[i] <> sl2[i]) then
begin
for j := sl1.Count - 1 downto i do
FormGroup1(j);
break;
end;
sl1.Free;
sl2.Free;
end;
procedure MakeTotals(sl: TStringList; Direction: Boolean);
var
i: Integer;
s, Old: String;
begin
Old := sl[0];
i := 0;
while i < sl.Count do
begin
s := sl[i];
if (s <> Old) and (Pos('+', s) = 0) then
begin
FormGroup(s, Old, Direction);
Old := s;
end;
Inc(i);
end;
FormGroup('', sl[sl.Count - 1], Direction);
end;
procedure CalcTotals(FieldsSl, RowsSl, ColumnsSl: TStringList);
var
i, j, k, i1: Integer;
l: TList;
cg: TfrCrossGroupItem;
begin
l := TList.Create;
l.Add(TfrCrossGroupItem.Create(Self, '', FieldsSl.Count, FCellItemsCount)); // grand total
for i := 0 to FieldsSl.Count - 1 do
l.Add(TfrCrossGroupItem.Create(Self, ColumnsSl[0], i, FCellItemsCount));
for i := 0 to RowsSl.Count - 1 do
begin
for k := 0 to FieldsSl.Count do
TfrCrossGroupItem(l[k]).Reset(ColumnsSl[0], 0);
for j := 0 to ColumnsSl.Count - 1 do
begin
for k := 0 to FieldsSl.Count do
begin
cg := TfrCrossGroupItem(l[k]);
if cg.IsBreak(ColumnsSl[j]) or
((k = 0) and (j = ColumnsSl.Count - 1)) then
begin
if (k = 0) or HasTotal(FieldsSl[k - 1]) then
begin
cg.CheckAvg;
if RowsSl = Rows then
begin
CellArray[i, j] := cg.Value;
Cell[Rows[0], Columns[j], -1] := cg.FStartFrom;
end
else
begin
CellArray[j, i] := cg.Value;
Cell[Rows[j], Columns[0], -1] := cg.FStartFrom;
end;
end;
i1 := j;
while i1 < ColumnsSl.Count do
begin
if Pos('+;+', ColumnsSl[i1]) = 0 then
break;
Inc(i1);
end;
if i1 < ColumnsSl.Count then
cg.Reset(ColumnsSl[i1], j);
break;
end
else if Pos('+;+', ColumnsSl[j]) = 0 then
if RowsSl = Rows then
cg.AddValue(CellArray[i, j]) else
cg.AddValue(CellArray[j, i]);
end;
end;
end;
for i := 0 to FieldsSl.Count do
TfrCrossGroupItem(l[i]).Free;
l.Free;
end;
procedure CheckAvg;
var
i, j: Integer;
v, n: Variant;
Check: Boolean;
procedure CalcAvg(i1, j1: Integer);
var
i, j, k: Integer;
v1: Variant;
begin
for i := 0 to FCellFields.Count - 1 do
begin
v[i] := 0;
n[i] := 0;
end;
for i := CellByIndex[i1, 0, -1] to i1 - 1 do
for j := CellByIndex[0, j1, -1] to j1 - 1 do
if (not IsTotalRow[i]) and (not IsTotalColumn[j]) then
for k := 0 to FCellFields.Count - 1 do
if FuncName(FCellFields[k]) = 'avg' then
begin
v1 := CellByIndex[i, j, k];
if v1 <> Null then
begin
n[k] := n[k] + 1;
v[k] := v[k] + v1;
end;
end;
for i := 0 to FCellFields.Count - 1 do
if FuncName(FCellFields[i]) = 'avg' then
if n[i] <> 0 then
Cell[Rows[i1], Columns[j1], i] := v[i] / n[i] else
Cell[Rows[i1], Columns[j1], i] := Null;
end;
begin
v := VarArrayCreate([0, FCellFields.Count - 1], varVariant);
n := VarArrayCreate([0, FCellFields.Count - 1], varInteger);
Check := False;
for i := 0 to FCellFields.Count - 1 do
if FuncName(FCellFields[i]) = 'avg' then
begin
Check := True;
break;
end;
if Check then
for i := 0 to Rows.Count - 1 do
if IsTotalRow[i] or (i = Rows.Count - 1) then
for j := 0 to Columns.Count - 1 do
if IsTotalColumn[j] or (j = Columns.Count - 1) then
CalcAvg(i, j);
for i := 0 to Rows.Count - 1 do
Cell[Rows[i], Columns[0], -1] := Null;
for i := 0 to Columns.Count - 1 do
Cell[Rows[0], Columns[i], -1] := Null;
VarClear(v);
VarClear(n);
end;
procedure MakeColumnHeader;
var
i, j, n, cn: Integer;
s: String;
sl, sl1: TStringList;
Flag: Boolean;
d: Double;
v: Variant;
function CompareSl(Index: Integer): Boolean;
begin
Result := (sl.Count > Index) and (sl1.Count > Index) and (sl[Index] = sl1[Index]);
end;
begin
sl := TStringList.Create;
sl1 := TStringList.Create;
cn := CharCount(';', Columns[0]) + 1; // height of header
FTopLeftSize.cy := cn;
for i := 0 to cn do
Cell[Chr(i), Columns[0], 0] := '';
for i := 0 to Columns.Count - 1 do
Cell[#0, Columns[i], -1] := frftTop + frftBottom;
Cell[#0, Columns[0], 0] := FHeaderString;
Cell[#0, Columns[0], -1] := frftLeft + frftTop + frftBottom;
Cell[#0, Columns[Columns.Count - 1], -1] := frftTop + frftRight;
for i := 1 to cn do
Cell[Chr(i), Columns[Columns.Count - 1], -1] := frftLeft + frftRight;
Cell[#1, Columns[Columns.Count - 1], 0] := FColumnGrandTotalString;
Cell[#1, Columns[Columns.Count - 1], -1] := frftLeft + frftTop + frftRight;
for i := 0 to Columns.Count - 2 do
begin
s := Columns[i];
frSetCommaText(s, sl);
if Pos('+;+', s) <> 0 then
begin
n := CharCount(';', s);
for j := 1 to n - 1 do
Cell[Chr(j), s, -1] := frftTop;
for j := n to cn do
if j = n then
begin
Cell[Chr(j), s, 0] := FColumnTotalString;
Cell[Chr(j), s, -1] := frftRight + frftLeft + frftTop;
end
else
Cell[Chr(j), s, -1] := frftRight + frftLeft;
end
else
begin
Flag := False;
for j := 0 to cn - 1 do
if (not Flag) and CompareSl(j) then
Cell[Chr(j + 1), s, -1] := frftTop
else
begin
if TVarData(FColTypes[j]).VType = varDate then
begin
d := StrToFloat(Trim(sl[j]));
TVarData(FColTypes[j]).VDate := d;
v := FColTypes[j];
end
else if (TVarData(FColTypes[j]).VType = varString) or
(TVarData(FColTypes[j]).VType = varOleStr) or
(TVarData(FColTypes[j]).VType = varEmpty) or
(TVarData(FColTypes[j]).VType = varNull) then
v := Trim(sl[j])
else
begin
d := StrToFloat(Trim(sl[j]));
v := FloatToStr(d);
end;
Cell[Chr(j + 1), s, 0] := v;
Cell[Chr(j + 1), s, -1] := frftTop + frftLeft;
Flag := True;
end;
end;
sl1.Assign(sl);
end;
sl.Free;
sl1.Free;
end;
procedure MakeRowHeader;
var
i, j, n, cn: Integer;
s: String;
sl, sl1: TStringList;
Flag: Boolean;
d: Double;
v: Variant;
function CompareSl(Index: Integer): Boolean;
begin
Result := (sl.Count > Index) and (sl1.Count > Index) and (sl[Index] = sl1[Index]);
end;
procedure CellOr(Index1, Index2: String; Value: Integer);
var
v: Variant;
begin
v := Cell[Index1, Index2, -1];
if v = Null then
v := 0;
v := v or Value;
Cell[Index1, Index2, -1] := v;
end;
begin
sl := TStringList.Create;
sl1 := TStringList.Create;
cn := CharCount(';', Rows[FTopLeftSize.cy + 1]) + 1; // width of header
FTopLeftSize.cx := cn;
for i := 0 to cn - 1 do
Cell[Rows[0], Chr(i), 0] := '';
Cell[Rows[Rows.Count - 1], #0, 0] := FRowGrandTotalString;
Cell[Rows[Rows.Count - 1], #0, -1] := frftTop + frftBottom + frftLeft;
for i := 1 to cn - 1 do
Cell[Rows[Rows.Count - 1], Chr(i), -1] := frftTop + frftBottom;
for i := 0 to FTopLeftSize.cy do
for j := 0 to cn - 1 do
Cell[Chr(i), Chr(j), -1] := 0;
for i := FTopLeftSize.cy + 1 to Rows.Count - 2 do
begin
s := Rows[i];
frSetCommaText(s, sl);
if Pos('+;+', s) <> 0 then
begin
n := CharCount(';', s);
for j := 1 to n - 1 do
Cell[s, Chr(j - 1), -1] := frftLeft;
for j := n to cn do
if j = n then
begin
Cell[s, Chr(j - 1), 0] := FRowTotalString;
Cell[s, Chr(j - 1), -1] := frftLeft + frftTop;
end
else
Cell[s, Chr(j - 1), -1] := frftTop + frftBottom;
end
else
begin
Flag := False;
for j := 0 to cn - 1 do
if (not Flag) and CompareSl(j) then
Cell[s, Chr(j), -1] := frftLeft
else
begin
if TVarData(FRowTypes[j]).VType = varDate then
begin
d := StrToFloat(Trim(sl[j]));
TVarData(FRowTypes[j]).VDate := d;
v := FRowTypes[j];
end
else if (TVarData(FRowTypes[j]).VType = varString) or
(TVarData(FRowTypes[j]).VType = varOleStr) or
(TVarData(FRowTypes[j]).VType = varEmpty) or
(TVarData(FRowTypes[j]).VType = varNull) then
v := Trim(sl[j])
else
begin
d := StrToFloat(Trim(sl[j]));
v := FloatToStr(d);
end;
Cell[s, Chr(j), 0] := v;
Cell[s, Chr(j), -1] := frftTop + frftLeft;
Flag := True;
end;
end;
sl1.Assign(sl);
end;
sl.Free;
sl1.Free;
for i := cn to Columns.Count - 1 do
CellOr(Rows[Rows.Count - 1], Columns[i], 15);
for i := cn to Columns.Count - 1 do
CellOr(Rows[FTopLeftSize.cy], Columns[i], frftBottom);
for i := 0 to cn - 1 do
CellOr(Rows[Rows.Count - 2], Columns[i], frftBottom);
end;
begin
FDataSet.Open;
FDataSet.First;
while not FDataSet.EOF do
begin
for i := 0 to FCellFields.Count - 1 do
begin
f := TfrTField(FDataSet.FindField(CurReport.Dictionary.RealFieldName[PureName(FCellFields[i])]));
if FuncName(FCellFields[i]) = 'count' then
begin
v := 0;
if f.Value <> Null then
v := 1;
end
else
v := f.Value;
s1 := GetFieldValues(FRowFields);
s2 := GetFieldValues(FColFields);
if Cell[s1, s2, i] = Null then
Cell[s1, s2, i] := v else
Cell[s1, s2, i] := Cell[s1, s2, i] + v;
end;
FDataSet.Next;
end;
if Columns.Count = 0 then Exit;
MakeTotals(Columns, True);
Cell[Rows[0], Columns[Columns.Count - 1] + '+', 0] := 0;
MakeTotals(Rows, False);
Cell[Rows[Rows.Count - 1] + '+', Columns[0], 0] := 0;
CalcTotals(FColFields, Rows, Columns);
CalcTotals(FRowFields, Columns, Rows);
CheckAvg;
MakeColumnHeader;
MakeRowHeader;
end;
function TfrCross.GetIsTotalRow(Index: Integer): Boolean;
begin
Result := Pos('+;+', Rows[Index]) <> 0;
end;
function TfrCross.GetIsTotalColumn(Index: Integer): Boolean;
begin
Result := Pos('+;+', Columns[Index]) <> 0;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -