捐赠 | 广告 | 注册 | 发布 | 上传 | 关于我们    
  粤ICP备10103342号-1 DELPHI盒子 | 盒子文章 | 盒子问答悬赏 | 最新更新 | 盒子检索 | 下载中心 | 高级搜索    
  精品专区 | 繁體中文 | 奖励公告栏 | 直通车账号登陆 | 关闭GOOGLE广告 | 临时留言    
 
广告
评论:DBGrid分页(Sheet)导出到Excel (支持超过65536条记录)
iamdream 45773 2013/4/12 10:27:22
最近将老代码升级到Delphi2010时将导出到Excel的代码整理了一下,现在可以支持D5~XE3了:DataSet分页导出到Excel(支持超过65536条记录)<http://dreamisx.blog.163.com/blog/static/115004839201331110398897/>

好久没看评论,这次正好总结一下:
1.不能设置类range的ColumnWidth属性
答:貌似是ColumnWidth超过255了,只要确保ColumnWidth不超过255即可,我这次最新整理的代码增加了检查;
2.导出的字符型字段数据都变成64
答:原先的代码只支持Ansi版本的Delphi,如果在Delphi2010之类的Unicode版本中用NumberFormatLocal := '@'来设置为文本型,则会变成64('@'的ASCII码),只要改成NumberFormatLocal := AnsiChar('@')就可以了;
3.之前的代码未处理Memo及Blob字段,这次整理也做了改进。
songyang 41383 2011/3/18 10:47:37
导出的字符型字段数据都变成64
xueguangjin 39737 2010/3/21 22:24:10
请求高人相助!
我问题太多!
suiyunonghen 37538 2009/5/22 0:01:08
修改了一下,我也。

procedure SaveDbGridAsExcel(Grid: TDBGrid;const FileName,title: string;
const MaxPageRowCount: Integer = 65535;const ShowProgress: Boolean = True);
const          
  MAX_VAR_ONCE   = 1000;     //一次导出的条数
var          //返回导出记录条数
  Excel, varCells: Variant;
  MySheet, MyCells, Cell1, Cell2, Range: OleVariant;
  iRow, iCol, iSheetIdx, iVarCount, iCurRow: integer;
  CurPos: TBookmark;
  ProgressForm: TForm;
  Prompt: TLabel;
  progressBar:  TProgressBar;
  Panel : TPanel;
  Button : TButton;
  procedure ReSetObjEvent(OldEventAddr: pointer;NewEventValue: pointer;ReSetObject: TObject);
  begin
     TMethod(OldEventAddr^).Code := NewEventValue;
     TMethod(OldEventAddr^).Data := ReSetObject;
  end;

  procedure ButtonClick(BtnObject: TObject;Sender: TObject);
  begin
    TComponent(BtnObject).Tag := Integer(MessageBox(Application.Handle,
          '真的要终止数据的导出吗?','确认',
          MB_OKCANCEL + MB_ICONINFORMATION) = IDOK);
  end;

  procedure CreateProgressForm;
  begin
    ProgressForm := TForm.Create(nil);
    With ProgressForm do
    begin
      Font.Name := '宋体';
      Font.Size := 10;
      BorderStyle := bsNone;
      Width := 280;
      Height := 120;
      BorderWidth := 1;
      Color := clBackground;
      Position := poOwnerFormCenter;
    end;
    Panel := TPanel.Create(ProgressForm);
    with Panel do { Create Panel }
    begin
      Parent := ProgressForm;
      Align := alClient;
      BevelInner := bvNone;
      BevelOuter := bvNone;
      Caption := '';
    end;

    Prompt := TLabel.Create(Panel);
    with Prompt do { Create Label }
    begin
      Parent := Panel;
      Left := 20;
      Top := 25;
      Caption := '正在启动Excel,请稍候……';
    end;

    progressBar := TProgressBar.Create(panel);
    with ProgressBar do { Create ProgressBar }
    begin
      Step := 1;
      Parent := Panel;
      Smooth := true;
      Left := 20;
      Top := 50;
      Height := 18;
      Width := 260;
    end;

    Button := TButton.Create(Panel);
    with Button do { Create Cancel Button }
    begin
      Parent := Panel;
      Left := 115;
      Top := 80;
      Caption := '关闭';
    end;
    ReSetObjEvent(@@Button.OnClick,@ButtonClick,Button);
    ProgressForm.FormStyle := fsStayOnTop;
    ProgressForm.Show;
    ProgressForm.Update;
  end;

