用户注册



邮箱:

密码:

用户登录


邮箱:

密码:
记住登录一个月忘记密码?

发表随想


还能输入:200字
云代码 - delphi代码库

excel导出多表头

2012-10-20 作者: 明州一帆举报

[delphi]代码库

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, Grids, DBGridEh, DB, ADODB, StdCtrls, Excel2000,
  OleServer;

type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    DBGridEh1: TDBGridEh;
    Panel1: TPanel;
    ComboBox1: TComboBox;
    Edit1: TEdit;
    Button1: TButton;
    Button2: TButton;
    ExcelApplication1: TExcelApplication;
    ExcelWorksheet1: TExcelWorksheet;
    ExcelWorkbook1: TExcelWorkbook;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses ExportMultiTitle;

{$R *.dfm}

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caFree;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  conStr:string;
  i :integer;
begin
  conStr:='Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;Data Source=';
  conStr:=conStr+ExtractFilePath(Application.ExeName)+'test.mdb;';
  conStr:=conStr+'Mode=Share Deny None;Extended Properties="";Jet OLEDB:System database="";Jet OLEDB:Registry Path="";Jet OLEDB:Database Password="";';
  conStr:=conStr+'Jet OLEDB:Engine Type=5;Jet OLEDB:Database Locking Mode=1;Jet OLEDB:Global Partial Bulk Ops=2;';
  conStr:=conStr+'Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database Password="";';
  conStr:=conStr+'Jet OLEDB:Create System Database=False;Jet OLEDB:Encrypt Database=False;Jet OLEDB:Don''t Copy Locale on Compact=False;';
  conStr:=conStr+'Jet OLEDB:Compact Without Replica Repair=False;Jet OLEDB:SFP=False';
  ADOConnection1.ConnectionString:=conStr;
  ADOConnection1.Open;
  ADOQuery1.Open;
  for i:=0 to AdoQuery1.Fields.Count-1 do
    combobox1.Items.Add(AdoQuery1.Fields[i].FieldName);
  ComboBox1.ItemIndex:=0;
  ComboBox1.OnChange(Self);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ADOQuery1.Close;
  ADOConnection1.Close;
end;

procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  Edit1.Text:=ADOQuery1.Fields[ComboBox1.ItemIndex].DisplayLabel;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ADOQuery1.Fields[ComboBox1.ItemIndex].DisplayLabel:=Edit1.Text;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i,j:Integer;
  dT,dL,dR,dB:Integer;
  Ra:Variant;
begin
  Try
    ExcelApplication1.Connect;
    ExcelWorkbook1.ConnectTo(ExcelApplication1.Workbooks.Add(EmptyParam,0));
    ExcelWorkSheet1.ConnectTo(ExcelWorkBook1.Sheets[1] as _WorkSheet);
    ExcelApplication1.Caption := '通用客户打印调用 Microsoft Excel';
    ExcelApplication1.Visible[0]:=True;
    ExportMyCell(ADOQuery1.Fields);
    for i:=0 to r-1 do
      for j:=0 to c-1 do
        if MyCells[i,j].Used then
        begin
          if (MyCells[i,j].Rect.Top=MyCells[i,j].Rect.Bottom)
            and (MyCells[i,j].Rect.Left=MyCells[i,j].Rect.Right) then
          begin
            dT:=MyCells[i,j].Rect.Top+1;
            dL:=MyCells[i,j].Rect.Left+1;
            ExcelWorksheet1.Cells.Item[dt,dl]:=MyCells[i,j].Text;
          end
          else
          begin
            dT:=MyCells[i,j].Rect.Top+1;
            dL:=MyCells[i,j].Rect.Left+1;
            dR:=MyCells[i,j].Rect.Right+1;
            dB:=MyCells[i,j].Rect.Bottom+1;
          //合并
            ExcelWorksheet1.Cells.Item[dt,dl]:=MyCells[i,j].Text;
            Ra:=ExcelWorksheet1.Range[ExcelWorksheet1.Cells.Item[dt,dl],ExcelWorksheet1.Cells.Item[db,dr]];
            Ra.MergeCells:=True;
          end;
        end;
    ExcelWorkSheet1.Columns.AutoFit;
  Finally
    ExcelWorkSheet1.Disconnect;
    ExcelWorkBook1.Disconnect;
    ExcelApplication1.Disconnect;
    Ra:=Unassigned;
  end;
