| 
| 
 | Вопрос # 1 093/ вопрос открыт / | 
 |  Приветствую, уважаемые эксперты!Мне необходимо сохранять StringGrid в Excel,нашёл TExcelApplicationприведите пожалуйста пример работы с ним(желательно сохранение в автоформате,ну там и другие опции).
 
|  |   Вопрос задал: GAZ (статус: Посетитель)Вопрос отправлен: 6 ноября 2007, 07:33
 Состояние вопроса: открыт, ответов: 2.
 |  Ответ #1. Отвечает эксперт: Николай Рубан Здравствуйте, GAZ!
 Все достаточно просто.
 
 Создаем рабочую книгу, только одно ЗАМЕЧАНИЕ - я создаю объекты TExcelApplication, ExcelWorkbook, ExcelWorkSheet вручную, соответственно и модули тоже
 uses OleServer, ExcelXP, ComObj, VarUtils; {список может быть и меньше - это Вы определите опытным путем ;)}
 (Вы же можете этого не делать... - просто расположите необходимые объекты на форме):
 
 var ExlApp: TExcelApplication;
 ExlWorkBook: ExcelWorkbook;
 ExlWorkSheet: ExcelWorkSheet;
 ...
 procedure TForm1.FormCreate(Sender: TObject);
 begin
 ExlApp:=TExcelApplication.Create(Self);
 ExlApp.ConnectKind := ckNewInstance;
 ExlApp.AutoQuit:=true;
 ExlApp.Visible[LOCALE_USER_DEFAULT]:=true;
 ExlWorkBook:=ExlApp.Workbooks.Add(EmptyParam,0);
 ExlWorkSheet:=ExlApp.ActiveWorkbook.ActiveSheet as ExcelWorksheet;
 end;
 ....
 
 И непосредственно заполняем ячейки листа данными из StringGrid-a:
 procedure TForm1.Button3Click(Sender: TObject);
 var i,j:integer;
 cell:String;
 begin
 with StringGrid1 do
 for i:=0 to ColCount-1 do
 for j:=0 to RowCount-1 do
 begin
 cell:=format('%s%d',[chr(ord('A')+j),i+1]); //формируем адрес ячейки в которую будем вносить данные
 ExlApp.Range[cell, EmptyParam].Value[xlRangeValueDefault] := Cells[j,i]; //непосредственно помещение даных
 end;
 end;
 
 Рассмотрим строку
 cell:=format('%s%d',[chr(ord('A')+j),i+1]);
 при i=0 и j=0 мы получим cell='A1'
 Следовательно заполнение данными начинается с адреса 'A1', если Вам необходимо начать вносить данные с другого адреса, то просто измените эту строку.
 Например для начала с адреса 'F3' достаточно сделать такой оператор:
 cell:=format('%s%d',[chr(ord('F')+j),i+3]);
 
 Good Luck!!!
 
