2013-05-20 3 views
6

Я пытаюсь экспортировать данные из stringgrid в delphi 7 в microsoft excel. Я использую этот код, чтобы сделать это:export delphi stringgrid to excel

objExcel := TExcelApplication.Create(nil); 
    objExcel.Visible[LOCALE_USER_DEFAULT] := true; 
    objWB := objExcel.workbooks.add(null,LOCALE_USER_DEFAULT); 
    lineNumber := 1; 

    for i:=1 to stringgrid1.rowcount-1 do begin 
    for j:=0 to stringgrid1.ColCount-1 do begin 
     objWB.Worksheets.Application.Cells.Item[i+lineNumber,j+1] := ''''+stringgrid1.Cells[j,i]; 
    end; 
    end; 

но когда данные большой, он занимает очень много времени, чтобы закончить. есть ли другой более быстрый способ экспортировать данные из delphi 7 stringgrid в excel?

+0

спасибо за быстрый ответ, ребята. Я думаю, что метод массива лучше всего подходит для моей ситуации прямо сейчас, потому что я не буду использовать CSV-файл. как я могу отметить этот вопрос как «разрешенный»? – dapidmini

ответ

18

Самый быстрый способ заключается в использовании массив Variant, и просто передать весь массив в Excel:

var 
    xls, wb, Range: OLEVariant; 
    arrData: Variant; 
    RowCount, ColCount, i, j: Integer; 
begin 
    {create variant array where we'll copy our data} 
    RowCount := StringGrid1.RowCount; 
    ColCount := StringGrid1.ColCount 
    arrData := VarArrayCreate([1, RowCount, 1, ColCount], varVariant); 

    {fill array} 
    for i := 1 to RowCount do 
    for j := 1 to ColCount do 
     arrData[i, j] := StringGrid1.Cells[j-1, i-1]; 

    {initialize an instance of Excel} 
    xls := CreateOLEObject('Excel.Application'); 

    {create workbook} 
    wb := xls.Workbooks.Add; 

    {retrieve a range where data must be placed} 
    Range := wb.WorkSheets[1].Range[wb.WorkSheets[1].Cells[1, 1], 
            wb.WorkSheets[1].Cells[RowCount, ColCount]]; 

    {copy data from allocated variant array} 
    Range.Value := arrData; 

    {show Excel with our data} 
    xls.Visible := True; 
end; 
+0

спасибо за быстрый ответ. очень ясные шаги для новичка, подобного мне. это решило мою проблему. это позор, я не могу оценить ответ еще ... – dapidmini

+0

+1, просто интересно, относится ли самое быстрое время, необходимое для кода, или время, необходимое для фактической «копии»? Другим способом было бы, например, поместить все в буфер обмена в формате csv, а затем вставить содержимое буфера обмена в Excel. –

+1

@MarjanVenema: Буфер обмена принадлежит пользователю, а не программисту, поэтому ИМО это не вариант. Переход от массива варианта к диапазону Excel происходит очень быстро и не закручивает ничего, что пользователь вложил в буфер обмена, ожидая, что он появится позже. –

3

Проблема заключается в том, что вы вызываете объект Excel для каждой ячейки; это медленная работа в лучшие времена, поэтому делать это для большого количества ячеек займет много времени. У меня был случай этого не так давно: 4000 строк с 9 столбцами заняли около 44 секунд для перевода в Excel.

Мое текущее решение включает создание файла csv, а затем импорт этого csv в Excel.

const 
fn = 'c:\windows\temp\csv.csv'; 

var 
csv: tstringlist; 
row, col: integer; 
s: string; 

begin 
csv:= tstringlist.create; 
for row:= 1 to stringgrid1.rowcount do 
    begin 
    s:= ''; 
    for col:= 0 to stringgrid1.ColCount-1 do 
    s:= s + stringgrid1.Cells[col, row-1] + ','; 
    csv.add (s) 
    end; 

csv.savetofile (fn); 
csv.free; 

objExcel := TExcelApplication.Create(nil); 
objExcel.workbooks.open (fn); 
deletefile (fn); 
end; 

Другой способ исходит из Mike Shkolnik, который я цитирую как:

var 
xls, wb, Range: OLEVariant; 
arrData: Variant; 

begin 
{create variant array where we'll copy our data} 
arrData := VarArrayCreate([1, yourStringGrid.RowCount, 1, yourStringGrid.ColCount], varVariant); 

{fill array} 
for i := 1 to yourStringGrid.RowCount do 
    for j := 1 to yourStringGrid.ColCount do 
    arrData[i, j] := yourStringGrid.Cells[j-1, i-1]; 

{initialize an instance of Excel} 
xls := CreateOLEObject('Excel.Application'); 

{create workbook} 
wb := xls.Workbooks.Add; 

{retrieve a range where data must be placed} 
Range := wb.WorkSheets[1].Range[wb.WorkSheets[1].Cells[1, 1], 
           wb.WorkSheets[1].Cells[yourStringGrid.RowCount, yourStringGrid.ColCount]]; 

{copy data from allocated variant array} 
Range.Value := arrData; 

{show Excel with our data} 
xls.Visible := True; 
end; 

Я предлагаю вам попробовать оба метода и посмотреть, что быстрее для ваших целей.

+0

спасибо за быстрый ответ. так как я не думаю, что буду использовать файл csv, сейчас я просто использую решение массива. К сожалению, я пока не могу оценить ответ. – dapidmini

+0

@ dapidmini: Преимущество метода csv заключается в том, что его можно использовать, когда количество строк неизвестно заранее. Очевидно, это не произойдет с stringgrid, но это произойдет, если вы хотите передать результаты запроса в Excel. Жаль, что вы отметили ответ, который не ссылался на его источник. –

+0

@ dapidmini: используя формат csv, вы также можете использовать буфер обмена, если это необходимо, без записи его сначала в файл. –