begin
  if (Grid.DataSource <> nil) and
     (Grid.DataSource.DataSet <> nil) and
     Grid.DataSource.DataSet.Active then
  begin
    Grid.DataSource.DataSet.DisableControls;
    CurPos  := Grid.DataSource.DataSet.GetBookmark;
    Grid.DataSource.DataSet.First;
    try
      if ShowProgress then
      begin
        CreateProgressForm;
        Button.Tag := 0; 
      end;
      Excel := CreateOleObject('Excel.Application');
      Excel.WorkBooks.Add;
      Excel.Visible := False;
    except
      Application.Messagebox('Excel 没有安装!','操作提示', MB_IConERROR + mb_Ok);
      Screen.Cursor := crDefault;
      Grid.DataSource.DataSet.GotoBookmark(CurPos);
      Grid.DataSource.DataSet.FreeBookmark(CurPos);
      Grid.DataSource.DataSet.EnableControls;
      if ProgressForm <> nil then
         ProgressForm.Free;
      exit;
    end;
    if Grid.DataSource.DataSet.RecordCount <= MAX_VAR_ONCE then
      iVarCount := Grid.DataSource.DataSet.RecordCount
    else iVarCount := MAX_VAR_ONCE;
    varCells  := VarArrayCreate([1, iVarCount,1,Grid.FieldCount],varVariant);

    iSheetIdx := 1;
    iRow      := 0;
    if ShowProgress then
    begin
      ProgressBar.Position := 0;
      Prompt.Caption := '请等待,正在导出数据……';
      ProgressBar.Max := Grid.DataSource.DataSet.RecordCount;
    end;
    while (not Grid.DataSource.DataSet.Eof and not ShowProgress) or
       (not Grid.DataSource.DataSet.Eof and ShowProgress and (Button.Tag = 0)) do
    begin
      if (iRow = 0) or (iRow > MaxPageRowCount + 1) then
      begin
        if iSheetIdx <= Excel.WorkBooks[1].WorkSheets.Count then
          MySheet := Excel.WorkBooks[1].WorkSheets[iSheetIdx]
        else
          MySheet := Excel.WorkBooks[1].WorkSheets.Add(NULL, MySheet);//加在后面
        MySheet.Name := Title + IntToStr(iSheetIdx);
        MyCells := MySheet.Cells;
        Inc(iSheetIdx);
        //开始新的数据表
        iRow := 1;
        //写入表头
        for iCol := 1 to Grid.FieldCount  do
        begin
          MySheet.Cells[1, iCol] := Grid.Columns[iCol-1].Title.Caption;
          MySheet.Cells[1, iCol].Font.Bold := True;
          if (Grid.Fields[iCol - 1].DataType = ftString) or 
          (Grid.Fields[iCol - 1].DataType = ftWideString) then
          //对于“字符串”型数据则设Excel单元格为“文本”型
          MySheet.Columns[iCol].NumberFormatLocal := '@';        
        end;        
        Inc(iRow);
      end;
      iCurRow := 1;
      while (not Grid.DataSource.DataSet.Eof and not ShowProgress) or
          (not Grid.DataSource.DataSet.Eof and ShowProgress and (Button.Tag = 0)) do
      begin
        for iCol := 1 to Grid.FieldCount do
        begin
          Application.ProcessMessages;
          if Grid.Fields[iCol - 1].IsBlob then
          varCells[iCurRow, iCol] := '二进制数据'
          else varCells[iCurRow, iCol] := Grid.Fields[iCol-1].AsString;
        end;
        Inc(iRow);
        Inc(iCurRow);
        if ShowProgress then
          ProgressBar.Position := ProgressBar.Position + 1;
        Application.ProcessMessages;
        Grid.DataSource.DataSet.Next;
        if (iCurRow > iVarCount) or (iRow > MaxPageRowCount + 1) then
        begin
          Application.ProcessMessages;
          Break;
        end;
      end;
      Cell1 := MyCells.Item[iRow - iCurRow + 1, 1];
      Cell2 := MyCells.Item[iRow - 1,Grid.FieldCount];
      Range := MySheet.Range[Cell1 ,Cell2];
      Range.Value := varCells;
      MySheet.Columns.AutoFit;
      Cell1    := Unassigned;
      Cell2    := Unassigned;
      Range    := Unassigned;
      Application.ProcessMessages;
    end;
    if (ShowProgress and (Button.Tag = 0)) or not ShowProgress then
      MySheet.saveas(FileName);
    MyCells  := Unassigned;
    varCells := Unassigned;
    Excel.WorkBooks[1].Saved := True;
    MySheet.application.quit;
    Excel.quit;
    Excel  := Unassigned;
    if CurPos <> nil then
    begin
      Grid.DataSource.DataSet.GotoBookmark(CurPos);
      Grid.DataSource.DataSet.FreeBookmark(CurPos);
    end;
    Grid.DataSource.DataSet.EnableControls;
    if ProgressForm <> nil then
      ProgressForm.Free;
  end;
