123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- unit ExportExcel;
- interface
- uses
- Classes, ZjGrid, ScXlsOutput, ScXlsCustomUD, Windows, StdCtrls,
- sdIDTree, sdDB, Graphics, SysUtils, ProgressHintFrm, Forms, Controls;
- type
- TExcelExportor = class
- private
- FXlsOutPut: TXlsOutPut;
- FGrid: TZJGrid;
- FTempFile: string;
- FFileName: string;
- procedure InitialPage(AGrid: TZJGrid; AXlsPage: TXlsCustomPage);
- protected
- procedure BeforeExport;
- procedure EndExport;
- public
- constructor Create;
- destructor Destroy; override;
- procedure ExportToXlsPage(AGrid: TZJGrid; AXlsPage: TXlsCustomPage);
- procedure ExportToFile(AGrid: TZJGrid; const AFileName: string);
- end;
- PColInfo = ^TColInfo;
- TColInfo = record
- // 字段名
- FieldName: string;
- // 查询字段名,应用于联合几个数据库的情况,参照dataset的Lookup方式
- KeyField: string;
- LookupKeyField: string;
- // 查询数据库ID
- LookupDataSetIndex: Integer;
- // 列名
- TitleCaption: string;
- // 列宽
- Width: Integer;
- // 对齐方式
- HorTextAlign: TUDHTextAlign;
- //VerTextAlign: TUDVTextAlign;
- end;
- PColInfos = ^TColInfos;
- TColInfos = array [0..30] of TColInfo;
- // 仿照DataSet的Lookup以及数据库的AutoUpdate已达到关于sdIDTree导出数据至Excel的普适性
- // 导出前须根据所需列信息,以及查询数据库(列信息须与查询数据库对等,否则将会报错,并不检查列与数据库是否匹配)
- TIDTreeExcelExportor = class
- private
- FXlsOutPut: TXlsOutPut;
- FDataSetList: TList;
- FColInfos: PColInfos;
- FColCount: Integer;
- FHasLevelCode: Boolean;
- FTree: TsdIDTree;
- FTempFile: string;
- // 当清单数超过3w3k行时,使用Variant会内存溢出
- function GetCellValue(ANode: TsdIDTreeNode; ColInfo: TColInfo): Variant;
- // 故换成直接使用String
- function GetCellStr(ANode: TsdIDTreeNode; ColInfo: TColInfo): string;
- procedure ExportNodeData(ANode: TsdIDTreeNode; AXlsPage: TXlsCustomPage; const ALevelCode: string);
- procedure ExportTreeNode(ANode: TsdIDTreeNode; AXlsPage: TXlsCustomPage; const ALevelCode: string);
- procedure DefineHeader(AXlsPage: TXlsCustomPage);
- protected
- procedure BeforeExport;
- procedure EndExport;
- public
- constructor Create;
- destructor Destroy; override;
- procedure AddLookupDataSet(ADataSet: TsdDataSet);
- procedure DefineCol(AColInfos: PColInfos; AColCount: Integer);
- procedure ExportToXlsPage(ATree: TsdIDTree; AXlsPage: TXlsCustomPage);
- procedure ExportToFile(ATree: TsdIDTree; const AFileName: string);
- property HasLevelCode: Boolean read FHasLevelCode write FHasLevelCode;
- end;
- const
- ciLedger: array [0..8] of TColInfo =(
- (FieldName: 'Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '项目节编号'; Width: 120; HorTextAlign: htaLeft),
- (FieldName: 'B_Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单编号'; Width: 80; HorTextAlign: htaLeft),
- (FieldName: 'Name'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '名称'; Width: 200; HorTextAlign: htaLeft),
- (FieldName: 'Units'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单位'; Width: 40; HorTextAlign: htaCenter),
- (FieldName: 'Price'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单价'; Width: 60; HorTextAlign: htaRight),
- (FieldName: 'OrgQuantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '数量'; Width: 80; HorTextAlign: htaRight),
- (FieldName: 'OrgTotalPrice'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '金额'; Width: 80; HorTextAlign: htaRight),
- (FieldName: 'DrawingCode'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '图号'; Width: 100; HorTextAlign: htaLeft),
- (FieldName: 'MemoStr'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '备注'; Width: 80; HorTextAlign: htaLeft)
- );
- ciFxBills: array [0..10] of TColInfo =(
- (FieldName: 'Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '预算项目节'; Width: 120; HorTextAlign: htaLeft),
- (FieldName: 'B_Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单子目号'; Width: 80; HorTextAlign: htaLeft),
- (FieldName: 'Name'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '名称'; Width: 200; HorTextAlign: htaLeft),
- (FieldName: 'Units'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单位'; Width: 40; HorTextAlign: htaCenter),
- (FieldName: 'OrgQuantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单数量'; Width: 80; HorTextAlign: htaRight),
- (FieldName: 'DgnQuantity1'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '设计数量1'; Width: 80; HorTextAlign: htaRight),
- (FieldName: 'DgnQuantity2'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '设计数量2'; Width: 80; HorTextAlign: htaRight),
- (FieldName: 'Price'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单价'; Width: 60; HorTextAlign: htaRight),
- (FieldName: 'OrgTotalPrice'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '合价'; Width: 80; HorTextAlign: htaRight),
- (FieldName: 'DrawingCode'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '图号'; Width: 100; HorTextAlign: htaLeft),
- (FieldName: 'MemoStr'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '备注'; Width: 80; HorTextAlign: htaLeft)
- );
- implementation
- uses
- ZhAPI, Variants, UtilMethods;
- { TExcelExportor }
- procedure TExcelExportor.BeforeExport;
- begin
- Screen.Cursor := crHourGlass;
- ShowProgressHint('导出Excel表格数据', FGrid.RowCount);
- end;
- constructor TExcelExportor.Create;
- begin
- FXlsOutPut := TXlsOutPut.Create;
- FTempFile := GetTempFileName;
- end;
- destructor TExcelExportor.Destroy;
- begin
- if FileExists(FTempFile) then
- DeleteFileOrFolder(FTempFile);
- FXlsOutPut.Free;
- inherited;
- end;
- procedure TExcelExportor.EndExport;
- begin
- CloseProgressHint;
- Screen.Cursor := crDefault;
- end;
- procedure TExcelExportor.ExportToFile(AGrid: TZJGrid;
- const AFileName: string);
- begin
- FFileName := AFileName;
- FGrid := AGrid;
- BeforeExport;
- try
- ExportToXlsPage(AGrid, FXlsOutPut.AddPage);
- FXlsOutPut.SaveToFile(FTempFile);
- if not FileExists(FFileName) or QuestMessage('存在同名文件,是否替换?') then
- CopyFile(PChar(FTempFile), PChar(FFileName), False);
- finally
- EndExport;
- end;
- end;
- procedure TExcelExportor.ExportToXlsPage(AGrid: TZJGrid;
- AXlsPage: TXlsCustomPage);
- procedure SetXlsCellTextAlign(AXlsCell: TXlsCustomCell; AGridCell: TzjCell);
- begin
- case AGridCell.TextAlign of
- gaTopLeft:
- begin
- AXlsCell.VTextAlign := vtaTop;
- AXlsCell.HTextAlign := htaLeft;
- end;
- gaTopCenter:
- begin
- AXlsCell.VTextAlign := vtaTop;
- AXlsCell.HTextAlign := htaCenter;
- end;
- gaTopRight:
- begin
- AXlsCell.VTextAlign := vtaTop;
- AXlsCell.HTextAlign := htaRight;
- end;
- gaCenterLeft:
- begin
- AXlsCell.VTextAlign := vtaCenter;
- AXlsCell.HTextAlign := htaLeft;
- end;
- gaCenterCenter:
- begin
- AXlsCell.VTextAlign := vtaCenter;
- AXlsCell.HTextAlign := htaCenter;
- end;
- gaCenterRight:
- begin
- AXlsCell.VTextAlign := vtaCenter;
- AXlsCell.HTextAlign := htaRight;
- end;
- gaBottomLeft:
- begin
- AXlsCell.VTextAlign := vtaBottom;
- AXlsCell.HTextAlign := htaLeft;
- end;
- gaBottomCenter:
- begin
- AXlsCell.VTextAlign := vtaBottom;
- AXlsCell.HTextAlign := htaCenter;
- end;
- gaBottomRight:
- begin
- AXlsCell.VTextAlign := vtaBottom;
- AXlsCell.HTextAlign := htaRight;
- end;
- end;
- if goWarpText in AGridCell.Grid.Options then
- AXlsCell.WartText := True;
- end;
- procedure ExportGridCell(AGridCell: TzjCell);
- var
- XlsCell: TXlsCustomCell;
- begin
- if AGridCell = nil then Exit;
- XlsCell := AXlsPage.AddCell(AGridCell.Col, AGridCell.Row, AGridCell.Text);
- SetXlsCellTextAlign(XlsCell, AGridCell);
- XlsCell.Font.Name := AGridCell.Font.Name;
- XlsCell.Font.Size := AGridCell.Font.Size;
- XlsCell.Width := AGridCell.Width;
- XlsCell.Height := AGridCell.Height;
- end;
- var
- iColumn, iRow: Integer;
- begin
- InitialPage(AGrid, AXlsPage);
- for iRow := 0 to AGrid.RowCount - 1 do
- begin
- UpdateProgressHint(Format('导出第%d行数据', [iRow + 1]));
- UpdateProgressHint(1);
- for iColumn := 0 to AGrid.ColCount - 1 do
- ExportGridCell(AGrid.Cells[iColumn, iRow]);
- end;
- end;
- procedure TExcelExportor.InitialPage(AGrid: TZJGrid;
- AXlsPage: TXlsCustomPage);
- procedure InitialColumnWidth;
- var
- iColumn: Integer;
- begin
- for iColumn := 0 to AGrid.ColCount - 1 do
- AXlsPage.Widths[iColumn] := AGrid.ColWidths[iColumn];
- end;
- procedure InitialRowHeight;
- var
- iRow: Integer;
- begin
- for iRow := 0 to AGrid.RowCount - 1 do
- AXlsPage.Heights.Items[iRow] := AGrid.RowHeights[iRow];
- end;
- begin
- InitialColumnWidth;
- InitialRowHeight;
- end;
- { TIDTreeExcelExportor }
- constructor TIDTreeExcelExportor.Create;
- begin
- FXlsOutPut := TXlsOutPut.Create;
- FDataSetList := TList.Create;
- FTempFile := GetTempFileName;
- end;
- destructor TIDTreeExcelExportor.Destroy;
- begin
- if FileExists(FTempFile) then
- DeleteFileOrFolder(FTempFile);
- FDataSetList.Free;
- FXlsOutPut.Free;
- inherited;
- end;
- procedure TIDTreeExcelExportor.ExportToFile(ATree: TsdIDTree;
- const AFileName: string);
- begin
- FTree := ATree;
- BeforeExport;
- try
- ExportToXlsPage(ATree, FXlsOutPut.AddPage);
- UpdateProgressHint('保存0号台账Excel数据');
- FXlsOutPut.SaveToFile(FTempFile);
- if not FileExists(AFileName) or QuestMessage('存在同名文件,是否替换?') then
- CopyFile(PChar(FTempFile), PChar(AFileName), False);
- finally
- EndExport;
- end;
- end;
- procedure TIDTreeExcelExportor.ExportTreeNode(ANode: TsdIDTreeNode;
- AXlsPage: TXlsCustomPage; const ALevelCode: string);
- function GetFirstChildLevelCode(const ACode: string): string;
- begin
- Result := ACode + '.1';
- end;
- function GetNextSiblingLevelCode(const ACode: string): string;
- var
- strPreCode, strLastCode: string;
- iNextCode: Integer;
- begin
- if Pos('.', ACode) = 0 then
- Result := IntToStr(StrToIntDef(ACode, 1) + 1)
- else
- begin
- strPreCode := GetPrefixOfCode(ACode, '.');
- strLastCode := GetLastSetmentOfCode(ACode, '.');
- iNextCode := StrToIntDef(strLastCode, 1) + 1;
- Result := strPreCode + '.' + IntToStr(iNextCode);
- end;
- end;
- var
- sHint: string;
- begin
- if not Assigned(ANode) then Exit;
- if ANode.Rec.ValueByName('Code').AsString <> '' then
- sHint := '正在导出清单 ' + ANode.Rec.ValueByName('Code').AsString
- else if ANode.Rec.ValueByName('B_Code').AsString <> '' then
- sHint := '正在导出清单 ' + ANode.Rec.ValueByName('B_Code').AsString
- else
- sHint := '正在导出清单 ' + ANode.Rec.ValueByName('Name').AsString;
- UpdateProgressHint(sHint);
- UpdateProgressHint(1);
- ExportNodeData(ANode, AXlsPage, ALevelCode);
- ExportTreeNode(ANode.FirstChild, AXlsPage, GetFirstChildLevelCode(ALevelCode));
- ExportTreeNode(ANode.NextSibling, AXlsPage, GetNextSiblingLevelCode(ALevelCode));
- end;
- procedure TIDTreeExcelExportor.ExportNodeData(ANode: TsdIDTreeNode;
- AXlsPage: TXlsCustomPage; const ALevelCode: string);
- function ExportCell(ACol, ARow: Integer; AValue: Variant): TXlsCustomCell;
- begin
- Result := nil;
- // -----------
- if VarIsNull(AValue) then Exit;
- // -----------
- // 当数据超过3w3k行时,运行至某行时,AddCell会内存溢出
- // 可能是Cell的数目超过某个限度时,报错
- // 如果AValue为Null时不AddCell,则3w3k行可以安全度过
- case VarType(AValue) of
- varSmallInt, varInteger, varSingle, varDouble,
- varCurrency, varShortInt, varByte, varWord,
- varLongWord, varInt64:
- begin
- if AValue <> 0 then
- Result := AXlsPage.AddCell(ACol, ARow, AValue);
- end
- else Result := AXlsPage.AddCell(ACol, ARow, AValue);
- end;
- end;
- var
- iCol: Integer;
- ColInfo: TColInfo;
- XlsCell: TXlsCustomCell;
- sStr: string;
- begin
- if not Assigned(ANode) then Exit;
- for iCol := 0 to FColCount - 1 do
- begin
- ColInfo := FColInfos[iCol];
- XlsCell := ExportCell(iCol, ANode.MajorIndex + 1, GetCellValue(ANode, ColInfo));
- {sStr := GetCellStr(ANode, ColInfo);
- if sStr = '' then Continue;
- XlsCell := AXlsPage.AddCell(iCol, ANode.MajorIndex + 1, sStr);}
- if Assigned(XlsCell) then
- begin
- XlsCell.HTextAlign := ColInfo.HorTextAlign;
- //XlsCell.VTextAlign := ColInfo.VerTextAlign;
- XlsCell.Font.Name := 'SmartSimSun';
- XlsCell.Font.Size := 9;
- end;
- end;
- if HasLevelCode then
- begin
- XlsCell := ExportCell(FColCount, ANode.MajorIndex + 1, ALevelCode);
- XlsCell.Font.Name := 'SmartSimSun';
- XlsCell.Font.Size := 9;
- end;
- end;
- procedure TIDTreeExcelExportor.ExportToXlsPage(ATree: TsdIDTree;
- AXlsPage: TXlsCustomPage);
- begin
- DefineHeader(AXlsPage);
- ExportTreeNode(ATree.FirstNode, AXlsPage, '1');
- end;
- function TIDTreeExcelExportor.GetCellValue(ANode: TsdIDTreeNode;
- ColInfo: TColInfo): Variant;
- function GetRec: TsdDataRecord;
- var
- DataSet: TsdDataSet;
- begin
- Result := nil;
- DataSet := TsdDataSet(FDataSetList.Items[ColInfo.LookupDataSetIndex]);
- if not Assigned(DataSet) then Exit;
- Result := DataSet.Locate(ColInfo.LookupKeyField, ANode.Rec.ValueByName(ColInfo.KeyField).Value);
- end;
- var
- ARec: TsdDataRecord;
- begin
- Result := '';
- if not Assigned(ANode) then Exit;
- if ColInfo.LookupDataSetIndex = -1 then
- ARec := ANode.Rec
- else
- ARec := GetRec;
- if Assigned(ARec) then
- Result := ARec.ValueByName(ColInfo.FieldName).Value;
- end;
- procedure TIDTreeExcelExportor.DefineHeader(AXlsPage: TXlsCustomPage);
- var
- iCol: Integer;
- ColInfo: TColInfo;
- XlsCell: TXlsCustomCell;
- begin
- for iCol := 0 to FColCount - 1 do
- begin
- ColInfo := FColInfos[iCol];
- XlsCell := AXlsPage.AddCell(iCol, 0, ColInfo.TitleCaption);
- XlsCell.HTextAlign := htaCenter;
- XlsCell.Font.Name := '黑体';
- XlsCell.Font.Size := 10;
- XlsCell.Font.Style := [fsBold];
- AXlsPage.Widths[iCol] := ColInfo.Width;
- end;
- if HasLevelCode then
- begin
- XlsCell := AXlsPage.AddCell(iCol, 0, '层次编号');
- XlsCell.HTextAlign := htaCenter;
- XlsCell.Font.Name := '黑体';
- XlsCell.Font.Size := 10;
- XlsCell.Font.Style := [fsBold];
- end;
- end;
- procedure TIDTreeExcelExportor.AddLookupDataSet(ADataSet: TsdDataSet);
- begin
- FDataSetList.Add(ADataSet);
- end;
- procedure TIDTreeExcelExportor.DefineCol(AColInfos: PColInfos;
- AColCount: Integer);
- begin
- FColInfos := AColInfos;
- FColCount := AColCount;
- end;
- procedure TIDTreeExcelExportor.BeforeExport;
- begin
- Screen.Cursor := crHourGlass;
- ShowProgressHint('导出0号台账Excel数据', FTree.Count);
- end;
- procedure TIDTreeExcelExportor.EndExport;
- begin
- CloseProgressHint;
- Screen.Cursor := crDefault;
- end;
- function TIDTreeExcelExportor.GetCellStr(ANode: TsdIDTreeNode;
- ColInfo: TColInfo): string;
- function GetRec: TsdDataRecord;
- var
- DataSet: TsdDataSet;
- begin
- Result := nil;
- DataSet := TsdDataSet(FDataSetList.Items[ColInfo.LookupDataSetIndex]);
- if not Assigned(DataSet) then Exit;
- Result := DataSet.Locate(ColInfo.LookupKeyField, ANode.Rec.ValueByName(ColInfo.KeyField).Value);
- end;
- var
- ARec: TsdDataRecord;
- begin
- Result := '';
- if not Assigned(ANode) then Exit;
- if ColInfo.LookupDataSetIndex = -1 then
- ARec := ANode.Rec
- else
- ARec := GetRec;
- if Assigned(ARec) then
- Result := ARec.ValueByName(ColInfo.FieldName).AsString;
- if SameText(Result, '0') then
- Result := '';
- end;
- end.
|