|
Вопрос # 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
Качать тут
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|