end;

end.



uses
  Windows, DB;

type
  PMyCell=^MyCell;
  MyCell=Record
    Text:String;
    Parent:PMyCell;
    Used:Boolean;
    Rect:TRect;
  end;

var
  MyCells: Array of Array of MyCell;
  R,C:Integer;

procedure ExportMyCell(AField:TFields);  

implementation

procedure ExportMyCell(AField:TFields);

  //取得列标题行数
  function GetTitleRow(ColTitle:String):Integer;
  var
    ii:Integer;
  begin
    Result:=1;
    for ii:=1 to Length(ColTitle) do
      if ColTitle[ii]='|' then Result:=Result+1;
  end;

  Function GetMaxTitleRow(AFields:TFields):Integer;
  var
    ii,jj:Integer;
  begin
    Result:=1;
    for ii:=0 to AFields.Count-1 do
    begin
      jj:=GetTitleRow(AFields[ii].DisplayLabel);
      if Result<jj then Result:=jj;
    end;
  end;

  procedure initMycells;
  var
    i,j:Integer;
  begin
    SetLength(MyCells,R);
    for i:=0 to R-1 do
    begin
      SetLength(MyCells[i],C);
      for j:=0 to C-1 do
      begin
        MyCells[i,j].Text:='';
        MyCells[i,j].Used:=True;
        MyCells[i,j].Rect.Left:=j;
        MyCells[i,j].Rect.Right:=j;
        MyCells[i,j].Rect.Top:=i;
        MyCells[i,j].Rect.Bottom:=i;
        if i=0 then MyCells[i,j].Parent:=nil
        else MyCells[i,j].Parent:=@MyCells[i-1,j];
      end;
    end;
  end;

  procedure GetFieldToMycells(AFields:TFields);
  var
    i,j:Integer;
    TmpStr:String;
  begin
    initMycells;
    for i:=0 to C-1 do
    begin
      TmpStr:=AFields[i].DisplayLabel;
      j:=0;
      while Pos('|',TmpStr)>0 do
      begin
        MyCells[j,i].Text:=Copy(TmpStr,1,Pos('|',TmpStr)-1);
        MyCells[j,i].Used:=True;
        if j<>0 then MyCells[j,i].Parent:=@MyCells[i-1,j];
        TmpStr:=Copy(TmpStr,Pos('|',TmpStr)+1,Length(TmpStr));
        Inc(j);
      end;
      MyCells[j,i].Text:=TmpStr;
    end;
  end;

  //合并过程(核心)
  procedure uniteMyCell;
  var
    i :integer;
    procedure MoveToLastCell(MR,MC:Integer);
    var
      i :integer;
    begin
      for i:=MR-1 downto 0 do
        if MyCells[i,MC].Text='' then Continue
        else
        begin
          MyCells[R-1,MC].Text:=MyCells[i,MC].Text;
          MyCells[i,MC].Text:='';
          Break;
        end;
    end;

    procedure CheckLastRow;//检测最后行
    var
      i:Integer;
    begin
      for i:=0 to C-1 do
        if MyCells[R-1,i].Text='' then MoveToLastCell(R-1,i);//移动最后一个有数据的单元格到最后一行
    end;

    //合并当前行
    procedure UionCurrRowCell(CR:Integer);
    var
      i,SC:integer;
      function GetNextCUCell(SC:Integer):Integer;
      var
        i:Integer;
      begin
        Result:=-1;
        i:=SC+1;
        while (Result=-1) and (i<C) do
          begin
            if not MyCells[CR,i].Used then Inc(i)
            else
              if (MyCells[CR,i].Text<>'') then Result:=i;
            MyCells[CR+1,i].Parent:=@MyCells[CR,i];
            Inc(i);
          end;
      end;
    begin
      SC:=GetNextCUCell(-1);//得到下一个可用单元
      if SC=-1 then Exit;
      //开始比较
      i:=SC+1;
      while (i<c) and (SC<>-1) do
      begin
        if MyCells[CR,i].Used then
        begin
          if (MyCells[CR,SC].Text=MyCells[CR,i].Text) then
          begin
            MyCells[CR,SC].Rect.Right:=i;
            MyCells[CR,i].Used:=False;
            MyCells[CR,i].Parent:=@MyCells[CR,SC];
            MyCells[CR+1,i].Parent:=@MyCells[CR,SC];
          end
          else SC:=i;
        end;
        i:=GetNextCUCell(i);
        if i=-1 then SC:=-1;
      end;
    end;

    procedure MoveUpCol(MR,MC:Integer);
    var
      i :integer;
    begin
      for i:=MR to R-1 do
        if (MyCells[i,MC].Text='') then Continue
        else
        begin
          MyCells[MR,MC].Text:=MyCells[i,MC].Text;
          MyCells[i,MC].Text:='';
          Break;
        end;
    end;

    //检测当前行单元是否为空,为空则将有数据的列上来
    procedure CheckCurrRow(CR:Integer);
    var
      i :integer;
    begin
      for i:=0 to C-1 do
      begin
        if (MyCells[CR,i].Used) and (MyCells[CR,i].Text='') then
        begin
          MoveUpCol(CR,i);
        end;
      end;
    end;

    //在范围内查找空行
    function FindEmpty(SR:Integer{开始行};FindRect:TRect;var RR:Integer):Boolean;
    var
      i,j :integer;
      Same:Boolean;
    begin
      Result:=False;
      for i:=SR to R-1 do
      begin
        Same:=True;
        for j:=FindRect.Left to FindRect.Right do
          if MyCells[i,j].Used and (MyCells[i,j].Text='') then Continue
          else
          begin
            Same:=False;
            Break;
          end;
        if Same then
        begin
          RR:=i;
          Result:=True;
          Break;
        end;
      end;
    end;
    //当前行与上一行交换
    procedure ChangeCell(CRect:TRect;RR:Integer);
    var
      i :integer;
    begin
      for i:= CRect.Left to CRect.Right do
      begin
        MyCells[RR,i].Text:=MyCells[RR-1,i].Text;
        MyCells[RR-1,i].Text:='';
      end;
    end;
    //提升空行
    procedure DoUpCol(CR,CC:Integer);
    var
      i,RR:integer;
    begin
      for i:=CR+2 to R-2 do
      //在范围内查找空行,并交换行
        if FindEmpty(i,MyCells[CR,CC].Rect,RR) then ChangeCell(MyCells[CR,CC].Rect,RR);
    end;
    //合并列
    procedure DoUionCell(CR,CC:Integer);
    var
      i,RR,j:Integer;
    begin
      for i:=CR+1 to R-1 do
      begin
        if FindEmpty(i,MyCells[CR,CC].Rect,RR) then
        begin
          if RR>CR then
          begin
            MyCells[CR,CC].Rect.Bottom:=RR;
            for j:=MyCells[CR,CC].Rect.Left to MyCells[CR,CC].Rect.Right do
            begin
              MyCells[RR,j].Used:=False;
              MyCells[RR,j].Parent:=@MyCells[CR,CC];
            end;
          end
          else Break;
        end else Break;
      end;
    end;
    //向下合并列 :)
    procedure UionCurrRowColCell(CR :integer);
    var
      i:integer;
    begin
      for i:=0 to C-1 do
      begin
        if MyCells[CR,i].Used then DoUpCol(CR,i);//提升空行
      end;
      for i:=0 to C-1 do
      begin
        if MyCells[CR,i].Used then DoUionCell(CR,i);//合并列
      end;
    end;
  begin
    CheckLastRow;         //检测最后行
    for i:=0 to R-2 do    //最后一行不管
    begin
      UionCurrRowCell(i); //合并当前行
      CheckCurrRow(i);    //检测当前行单元是否为空,为空则将有数据的列上来
      UionCurrRowColCell(i); //向下合并列 :)
    end;
  end;
begin
  R:=GetMaxTitleRow(AField);
  C:=AField.Count;
  GetFieldToMycells(AField);
  uniteMyCell; 
end;

end.


网友评论    (发表评论)


发表评论:

评论须知:

  • 1、评论每次加2分,每天上限为30;
  • 2、请文明用语,共同创建干净的技术交流环境;
  • 3、若被发现提交非法信息,评论将会被删除,并且给予扣分处理,严重者给予封号处理;
  • 4、请勿发布广告信息或其他无关评论,否则将会删除评论并扣分,严重者给予封号处理。


扫码下载

加载中,请稍后...

输入口令后可复制整站源码

加载中,请稍后...