|  | Ответ отправил: Николай Рубан (статус: 10-ый класс)Время отправки: 6 ноября 2007, 10:03
 
 |  Ответ #2. Отвечает эксперт: Feniks Здравствуйте, GAZ!Держите пару примеров в Приложении. Если у Вас StringGrid очень большой и надо много данных экспортировать, тогда лучше не использовать OLE объекты Оффиса, а делать на прямую в файл XLS. Для этого есть компоненты, например, VTKExport из библиотеки VTKTools. В атаче пример работы с ним.
 К ответу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки ответа)
 
 Приложение:Переключить в обычный режим   uses  ComObj;procedure XlsWriteCellLabel(XlsStream: TStream; const ACol, ARow: Word;  const AValue: string);var  L: Word;const  {$J+}  CXlsLabel: array[0..5] of Word = ($204, 0, 0, 0, 0, 0);  {$J-}begin  L := Length(AValue);  CXlsLabel[1] := 8 + L;  CXlsLabel[2] := ARow;  CXlsLabel[3] := ACol;  CXlsLabel[5] := L;  XlsStream.WriteBuffer(CXlsLabel, SizeOf(CXlsLabel));  XlsStream.WriteBuffer(Pointer(AValue)^, L);end; function SaveAsExcelFile(AGrid: TStringGrid; AFileName: string): Boolean;const  {$J+} CXlsBof: array[0..5] of Word = ($809, 8, 00, $10, 0, 0); {$J-}  CXlsEof: array[0..1] of Word = ($0A, 00);var  FStream: TFileStream;  I, J: Integer;begin  Result := False;  FStream := TFileStream.Create(PChar(AFileName), fmCreate or fmOpenWrite);  try    CXlsBof[4] := 0;    FStream.WriteBuffer(CXlsBof, SizeOf(CXlsBof));    for i := 0 to AGrid.ColCount - 1 do      for j := 0 to AGrid.RowCount - 1 do        XlsWriteCellLabel(FStream, I, J, AGrid.cells[i, j]);    FStream.WriteBuffer(CXlsEof, SizeOf(CXlsEof));    Result := True;  finally    FStream.Free;  end;end; // Example:  procedure TForm1.Button2Click(Sender: TObject);begin  if SaveAsExcelFile(StringGrid1, 'c:MyExcelFile.xls') then    ShowMessage('StringGrid saved!');end; ============================================================  { Code by Reinhard Schatzl } uses  ComObj; // Hilfsfunktion fur StringGridToExcelSheet // Helper function for StringGridToExcelSheet function RefToCell(RowID, ColID: Integer): string;var  ACount, APos: Integer;begin  ACount := ColID div 26;  APos := ColID mod 26;  if APos = 0 then  begin    ACount := ACount - 1;    APos := 26;  end;   if ACount = 0 then    Result := Chr(Ord('A') + ColID - 1) + IntToStr(RowID);   if ACount = 1 then    Result := 'A' + Chr(Ord('A') + APos - 1) + IntToStr(RowID);   if ACount > 1 then    Result := Chr(Ord('A') + ACount - 1) + Chr(Ord('A') + APos - 1) + IntToStr(RowID);end; // StringGrid Inhalt in Excel exportieren // Export StringGrid contents to Excel function StringGridToExcelSheet(Grid: TStringGrid; SheetName, FileName: string;  ShowExcel: Boolean): Boolean;const  xlWBATWorksheet = -4167;var  SheetCount, SheetColCount, SheetRowCount, BookCount: Integer;  XLApp, Sheet, Data: OLEVariant;  I, J, N, M: Integer;  SaveFileName: string;begin  //notwendige Sheetanzahl feststellen SheetCount := (Grid.ColCount div 256) + 1;  if Grid.ColCount mod 256 = 0 then    SheetCount := SheetCount - 1;  //notwendige Bookanzahl feststellen BookCount := (Grid.RowCount div 65536) + 1;  if Grid.RowCount mod 65536 = 0 then    BookCount := BookCount - 1;   //Create Excel-OLE Object Result := False;  XLApp  := CreateOleObject('Excel.Application');  try    //Excelsheet anzeigen    if ShowExcel = False then      XLApp.Visible := False    else      XLApp.Visible := True;    //Workbook hinzufugen    for M := 1 to BookCount do    begin      XLApp.Workbooks.Add(xlWBATWorksheet);      //Sheets anlegen      for N := 1 to SheetCount - 1 do      begin        XLApp.Worksheets.Add;      end;    end;    //Sheet ColAnzahl feststellen    if Grid.ColCount <= 256 then      SheetColCount := Grid.ColCount    else      SheetColCount := 256;    //Sheet RowAnzahl feststellen    if Grid.RowCount <= 65536 then      SheetRowCount := Grid.RowCount    else      SheetRowCount := 65536;     //Sheets befullen    for M := 1 to BookCount do    begin      for N := 1 to SheetCount do      begin        //Daten aus Grid holen        Data := VarArrayCreate([1, Grid.RowCount, 1, SheetColCount], varVariant);        for I := 0 to SheetColCount - 1 do          for J := 0 to SheetRowCount - 1 do            if ((I + 256 * (N - 1)) <= Grid.ColCount) and              ((J + 65536 * (M - 1)) <= Grid.RowCount) then              Data[J + 1, I + 1] := Grid.Cells[I + 256 * (N - 1), J + 65536 * (M - 1)];        //-------------------------        XLApp.Worksheets[N].Select;        XLApp.Workbooks[M].Worksheets[N].Name := SheetName + IntToStr(N);        //Zellen als String Formatieren        XLApp.Workbooks[M].Worksheets[N].Range[RefToCell(1, 1),          RefToCell(SheetRowCount, SheetColCount)].Select;        XLApp.Selection.NumberFormat := '@';        XLApp.Workbooks[M].Worksheets[N].Range['A1'].Select;        //Daten dem Excelsheet ubergeben        Sheet := XLApp.Workbooks[M].WorkSheets[N];        Sheet.Range[RefToCell(1, 1), RefToCell(SheetRowCount, SheetColCount)].Value :=          Data;      end;    end;    //Save Excel Worksheet    try      for M := 1 to BookCount do      begin        SaveFileName := Copy(FileName, 1,Pos('.', FileName) - 1) + IntToStr(M) +          Copy(FileName, Pos('.', FileName),          Length(FileName) - Pos('.', FileName) + 1);        XLApp.Workbooks[M].SaveAs(SaveFileName);      end;      Result := True;    except      // Error ?    end;  finally    //Excel Beenden    if (not VarIsEmpty(XLApp)) and (ShowExcel = False) then    begin      XLApp.DisplayAlerts := False;      XLApp.Quit;      XLAPP := Unassigned;      Sheet := Unassigned;    end;  end;end; //Example procedure TForm1.Button1Click(Sender: TObject);begin  //StringGrid inhalt in Excel exportieren //Grid : stringGrid, SheetName : stringgrid Print, Pfad : c:TestExcelFile.xls, Excelsheet anzeigen StringGridToExcelSheet(StringGrid, 'Stringgrid Print', 'c:TestExcelFile.xls', True);end;