end;
hongss 37412 2009/5/7 12:07:36
  MyExcel.Visible := True;
  MyExcel.WorkBooks[1].Saved := True;
改为
  MyExcel.Visible := False;
  MyExcel.SaveAs('文件路径名');
Excel还是会打开,而且用SaveAs也存不下来。
用MyExcel.WorkBooks[1].SaveAs也不行……
onionzq 37395 2009/5/1 23:44:35
速度确实挺快的,Mark.
wgxis 37347 2009/4/27 20:28:05
不知道为什么,导出时会显示错误(编译没错误)
Access violation at address 0047D2B1 in module 'warehouse.exe'.Read of address 000000D2
warehouse.exe 是我的项目
zjyn 37201 2009/4/13 18:12:11
不能设置类range的columnwidth属性是什么意思?
longwater 37079 2009/4/3 0:39:54
我的做的系统有18W个客户以前导客户资料要是存成Excel 根本不够,不过我有自己在SQL里实现分开保存,啥时候有空拿这个试试卡
zhoukuanyu 36097 2008/11/8 11:47:07
速度很快 非常感谢
huangbit 35123 2008/7/28 23:47:05
非常感谢您iamdream,解决了困惑我很久的大问题。刚刚测试了,速度很快,而且调用很方便。
aagen 34024 2008/5/7 2:40:36
学习了啊

支持一下哦

多谢
iamdream 32836 2008/1/21 22:51:14
众人拾柴火焰高啊! 最新发现,如何用于导出Memo等字段的内容时,一旦Memo字段的内容一多或复杂(不能肯定是这个原因)就会报OLE Error,所以导出Memo字段内容时还是一格一格输出吧,毕竟难得需要导出大量带Memo字段的数据到Excel的.
iamdream 26522 2006/10/11 20:07:03
那你用MyExcel.WorkBooks[1].SaveAs(...)试试。
zlbpolly 26466 2006/10/8 12:32:05
iamdream 你好!

MyExcel.SaveAs('data.xls');
要保存为Excel文件,这样做报错:

----------
Debugger Exception Notification
----------
Project Project2.exe raised exception class EOleError with message 'Method 'SaveAs' not supported by automation object'. Process stopped. Use Step or Run to continue.
----------
OK   Help   
----------
iamdream 25506 2006/8/17 13:30:46
to xue_qy:
最后加一个MyExcel.Quit;就可以使Excel退出.
xue_qy 25016 2006/7/20 14:54:04
非常感谢iamdream,喜欢这种朴素的、实用的技巧。
有个问题,储存完excel文件后,windows内存中的excel进程并没关闭,这时如果要打开excel文件会出错,如何安全关闭excel进程。
iamdream 24358 2006/6/17 11:49:05
to gmshello:
你将最后的
  MyExcel.Visible := True;
  MyExcel.WorkBooks[1].Saved := True;
改为
  MyExcel.Visible := False;
  MyExcel.SaveAs('文件路径名');
就可以了。
gmshello 24260 2006/6/13 11:17:38
能否给个实例使导出的数据保存在指定的文件路径和文件名中但用不显示Excel
idoudo 24198 2006/6/9 21:38:52
问下delphi 方面的问题,我经常遇到这个问题。
   我的程序 经常是 在莫个控件后"."下面的提示出不来,(我放到 程序开头时就才有) 一定要自己写出它的属性或方法,(在没提示的情况下)运行时也不会出错的。就是重起了也没用。这是为什么的~~各位。。
第一页 上一页 下一页 最后页 有 57 条纪录 共3页 1 - 20
 用户名:
 密 码:
自动登陆(30天有效)
 
  DELPHI盒子版权所有 技术支持:深圳市麟瑞科技有限公司 1999-2024 V4.01 粤ICP备10103342号-1 更新RSS列表