zoukankan      html  css  js  c++  java
  • Freeform Excel Worksheet (No OLE or EXCEL required)

     

    Question/Problem/Abstract:

    See also : Article_3475.asp 
    - (TDataSet to Excel) 

    This Class allows you to create an Excel Worksheet 
    in much the 
    same way 
    as you create a TStringGrid. ie. Cell[Column,Row]. 

    ------------------------------------------------------------------------- 
    Features 
    ------------------------------------------------------------------------- 

    Freeform cell access with DataType,FontIndex,FormatString, 
    Alignment,Pattern and BorderStyle. 
    NOTE : The col and row indexes are ZERO based 
    in the same way 
           
    as cells in a TStringGrid 

    4 Mapable system fonts (Preset to .) 
           Default   
    = Arial 10 regular         : FontIndex = 0 
           Alt_1     
    = Arial 10 bold            : FontIndex = 1 
           Alt_2     
    = Courier New 11 regular   : FontIndex = 2 
           Alt_3     
    = Courier New 11 bold      : FontIndex = 3 

    User definable cell formats 
    using Excel syntax (Defaults set to .) 
           String    
    = 'General' 
           Integer   
    = '0' 
           Double    
    = '###,###,##0.00' 
           DateTime  
    = 'dd-mmm-yyyy hh:mm:ss' 
           Date      
    = 'dd-mmm-yyyy' 
           Time      
    = 'hh:mm:ss' 

    Set individual Column Widths and Row Heights. 

    ------------------------------------------------------------------------- 
    Example Code Snippet 
    ------------------------------------------------------------------------- 

    uses MahWorksheet; 

    procedure ExcelDemo; 
    var i : integer; 
        oWorksheet : TExcelWorkSheet; 
        oCell : TExcelCell; 
    begin 
      oWorksheet :
    = TExcelWorkSheet.Create; 

      
    // Override mappable font 2 and 3 
      oWorksheet.SetFont_2('Times Roman',12, [fsBold,fsUnderline],XL_BLUE); 
      oWorksheet.SetFont_3(
    'Ms Serif'); // accept other defaults 

      
    // Set a column width 
      oWorksheet.ColumnWidth(3,50);   // Excel Col D 

      
    // Set a row height 
      oWorksheet.RowHeight(25,40);    // Excel Row 26 
      oWorksheet.RowHeight(26,30);    // Excel Row 27 

      
    // Set a cell via the procedural way 
      oWorksheet.SetCell(3,25,xlString,'Hello World',XL_FONT_2, 
                         
    'General',xalLeft,true,[xbTop,xbBottom]); 

      
    // Do the same thing via object oriented 
      oCell := oWorksheet.NewCell(3,16); 
      oCell.DataType :
    = xlDateTime; 
      oCell.Data :
    = Now; 

      
    // Change the data in cell 
      oCell := oWorksheet.GetCell(3,25); 
      oCell.Data :
    = 'Hello World with Borders'
      oCell.BorderStyle :
    = [xbLeft,xbRight,xbTop,xbBottom]; 
      oCell.Align :
    = xalCenter; 

      
    // Write out a column of integers 
      for i := 1000 to 1255 do begin 
        oCell :
    = oWorksheet.NewCell(6,i - 1000); 
        oCell.DataType :
    = xlInteger; 
        oCell.Data :
    = i; 
        oCell.FormatString :
    = '###,##0';  // overide default '0' 
        oCell.FontIndex := XL_FONT_1; 
      end; 

      
    // Blank out a cell 
      oWorksheet.BlankCell(6,20); 

      
    // Save our work 
      oWorksheet.SaveToFile('c:\temp\test'); 
      FreeAndNil(oWorksheet); 
    end;
    Answer:

    unit MahWorksheet; 
    interface 
    uses Windows, Classes, SysUtils, Math, Variants, Graphics; 

    // ========================================================================= 
    // Microsoft Excel Worksheet Class 
    // Excel 2.1 BIFF2 Specification 
    // 
    // Mike Heydon 2007 
    // 
    // --------------------------------------------------------------------- 
    // PUBLIC Methods 
    // --------------------------------------------------------------------- 
    // function GetCell(ACol,ARow : word) : TExcelCell; 
    // function NewCell(ACol,ARow :word) : TExcelCell; 
    // function GetFont_Default : TExcelFont; 
    // function GetFont_1 : TExcelFont; 
    // function GetFont_2 : TExcelFont; 
    // function GetFont_3 : TExcelFont; 
    // procedure SetFont_Default(const AFontName : string; 
    //                           AFontSize : byte = 10; 
    //                           AFontStyle : TFontStyles = []; 
    //                           AFontColor : word = 0); 
    // procedure SetFont_1(const AFontName : string; 
    //                     AFontSize : byte = 10; 
    //                     AFontStyle : TFontStyles = []; 
    //                     AFontColor : word = 0); 
    // procedure SetFont_2(const AFontName : string; 
    //                     AFontSize : byte = 10; 
    //                     AFontStyle : TFontStyles = []; 
    //                     AFontColor : word = 0); 
    // procedure SetFont_3(const AFontName : string; 
    //                     AFontSize : byte = 10; 
    //                     AFontStyle : TFontStyles = []; 
    //                     AFontColor : word = 0); 
    // procedure BlankCell(ACol,ARow : word); 
    // procedure SetCell(ACol,ARow : word; 
    //                   ADataType : TExcelDataType; 
    //                   AData : Olevariant; 
    //                   AFontIndex : byte = 0; 
    //                   AFormatString : string = 'General'; 
    //                   AAlign : TExcelCellAlign = xalGeneral; 
    //                   AHasPattern : boolean = false; 
    //                   ABorderStyle : TExcelBorders = []); 
    // procedure ColumnWidth(ACol : byte; AWidth : word); 
    // procedure RowHeight(ARow : word; AHeight : byte); 
    // procedure SaveToFile(const AFileName : string); 
    // 
    // ========================================================================= 


    const 
         
    // Font Types - 4 Mapable Fonts - TExcelCell.FontIndex 
         XL_FONT_DEFAULT = 0
         XL_FONT_1       
    = 1
         XL_FONT_2       
    = 2
         XL_FONT_3       
    = 3

         
    // Font Colors 
         XL_BLACK    : word = $0000
         XL_WHITE    : word 
    = $0001
         XL_RED      : word 
    = $0002
         XL_GREEN    : word 
    = $0003
         XL_BLUE     : word 
    = $0004
         XL_YELLOW   : word 
    = $0005
         XL_MAGENTA  : word 
    = $0006
         XL_CYAN     : word 
    = $0007
         XL_SYSTEM   : word 
    = $7FFF; 

    type 
         
    // Border Styles used by TExcelCell.BorderStyle 
         TExcelBorderType = (xbLeft,xbRight,xbTop,xbBottom); 
         TExcelBorders    
    = set of TExcelBorderType; 

         
    // Data types used by TExcelCell.DataType 
         TExcelDataType = (xlDouble,xlInteger,xlDate,xlTime, 
                           xlDateTime,xlString); 

         
    // Cell Alignment used by TExcelCell.Align 
         TExcelCellAlign = (xalGeneral,xalLeft,xalCenter,xalRight); 

         
    // Structure Returned by GetFont_?() 
         TExcelFont = record 
           FontName : 
    string
           FontSize : 
    byte
           FontStyle : TFontStyles; 
           FontColor : word; 
         end; 

         
    // Cell object of a TExcelWorkSheet 
         TExcelCell = class(TObject) 
         
    private 
           FRow,FCol : word; 
         
    public 
           DataType : TExcelDataType; 
           Data : Olevariant; 
           FontIndex : 
    byte
           FormatString : 
    string
           Align : TExcelCellAlign; 
           HasPattern : boolean; 
           BorderStyle : TExcelBorders; 
           constructor Create; 
         end; 

         
    // Main TExcelWorkSheet Class 
         TExcelWorkSheet = class(TObject) 
         
    private 
           FFile : file; 
           FMaxRow,FMaxCol : word; 
           FRowHeights,FFontTable, 
           FUsedRows,FFormats, 
           FColWidths,FCells : TStringList; 
           function _GetFont(AFontNum : 
    byte) : TExcelFont; 
           function _CalcSize(AIndex : integer) : word; 
           procedure _SetColIdx(AListIdx : integer; ARow : word; 
                               
    out AFirst : word; out ALast : word); 
           procedure _SaveFontTable; 
           procedure _SaveColWidths; 
           procedure _SaveFormats; 
           procedure _SaveDimensions; 
           procedure _SaveRowBlocks; 
           procedure _SaveCells(ARowFr,ARowTo : word); 
           procedure _WriteToken(AToken : word; ADataLen : word); 
           procedure _WriteFont(
    const AFontName : string; AFontHeight, 
                                AAttribute : word); 
           procedure _SetFont(AFontNum : 
    byteconst AFontName : string
                              AFontSize : 
    byte; AFontStyle : TFontStyles; 
                              AFontColor : word); 
         
    public 
           constructor Create; 
           destructor Destroy; 
    override
           function GetCell(ACol,ARow : word) : TExcelCell; 
           function NewCell(ACol,ARow :word) : TExcelCell; 
           function GetFont_Default : TExcelFont; 
           function GetFont_1 : TExcelFont; 
           function GetFont_2 : TExcelFont; 
           function GetFont_3 : TExcelFont; 
           procedure SetFont_Default(
    const AFontName : string
                                     AFontSize : 
    byte = 10
                                     AFontStyle : TFontStyles 
    = []; 
                                     AFontColor : word 
    = 0); 
           procedure SetFont_1(
    const AFontName : string
                               AFontSize : 
    byte = 10
                               AFontStyle : TFontStyles 
    = []; 
                               AFontColor : word 
    = 0); 
           procedure SetFont_2(
    const AFontName : string
                               AFontSize : 
    byte = 10
                               AFontStyle : TFontStyles 
    = []; 
                               AFontColor : word 
    = 0); 
           procedure SetFont_3(
    const AFontName : string
                               AFontSize : 
    byte = 10
                               AFontStyle : TFontStyles 
    = []; 
                               AFontColor : word 
    = 0); 
           procedure BlankCell(ACol,ARow : word); 
           procedure SetCell(ACol,ARow : word; 
                             ADataType : TExcelDataType; 
                             AData : Olevariant; 
                             AFontIndex : 
    byte = 0
                             AFormatString : 
    string = 'General'
                             AAlign : TExcelCellAlign 
    = xalGeneral; 
                             AHasPattern : boolean 
    = false
                             ABorderStyle : TExcelBorders 
    = []); 
           procedure ColumnWidth(ACol : 
    byte; AWidth : word); 
           procedure RowHeight(ARow : word; AHeight : 
    byte); 
           procedure SaveToFile(
    const AFileName : string); 
         end; 


    // ----------------------------------------------------------------------------- 
    implementation 

    const 
          
    // XL Tokens 
          XL_DIM       : word = $0000
          XL_BOF       : word 
    = $0009
          XL_EOF       : word 
    = $000A; 
          XL_ROW       : word 
    = $0008
          XL_DOCUMENT  : word 
    = $0010
          XL_FORMAT    : word 
    = $001E; 
          XL_COLWIDTH  : word 
    = $0024
          XL_FONT      : word 
    = $0031
          XL_FONTCOLOR : word 
    = $0045

          
    // XL Cell Types 
          XL_INTEGER   = $02
          XL_DOUBLE    
    = $03
          XL_STRING    
    = $04


    type 
         
    // Used when writing in RowBlock mode 
         TRowRec = packed record 
           RowIdx,FirstCell,LastCell : word; 
           Height : word; 
           NotUsed : word; 
           Defs : 
    byte
           OSet : word; 
         end; 

    // ========================================================================= 
    // Free Form Excel Spreadsheet 
    // ========================================================================= 

    // ========================================================= 
    // Create a ne Excel Cell Object and initialise defaults 
    // ========================================================= 
    constructor TExcelCell.Create; 
    begin 
      inherited Create; 

      FRow :
    = 0
      FCol :
    = 0
      DataType :
    = xlString; 
      FontIndex :
    = 0
      FormatString :
    = 'General'
      Align :
    = xalGeneral; 
      HasPattern :
    = false
      BorderStyle :
    = []; 
    end; 

    // ============================================== 
    // Create and Destroy TExcelWorkSheet Class 
    // ============================================== 

    constructor TExcelWorkSheet.Create; 
    begin 
      inherited Create; 

      FColWidths :
    = TStringList.Create; 
      FRowHeights :
    = TStringList.Create; 
      FUsedRows :
    = TStringList.Create; 
      FUsedRows.Sorted :
    = true
      FUsedRows.Duplicates :
    = dupIgnore; 
      FFormats :
    = TStringList.Create; 
      FFormats.Sorted :
    = true
      FFormats.Duplicates :
    = dupIgnore; 
      FCells :
    = TStringList.Create; 
      FCells.Sorted :
    = true
      FCells.Duplicates :
    = dupIgnore; 
      FFontTable :
    = TStringList.Create; 
      FFontTable.AddObject(
    'Arial|10|0',nil); 
      FFontTable.AddObject(
    'Arial|10|1',nil); 
      FFontTable.AddObject(
    'Courier New|11|0',nil); 
      FFontTable.AddObject(
    'Courier New|11|1',nil); 
    end; 


    destructor TExcelWorkSheet.Destroy; 
    var i : integer; 
    begin 
      
    for i := 0 to FCells.Count - 1 do 
        TExcelCell(FCells.Objects[i]).Free; 
      FreeAndNil(FCells); 
      FreeAndNil(FColWidths); 
      FreeAndNil(FFormats); 
      FreeAndNil(FFontTable); 
      FreeAndNil(FUsedRows); 
      FreeAndNil(FRowHeights); 

      inherited Destroy; 
    end; 

    // ===================================================== 
    // INTERNAL - Write out a Token and Data length record 
    // ===================================================== 

    procedure TExcelWorkSheet._WriteToken(AToken : word; ADataLen : word); 
    var aWord : array [
    0..1] of word; 
    begin 
      aWord[
    0] := AToken; 
      aWord[
    1] := ADataLen; 
      Blockwrite(FFile,aWord,SizeOf(aWord)); 
    end; 


    // ======================================= 
    // INTERNAL - Write out a FONT record 
    // ======================================= 

    procedure TExcelWorksheet._WriteFont(
    const AFontName : string
                                         AFontHeight,AAttribute : word); 
    var iLen : 
    byte
    begin 
      AFontHeight :
    = AFontHeight * 20
      _WriteToken(XL_FONT,
    5 + length(AFontName)); 
      BlockWrite(FFile,AFontHeight,
    2); 
      BlockWrite(FFile,AAttribute,
    2); 
      iLen :
    = length(AFontName); 
      BlockWrite(FFile,iLen,
    1); 
      BlockWrite(FFile,AFontName[
    1],iLen); 
    end; 


    // ==================================================================== 
    // INTERNAL - Write out the Font Table 
    // Also create a table of used rows and rows that have height changed. 
    // Also set the Max Row and Col used for DIMENSION Record 
    // Also create the user defined format strings table 
    // ==================================================================== 

    procedure TExcelWorkSheet._SaveFontTable; 
    var i,iAttr,iSize, 
        iRow,iIdx : integer; 
        iColor : word; 
        sKey,sName : 
    string
        oCell : TexcelCell; 
    begin 
      FMaxRow :
    = 0
      FMaxCol :
    = 0
      FFormats.Clear; 
      FUsedRows.Clear; 

      
    // Add any new formats - Get Unique Rows Used 
      for i := 0 to FCells.Count - 1 do begin 
        oCell :
    = TExcelCell(FCells.Objects[i]); 
        
    if not SameText('General',oCell.FormatString) then 
          FFormats.Add(oCell.FormatString); 
        FUsedRows.Add(FormatFloat(
    '00000',oCell.FRow)); 
        FMaxRow :
    = Min(oCell.FRow,$FFFF); 
        FMaxCol :
    = Min(oCell.FCol,$FFFF); 
      end; 

      
    // Add any custom row heights 
      for i := 0 to FRowHeights.Count - 1 do begin 
        iRow :
    = StrToInt(FRowHeights[i]); 
        sKey :
    = FormatFloat('00000',iRow); 
        iSize :
    = word(FRowHeights.Objects[i]); 

        
    if FUsedRows.Find(sKey,iIdx) then 
          FUsedRows.Objects[iIdx] :
    = TObject(iSize) 
        
    else 
          FUsedRows.AddObject(sKey,TObject(iSize)); 
      end; 

      
    // Write Font Table 
      for i := 0 to FFontTable.Count - 1 do begin 
        sKey :
    = FFontTable[i]; 
        sName :
    = copy(sKey,1,pos('|',sKey) - 1); 
        sKey :
    = copy(sKey,pos('|',skey) + 1,2096); 
        iSize :
    = StrToInt(copy(sKey,1,pos('|',sKey) - 1)); 
        iAttr :
    = StrToInt(copy(sKey,pos('|',skey) + 1,2096)); 
        _WriteFont(sName,iSize,iAttr); 
        _WriteToken(XL_FONTCOLOR,
    2); 
        iColor :
    = word(FFontTable.Objects[i]); 
        Blockwrite(FFile,iColor,
    2); 
      end; 

    end; 


    // ======================================================== 
    // INTERNAL - Write out the default + user format strings 
    // ======================================================== 

    procedure TExcelWorkSheet._SaveFormats; 
    var i : integer; 
        iLen : 
    byte
        sFormat : 
    string
    begin 
      
    // FFormats already loaded in _SaveFontTable 
      FFormats.Add('0');                     // Integer Default 
      FFormats.Add('###,###,##0.00');        // Double Default 
      FFormats.Add('dd-mmm-yyyy hh:mm:ss');  // DateTime Default 
      FFormats.Add('dd-mmm-yyyy');           // Date Default 
      FFormats.Add('hh:mm:ss');              // Time default 

      
    // Add General Default index 0 
      sFormat := 'General'
      _WriteToken(XL_FORMAT,
    1 + length(sFormat)); 
      iLen :
    = length(sFormat); 
      Blockwrite(FFile,iLen,
    1); 
      Blockwrite(FFile,sFormat[
    1],iLen); 

      
    for i := 0 to FFormats.Count - 1 do begin 
        sFormat :
    = trim(FFormats[i]); 

        
    if not SameText(sFormat,'General') then begin 
          _WriteToken(XL_FORMAT,
    1 + length(sFormat)); 
          iLen :
    = length(sFormat); 
          Blockwrite(FFile,iLen,
    1); 
          Blockwrite(FFile,sFormat[
    1],iLen); 
        end; 
      end; 
    end; 


    // ============================================= 
    // INTERNAL - Write out DIMENSION Record 
    // ============================================= 

    procedure TExcelWorkSheet._SaveDimensions; 
    var aDIMBuffer : array [
    0..3] of word; 
    begin 
      _WriteToken(XL_DIM,
    8); 
      aDIMBuffer[
    0] := 0
      aDIMBuffer[
    1] := FMaxRow; 
      aDIMBuffer[
    2] := 0
      aDIMBuffer[
    3] := FMaxCol; 
      Blockwrite(FFile,aDIMBuffer,SizeOf(aDIMBuffer)); 
    end; 


    // ===================================== 
    // INTERNAL - Save Cell Records 
    // ===================================== 

    procedure TExcelWorkSheet._SaveCells(ARowFr,ARowTo : word); 
    var i,iIdx : integer; 
        iRow,iCol : word; 
        iDataLen,iFmtIdx, 
        iBorders, 
        iShade,iAlign, 
        iFntIdx,iFmtFnt : 
    byte
        oCell : TExcelCell; 
        dDblData : 
    double
        sStrData : 
    string
        aAttributes : array [
    0..2] of byte
    begin 
      aAttributes[
    0] := 0;  // No reference to XF 

      
    for i := 0 to FCells.Count - 1 do begin 
        oCell :
    = TExcelCell(FCells.Objects[i]); 
        
    // Row and Col resolve 
        iRow := oCell.FRow; 

        
    if iRow >= ARowFr then begin 
          
    if iRow > ARowTo then break
          iCol :
    = oCell.FCol; 
          
    if iCol > 255 then iCol := 255

          
    // Format IDX resolve - set defaults for numerics/dates 
          iFmtIdx := 0

          
    if SameText('General',oCell.FormatString) and 
             (oCell.DataType 
    <> xlString) then begin 
          
    case oCell.DataType of 
            xlInteger   : oCell.FormatString :
    = '0'
            xlDateTime  : oCell.FormatString :
    = 'dd-mmm-yyyy hh:mm:ss'
            xlTime      : oCell.FormatString :
    = 'hh:mm:ss'
            xlDate      : oCell.FormatString :
    = 'dd-mmm-yyyy'
            xlDouble    : oCell.FormatString :
    = '###,###,##0.00'
            end; 
          end; 

          
    if FFormats.Find(oCell.FormatString,iIdx) then begin 
            
    if iIdx > 62 then iIdx := 62
            iFmtIdx :
    = iIdx + 1
          end; 

          
    // Font IDX resolve and or with format 
          iFntIdx := oCell.FontIndex shl 6
          iFmtFnt :
    = iFmtIdx or iFntIdx; 

          
    // Shading and alignment and borders 
          iShade := 0
          
    if oCell.HasPattern then iShade := $80
          iAlign :
    = byte(oCell.Align); 
          iBorders :
    = 0
          
    if xbLeft in oCell.BorderStyle then iBorders := iBorders or $08
          
    if xbRight in oCell.BorderStyle then iBorders := iBorders or $10
          
    if xbTop in oCell.BorderStyle then iBorders := iBorders or $20
          
    if xbBottom in oCell.BorderStyle then iBorders := iBorders or $40

          
    // Resolve Data Type 
          case oCell.DataType of 
            xlInteger, 
            xlDateTime, 
            xlTime, 
            xlDate, 
            xlDouble  : begin 
                          dDblData :
    = oCell.Data; 
                          iDataLen :
    = SizeOf(double); 
                          _WriteToken(XL_DOUBLE,
    15); 
                          _WriteToken(iRow,iCol); 
                          aAttributes[
    1] := iFmtFnt; 
                          aAttributes[
    2] := iAlign or iShade or iBorders; 
                          Blockwrite(FFile,aAttributes,SizeOf(aAttributes)); 
                          Blockwrite(FFile,dDblData,iDatalen); 
                        end; 

            xlString  : begin 
                          sStrData :
    = oCell.Data; 
                          iDataLen :
    = length(sStrData); 
                          _WriteToken(XL_STRING,iDataLen 
    + 8); 
                          _WriteToken(iRow,iCol); 
                          aAttributes[
    1] := iFmtFnt; 
                          aAttributes[
    2] := iAlign or iShade or iBorders; 
                          Blockwrite(FFile,aAttributes,SizeOf(aAttributes)); 
                          Blockwrite(FFile,iDataLen,SizeOf(iDataLen)); 
                          
    if iDataLen > 0 then Blockwrite(FFile,sStrData[1],iDataLen); 
                        end; 
          end; 
        end; 
      end; 
    end; 



    // ======================================================= 
    // INTERNAL - Calulate the size of the cell record + data 
    // ======================================================= 

    function TExcelWorkSheet._CalcSize(AIndex : integer) : word; 
    var iResult : word; 
        oCell : TExcelCell; 
    begin 
      iResult :
    = 0
      oCell :
    = TExcelCell(FCells.Objects[AIndex]); 

      
    case oCell.DataType of 
        xlInteger, 
        xlDateTime, 
        xlTime, 
        xlDate, 
        xlDouble  : iResult :
    = 19

        xlString  : iResult :
    = length(oCell.Data) + 12
      end; 

      Result :
    = iResult; 
    end; 


    // ================================================================ 
    // INTERNAL - Fint fisrt and last used column ro ROW Record 
    // Only used when writing in RowBlock mode (_SaveRowBlocks) 
    // ================================================================ 

    procedure TExcelWorkSheet._SetColIdx(AListIdx : integer; 
                                         ARow : word; 
                                         
    out AFirst : word; 
                                         
    out ALast : word); 
    var sKey : 
    string
        i,iIdx, 
        iRow : integer; 
        iDataSize : word; 
    begin 
      FUsedRows.Objects[AListIdx] :
    = nil; 
      iDataSize :
    = 0
      iIdx :
    = -1
      AFirst :
    = 0
      ALast :
    = 0

      
    // Find first row-col combo 
      for i := 0 to FCells.Count - 1 do begin 
        sKey :
    = FCells[i]; 
        iRow :
    = StrToInt('$' + copy(sKey,1,4)); 

        
    if iRow = ARow then begin 
          iIdx :
    = i; 
          
    break
        end; 
      end; 

      
    // Found rows? 
      if iIdx >= 0 then begin 
        AFirst :
    = StrToInt('$' + copy(sKey,5,4)); 
        ALast :
    = AFirst; 
        inc(iDataSize,_CalcSize(iIdx)); 
        inc(iIdx); 

        
    // Repeat until last row-col 
        if iIdx < FCells.Count then begin 
          
    while true do begin 
            sKey :
    = FCells[iIdx]; 
            iRow :
    = StrToInt('$' + copy(sKey,1,4)); 

            
    if iRow = ARow then begin 
              ALast :
    = StrToInt('$' + copy(sKey,5,4)); 
              inc(iDataSize,_CalcSize(iIdx)); 
            end 
            
    else 
              
    break

            inc(iIdx); 
            
    if iIdx = FCells.Count then break
          end; 
        end; 

        inc(ALast); 
        FUsedRows.Objects[AListIdx] :
    = TObject(iDataSize); 
      end; 
    end; 

    // ================================================================== 
    // INTERNAL - Write out row/cells in ROWBLOCK format 
    // NOTE : This mode is onley used when at least 1 row has 
    // had it's height set by SetRowHeight(), otherwise _SaveCell() 
    // is run from first to last cells in sheet (faster) 
    // ================================================================== 

    procedure TExcelWorkSheet._SaveRowBlocks; 
    const aWINDOW1 : array [0..13] of byte = ($3d,$00,$0A,$00,$68,$01,$D2, 
                                              $
    00,$DC,$41,$B8,$29,$00,$00); 
    var i,iArrIdx, 
        iIdx,iCount,iLoop : integer; 
        iFirst,iLast,iHeight : word; 
        aAttributes : array [
    0..2] of byte
        aRowRec : array of TRowRec; 
    begin 
      aAttributes[
    0] := 0;  // No reference to XF 
      iLoop := 0

      
    // Process in blocks of 32 rows 
      while true do begin 
        iArrIdx :
    = 0

        
    if iLoop + 31 < FUsedRows.Count - 1 then begin 
          iCount :
    = iLoop + 31
          SetLength(aRowRec,
    32); 
        end 
        
    else begin 
          iCount :
    = FUsedRows.Count - 1
          SetLength(aRowRec,iCount 
    - iLoop + 1); 
        end; 

        
    for i := iLoop to iCount do begin 
          aRowRec[iArrIdx].RowIdx :
    = StrToInt(FUsedRows[i]); 
          _SetColIdx(i,aRowRec[iArrIdx].RowIdx,iFirst,iLast); 
          aRowRec[iArrIdx].FirstCell :
    = iFirst; 
          aRowRec[iArrIdx].LastCell :
    = iLast; 
          aRowRec[iArrIdx].Defs :
    = 0
          aRowRec[iArrIdx].NotUsed :
    = 0
          aRowRec[iArrIdx].Height :
    = $80FF; 
          iIdx :
    = FRowHeights.IndexOf(IntToStr(aRowRec[iArrIdx].RowIdx)); 

          
    if iIdx <> -1 then begin 
            iHeight :
    = word(FRowHeights.Objects[iIdx]); 
            
    if iHeight <> 0 then aRowRec[iArrIdx].Height := iHeight * 20
          end; 

          
    if iArrIdx = 0 then 
            aRowRec[iArrIdx].OSet :
    = (iCount - iLoop) * 
                                     (SizeOf(TRowRec) 
    + 4
          
    else 
            aRowRec[iArrIdx].OSet :
    = word(FUsedRows.Objects[i - 1]); 

          _WriteToken(XL_ROW,SizeOf(TRowRec)); 
          BlockWrite(FFile,aRowRec[iArrIdx],SizeOf(TRowRec)); 
          inc(iArrIdx); 
        end; 

        _SaveCells(aRowRec[
    0].RowIdx,aRowRec[high(aRowRec)].RowIdx); 
        SetLength(aRowRec,
    0); 
        iLoop :
    = iLoop + (iCount - iLoop + 1); 
        
    if iLoop >= FUsedRows.Count - 1 then break
      end; 

      
    // Write WINDOW1 Record 
      BlockWrite(FFile,aWINDOW1,SizeOf(aWINDOW1)); 
    end; 


    // ========================================================= 
    // INTERNAL - Write out non-default column widths as 
    // set by ColumnWidth() 
    // ========================================================= 

    procedure TExcelWorkSheet._SaveColWidths; 
    var i : integer; 
        iCol : 
    byte
        iWidth : word; 
    begin 
      
    for i := 0 to FColWidths.Count - 1 do begin 
        iCol :
    = StrToInt(FColWidths[i]); 
        iWidth :
    = 256 * word(FColWidths.Objects[i]); 
        _WriteToken(XL_COLWIDTH,
    4); 
        Blockwrite(FFile,iCol,
    1); 
        Blockwrite(FFile,iCol,
    1); 
        Blockwrite(FFile,iWidth,
    2); 
      end; 
    end; 


    // ======================================================= 
    // INTERNAL Base Font Setting Method - Default and 1..3 
    // ======================================================= 

    procedure TExcelWorkSheet._SetFont(AFontNum : 
    byte
                                       
    const AFontName : string
                                       AFontSize : 
    byte
                                       AFontStyle : TFontStyles; 
                                       AFontColor : word); 
    var sKey : 
    string
        iAttr : integer; 
    begin 
      iAttr :
    = 0
      
    if fsBold in AFontStyle then iAttr := iAttr or 1
      
    if fsItalic in AFontStyle then iAttr := iAttr or 2
      
    if fsUnderline in AFontStyle then iAttr := iAttr or 4
      
    if fsStrikeOut in AFontStyle then iAttr := iAttr or 8
      sKey :
    = trim(AFontName) + '|' + IntToStr(AFontSize) + 
              
    '|' + IntToStr(iAttr); 
      FFontTable[AFontNum] :
    = sKey; 
      FFontTable.Objects[AFontNum] :
    = TObject(AFontColor); 
    end; 


    // ======================================================= 
    // INTERNAL Base Font Get Info Method - Default and 1..3 
    // ======================================================= 

    function TExcelWorkSheet._GetFont(AFontNum : 
    byte) : TExcelFont; 
    var rResult : TExcelFont; 
        sKey : 
    string
        iStyle : integer; 
    begin 
      rResult.FontStyle :
    = []; 
      
    if AFontNum > 3 then AFontNum := 3
      sKey :
    = FFontTable[AFontNum]; 
      rResult.FontName :
    = copy(skey,1,pos('|',sKey) - 1); 
      sKey :
    = copy(sKey,pos('|',skey) + 1,2096); 
      rResult.FontSize :
    = StrToInt(copy(sKey,1,pos('|',sKey) - 1)); 
      iStyle :
    = StrToInt(copy(sKey,pos('|',skey) + 1,2096)); 
      rResult.FontColor :
    = integer(FFontTable.Objects[AFontNum]); 
      
    if iStyle and 1 = 1 then include(rResult.FontStyle,fsBold); 
      
    if iStyle and 2 = 2 then include(rResult.FontStyle,fsItalic); 
      
    if iStyle and 4 = 4 then include(rResult.FontStyle,fsUnderline); 
      
    if iStyle and 8 = 8 then include(rResult.FontStyle,fsStrikeOut); 

      Result :
    = rResult; 
    end; 


    // ===================================== 
    // PUBLIC - Font Setting Methods 
    // ===================================== 

    procedure TExcelWorkSheet.SetFont_Default(
    const AFontName : string
                                              AFontSize : 
    byte = 10
                                              AFontStyle : TFontStyles 
    = []; 
                                              AFontColor : word 
    = 0); 
    begin 
      _SetFont(XL_FONT_DEFAULT,AFontName,AFontSize,AFontStyle,AFontColor); 
    end; 


    procedure TExcelWorkSheet.SetFont_1(
    const AFontName : string
                                        AFontSize : 
    byte = 10
                                        AFontStyle : TFontStyles 
    = []; 
                                        AFontColor : word 
    = 0); 
    begin 
      _SetFont(XL_FONT_1,AFontName,AFontSize,AFontStyle,AFontColor); 
    end; 

    procedure TExcelWorkSheet.SetFont_2(
    const AFontName : string
                                        AFontSize : 
    byte = 10
                                        AFontStyle : TFontStyles 
    = []; 
                                        AFontColor : word 
    = 0); 
    begin 
      _SetFont(XL_FONT_2,AFontName,AFontSize,AFontStyle,AFontColor); 
    end; 

    procedure TExcelWorkSheet.SetFont_3(
    const AFontName : string
                                        AFontSize : 
    byte = 10
                                        AFontStyle : TFontStyles 
    = []; 
                                        AFontColor : word 
    = 0); 
    begin 
      _SetFont(XL_FONT_3,AFontName,AFontSize,AFontStyle,AFontColor); 
    end; 


    // ====================================== 
    // PUBLIC - Font Get Information Methods 
    // ====================================== 

    function TExcelWorkSheet.GetFont_Default : TExcelFont; 
    begin 
      Result :
    = _GetFont(XL_FONT_DEFAULT); 
    end; 

    function TExcelWorkSheet.GetFont_1 : TExcelFont; 
    begin 
      Result :
    = _GetFont(XL_FONT_1); 
    end; 

    function TExcelWorkSheet.GetFont_2 : TExcelFont; 
    begin 
      Result :
    = _GetFont(XL_FONT_2); 
    end; 

    function TExcelWorkSheet.GetFont_3 : TExcelFont; 
    begin 
      Result :
    = _GetFont(XL_FONT_3); 
    end; 


    // ===================================== 
    // Set a single column width 
    // ===================================== 

    procedure TExcelWorkSheet.ColumnWidth(ACol : 
    byte; AWidth : word); 
    var sKey : 
    string
        iIdx : integer; 
    begin 
      sKey :
    = IntToStr(ACol); 
      iIdx :
    = FColWidths.IndexOf(sKey); 
      
    if AWidth > 255 then AWidth := 255

      
    if iIdx <> -1 then 
        FColWidths.Objects[iIdx] :
    = TObject(AWidth) 
      
    else 
        FColWidths.AddObject(sKey,TObject(AWidth)); 
    end; 


    // ============================ 
    // Set a single row height 
    // ============================ 

    procedure TExcelWorkSheet.RowHeight(ARow : word; AHeight : 
    byte); 
    var sKey : 
    string
        iIdx : integer; 
    begin 
      sKey :
    = IntToStr(ARow); 
      iIdx :
    = FRowHeights.IndexOf(sKey); 

      
    if iIdx <> -1 then 
        FRowHeights.Objects[iIdx] :
    = TObject(AHeight) 
      
    else 
        FRowHeights.AddObject(sKey,TObject(AHeight)); 
    end; 


    // ================================================= 
    // Get a cell info object 
    // NOTE : A reference to the object is returned. 
    //        No need for user to FREE the object 
    // ================================================= 

    function TExcelWorkSheet.GetCell(ACol,ARow :word) : TExcelCell; 
    var oResult : TExcelCell; 
        sKey : 
    string
        iIndex : integer; 
    begin 
      sKey :
    = IntToHex(ARow,4+ IntToHex(ACol,4); 

      
    // Existing ? 
      if FCells.Find(sKey,iIndex) then 
        oResult :
    = TExcelCell(FCells.Objects[iIndex]) 
      
    else 
        oResult :
    = nil; 

      Result :
    = oResult; 
    end; 

    // ==================================================== 
    // Add or replace a cell in the worksheet 
    // NOTE : A reference to the object is returned. 
    //        No need for user to FREE the object 
    // ==================================================== 

    function TExcelWorkSheet.NewCell(ACol,ARow :word) : TExcelCell; 
    var oResult : TExcelCell; 
        sKey : 
    string
        iIndex : integer; 
    begin 
      oResult :
    = TExcelCell.Create; 
      oResult.FRow :
    = ARow; 
      oResult.FCol :
    = ACol; 
      
    if ACol > 255 then oResult.FCol := 255
      sKey :
    = IntToHex(ARow,4+ IntToHex(ACol,4); 

      
    // Existing ? 
      if FCells.Find(sKey,iIndex) then begin 
        TExcelCell(FCells.Objects[iIndex]).Free; 
        FCells.Objects[iIndex] :
    = oResult; 
      end 
      
    else 
        FCells.AddObject(sKey,oResult); 

      Result :
    = oResult; 
    end; 


    // ========================================= 
    // Blanks out a cell in the worksheet 
    // ========================================= 

    procedure TExcelWorkSheet.BlankCell(ACol,ARow :word); 
    var sKey : 
    string
        iIndex : integer; 
    begin 
      sKey :
    = IntToHex(ARow,4+ IntToHex(ACol,4); 

      
    // Existing ? 
      if FCells.Find(sKey,iIndex) then begin 
        TExcelCell(FCells.Objects[iIndex]).Free; 
        FCells.Delete(iIndex); 
      end; 
    end; 

    // =========================================== 
    // Procedural way to add or change a cell 
    // =========================================== 

    procedure TExcelWorkSheet.SetCell(ACol,ARow : word; 
                                      ADataType : TExcelDataType; 
                                      AData : Olevariant; 
                                      AFontIndex : 
    byte = 0
                                      AFormatString : 
    string = 'General'
                                      AAlign : TExcelCellAlign 
    = xalGeneral; 
                                      AHasPattern : boolean 
    = false
                                      ABorderStyle : TExcelBorders 
    = []); 
    var oCell : TExcelCell; 
        sKey : 
    string
        iIndex : integer; 
    begin 
      oCell :
    = TExcelCell.Create; 
      oCell.FRow :
    = ARow; 
      oCell.FCol :
    = ACol; 
      
    if ACol > 255 then ACol := 255
      oCell.DataType :
    = ADataType; 
      oCell.Data :
    = AData; 
      oCell.FontIndex :
    = AFontIndex; 
      
    if AFontIndex > 3 then oCell.FontIndex := 3

      oCell.FormatString :
    = AFormatString; 
      oCell.Align :
    = AAlign; 
      oCell.HasPattern :
    = AHasPattern; 
      oCell.BorderStyle :
    = ABorderStyle; 
      sKey :
    = IntToHex(ARow,4+ IntToHex(ACol,4); 

      
    // Existing ? 
      if FCells.Find(sKey,iIndex) then begin 
        TExcelCell(FCells.Objects[iIndex]).Free; 
        FCells.Objects[iIndex] :
    = oCell; 
      end 
      
    else 
        FCells.AddObject(sKey,oCell); 
    end; 

    // ==================================== 
    // Save Worksheet as an XLS file 
    // ==================================== 

    procedure TExcelWorkSheet.SaveToFile(
    const AFileName : string); 
    var aWord : array [
    0..1] of word; 
    begin 
      AssignFile(FFile,ChangeFileExt(AFileName,
    '.xls')); 
      Rewrite(FFile,
    1); 

      
    // BOF 
      _WriteToken(XL_BOF,4); 
      aWord[
    0] := 0
      aWord[
    1] := XL_DOCUMENT; 
      Blockwrite(FFile,aWord,SizeOf(aWord)); 

      
    // FONT 
      _SaveFontTable; 

      
    // COLWIDTH 
      _SaveColWidths; 

      
    // COLFORMATS 
      _SaveFormats; 

      
    // DIMENSIONS 
      _SaveDimensions; 

      
    // CELLS 
      if FRowHeights.Count > 0 then 
        _SaveRowBlocks          
    // Slower 
      else 
        _SaveCells(
    0,$FFFF);    // Faster 

      
    // EOF 
      _WriteToken(XL_EOF,0); 
      CloseFile(FFile); 
    end; 

    end. 
  • 相关阅读:
    ChsDet is a Charset Detector (检测字符编码)
    Microsoft Fakes进行单元测试
    区域及分离、Js压缩、css、jquery扩展
    服务端软件的服务品质
    警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context}
    开发之技能
    分布式
    工具集
    Visual Studio Code
    Autofac 入门
  • 原文地址:https://www.cnblogs.com/taobataoma/p/782376.html
Copyright © 2011-2022 走看看