|  | Ответ отправил: Feniks (статус: Бакалавр)Время отправки: 6 ноября 2007, 11:36
 
 |  
 Мини-форум вопросаВсего сообщений: 6; последнее сообщение — 9 ноября 2007, 10:39; участников в обсуждении: 4. 
|   | min@y™ (статус: Доктор наук), 6 ноября 2007, 08:18 [#1]:Откопал примерчик у себя на винте, но без TExcelApplication. Поэтому публикую не как ответ, а в форуме. Попробовал, вроде работает (Excel 2007). Подумал - может пригодится. 
 procedure TMainForm.Button1Click(Sender: TObject);
var 
   ServerIsRunning : boolean; 
   Unknown : IUnknown; 
   Result : HResult;
   AppProgID : String; 
   App : Variant;
   i,j:Integer;
begin
 //Указать программный идентификатор приложения-сервера
 AppProgID:='Excel.Application';
 ServerIsRunning := False;
 Result := GetActiveObject(ProgIDToClassID(AppProgID),nil,Unknown);
 if (Result = MK_E_UNAVAILABLE) then
 //Создать один экземпляр сервера
 App := CreateOleObject(AppProgID)
 else
  begin
   //Соединиться с уже запущенной копией сервера
   App := GetActiveOleObject(AppProgID);
   ServerIsRunning := True;
  end;
  //показать окно приложения на экране
  App.Visible := True;
  App.WorkBooks.Add;
  try
   for i:=0 to Grid.RowCount-1 do
    for j:=0 to Grid.ColCount-1 do
     begin
      App.ActiveWorkBook.WorkSheets[1].Cells[i+1,j+1].Value:=Grid.Cells[j,i];
     end;
  except
   Application.MessageBox(PChar('Упс!'),'Ошибка',mb_Ok+mb_IconError);
  end;
 if not ServerIsRunning then App.Quit;
 App:=Unassigned;
end;Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп! |  
|   | GAZ (статус: Посетитель), 8 ноября 2007, 17:40 [#2]:Н. Рубан: 1. cell:=format('%s%d',[chr(ord('A')+j),i+1]);
 .... после этой строчки прога вылетает и кроме как заголовка столбцов в Excel ничего больше не заноситься
 
 2.А всё таки как выполнить программно автоформат в Excel ,нашёл вроде опцию с аналогичным названием ,но в ней что то очень много параметров,может расскажете о них
 |  
|   | Николай Рубан (статус: 10-ый класс), 8 ноября 2007, 18:50 [#3]:А Вы мой код использовали один в один? Или же внесли некие коррективы? Если да, то прошу привести полный код Вашей программы...
 
 У меня все работает!!! Перед отправкой ответа я все коды тестирую
   |  
|   | GAZ (статус: Посетитель), 8 ноября 2007, 19:04 [#4]:Вроде один в один,есть правда одна штука может из за неё,у моего StringGrid многострочный заголовок и все записи в нём сцентрированны. |  
|   | Николай Рубан (статус: 10-ый класс), 8 ноября 2007, 20:35 [#5]:Так возьмите и испытайте мой код на ПРОСТОМ гриде без изысков, и если вы получите результат, значит нужно искать проблему именно в заголовках Вашего грида. |  
|   | Feniks (статус: Бакалавр), 9 ноября 2007, 10:39 [#6]:Попробуйте еще компонент XLSReadWrite: Мощный компонент для работы с файлами *.xls.
 Объём: 263 Кб
 Формат файла: RAR
 Версия: 1.15.02
 Качать тут
 |  Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |