Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: ActiveX/СОМ/CORBA > Содержимое Table скинуть в Excel 2003


Автор: Jey_k 10.11.2004, 13:02
Сабж. Заказчику приспичило.

Автор: Vit 10.11.2004, 17:30
Какой именно пример из FAQ?

Ты пробовал подсоединится через ADO, создать SQL запросом в Excel таблицу и перенести? Как он может не работать?

Автор: Jey_k 10.11.2004, 18:39
Vit
То что скачивал в DelphistsFAQ мне не помогло к сожалению.
Например на CreateOleObject вообще ругается.
Буду благодарен примерчику.

Автор: Satana 10.11.2004, 23:28
Jey_k А ты добавлял библиотеку comobj когда использовал CreateOleObject?

Автор: Jey_k 10.11.2004, 23:53
Satana
Не-а.
Завтра попробую. А можно примерчик, кратко и лаконично?

Автор: Fantasist 10.11.2004, 23:54
Jey_k, так не пойдет. Скажи, конкретно, что за код ты пытался использовать и с какой ошибкой он у тебя валиться. Потому как "не пашет" слабо отражает суть происходящего.

Могу разве что еще посоветовать (кроме перечисленных в FAQ) посмотреть F1Book (обычно есть на закладке то ли ActiveX, то ли Samples). С помощью него тоже неплохо получаеться.

Автор: Jey_k 11.11.2004, 00:10
Fantasist
Млин, да я вообще не знаю как это организовывается.
У меня на форме DBGrid связанный через Table с .db базой.

Вписав код из ФАКА получил кучу ошибок.


Мне нужно знать какие компоненты еще должны присутствовать, какие библиотеки нужно подключить и собственно код покороче.


Код

unit DBGridExportToExcel;  

interface  

uses  
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  
 ExtCtrls, StdCtrls, ComCtrls, DB, IniFiles, Buttons, dbgrids, ADOX_TLB, ADODB;  


type TScrollEvents = class  
      BeforeScroll_Event: TDataSetNotifyEvent;  
      AfterScroll_Event: TDataSetNotifyEvent;  
      AutoCalcFields_Property: Boolean;  
 end;  

procedure DisableDependencies(DataSet: TDataSet; var ScrollEvents: TScrollEvents);  
procedure EnableDependencies(DataSet: TDataSet; ScrollEvents: TScrollEvents);  
procedure DBGridToExcelADO(DBGrid: TDBGrid; FileName: string; SheetName: string);  


implementation  

//Support procedures: I made that in order to increase speed in  
//the process of scanning large amounts  
//of records in a dataset  

//we make a call to the "DisableControls" procedure and then disable the "BeforeScroll" and  
//"AfterScroll" events and the "AutoCalcFields" property.  
procedure DisableDependencies(DataSet: TDataSet; var ScrollEvents: TScrollEvents);
begin
 with DataSet do
   begin
     DisableControls;
     ScrollEvents := TScrollEvents.Create();
     with ScrollEvents do
       begin
         BeforeScroll_Event := BeforeScroll;
         AfterScroll_Event := AfterScroll;
         AutoCalcFields_Property := AutoCalcFields;
         BeforeScroll := nil;
         AfterScroll := nil;
         AutoCalcFields := False;
       end;
   end;
end;

//we make a call to the "EnableControls" procedure and then restore
// the "BeforeScroll" and "AfterScroll" events and the "AutoCalcFields" property.

procedure EnableDependencies(DataSet: TDataSet; ScrollEvents: TScrollEvents);
begin
 with DataSet do
   begin
     EnableControls;
     with ScrollEvents do
       begin
         BeforeScroll := BeforeScroll_Event;
         AfterScroll := AfterScroll_Event;
         AutoCalcFields := AutoCalcFields_Property;
       end;
   end;
end;

//This is the procedure which make the work:  

procedure DBGridToExcelADO(DBGrid: TDBGrid; FileName: string; SheetName: string);  
var  
 cat: _Catalog;  
 tbl: _Table;  
 col: _Column;  
 i: integer;  
 ADOConnection: TADOConnection;  
 ADOQuery: TADOQuery;  
 ScrollEvents: TScrollEvents;  
 SavePlace: TBookmark;  
begin  
 //  
 //WorkBook creation (database)  
 cat := CoCatalog.Create;  
 cat._Set_ActiveConnection('Provider=Microsoft.Jet.OLEDB.4.0; Data Source=' + FileName + ';Extended Properties=Excel 8.0');  
 //WorkSheet creation (table)  
 tbl := CoTable.Create;  
 tbl.Set_Name(SheetName);  
 //Columns creation (fields)  
 DBGrid.DataSource.DataSet.First;  
 with DBGrid.Columns do  
   begin  
     for i := 0 to Count - 1 do  
       if Items[i].Visible then  
       begin  
         col := nil;  
         col := CoColumn.Create;  
         with col do  
           begin  
             Set_Name(Items[i].Title.Caption);  
             Set_Type_(adVarWChar);  
           end;  
         //add column to table  
         tbl.Columns.Append(col, adVarWChar, 20);  
       end;  
   end;  
 //add table to database  
 cat.Tables.Append(tbl);  

 col := nil;  
 tbl := nil;  
 cat := nil;  

 //exporting  
 ADOConnection := TADOConnection.Create(nil);  
 ADOConnection.LoginPrompt := False;  
 ADOConnection.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0; Data Source=' + FileName + ';Extended Properties=Excel 8.0';  
 ADOQuery := TADOQuery.Create(nil);  
 ADOQuery.Connection := ADOConnection;  
 ADOQuery.SQL.Text := 'Select * from [' + SheetName + '$]';  
 ADOQuery.Open;  


 DisableDependencies(DBGrid.DataSource.DataSet, ScrollEvents);  
 SavePlace := DBGrid.DataSource.DataSet.GetBookmark;  
 try  
 with DBGrid.DataSource.DataSet do  
   begin  
     First;  
     while not Eof do  
       begin  
         ADOQuery.Append;  
         with DBGrid.Columns do  
           begin  
             ADOQuery.Edit;  
             for i := 0 to Count - 1 do  
               if Items[i].Visible then  
                 begin  
                   ADOQuery.FieldByName(Items[i].Title.Caption).AsString := FieldByName(Items[i].FieldName).AsString;  
                 end;  
             ADOQuery.Post;  
           end;  
         Next;  
       end;  
   end;  

 finally  
 DBGrid.DataSource.DataSet.GotoBookmark(SavePlace);  
 DBGrid.DataSource.DataSet.FreeBookmark(SavePlace);  
 EnableDependencies(DBGrid.DataSource.DataSet, ScrollEvents);  

 ADOQuery.Close;  
 ADOConnection.Close;  

 ADOQuery.Free;  
 ADOConnection.Free;  

 end;  

end;  

end.  



Какую-то из библиотек вообще компилятор не увидел

Автор: Satana 11.11.2004, 08:32
ну смотри как у меня это сделано:
Код

var
txt, Excel,WB:variant;

begin
  Excel:=CreateOleObject('Excel.Application'); //Связываем объект
  Excel.WorkBooks.Open(OpenDialog1.FileName); //Загружаем книгу
  WB:=Excel.WorkBooks[1].WorkSheets[1]; //Устанавливаем первый лист первой книги.
//Теперь мона читать и писать в эксель
WB.cells[1,1]:='чонить'; //Добавили в первую колонку первую строку значение.
//И точно так же мона читать из ячеек
txt:=WB.cells[1,1];

end;

Автор: Jey_k 11.11.2004, 11:17
Satana
Хорошо, при этом какие библиотеки и компоненты нужны?
И еще адресация ячеек DBGrid не помешает.

Автор: <Spawn> 11.11.2004, 11:52
Jey_k Ни какие компоненты не нужны, разве что подключи модуль ComObj. Этот называется позднее связывание.

Цитата
И еще адресация ячеек DBGrid не помешает.


А зачем это? DBGrid предназначена для отображения данных, что не раз освещалось на форуме. Делай обычный цикл по набору данных, на подобии этого:

Код

CurrentRow := 1;
with Query1 do
begin
 First;
 while not Eof do
 begin
   WB.cells[CurrentRow, 1] := FieldByName('SomeField').AsString;
   {Либо если у тебя нескольо ячеек можно сделать так
    for i := 0 to FeldsCount - 1 do
      WB.cells[CurrentRow, i] := Feilds[i];}
   Inc(CurrentRow);
   Next;
 end;
end;


Писал без Delphi, так что могут быть ошибки smile

Автор: Satana 11.11.2004, 20:49
Jey_k Набор библиотек стандартный при создании нового проекта + comobj и все...

А на счет адресации ячеек <Spawn> правильно сказал во первых а во вторых ну не ужели низя самому проверить или хелп почитать?

Автор: Jey_k 11.11.2004, 22:21
<Spawn>
Насколько я понял надо Query на форму кидать, связывать его с Table и еще не забыть comobj в uses добавить

Автор: Satana 12.11.2004, 09:48
Примерно так...

Автор: <Spawn> 12.11.2004, 20:41
Цитата(Jey_k @ 11.11.2004, 14:21)
<Spawn>
Насколько я понял надо Query на форму кидать, связывать его с Table и еще не забыть comobj в uses добавить

Не совсемsmile Я привел пример для Query. Но если же ты используешь Table, то воспользуйся его методами для навигации по набору данных. Вся идея состоит в том, что тебе нужно перебрать весь имющийся набор данных и на каждой итерации цикла добавлять запись в таблицу Excel.

Автор: Jey_k 12.11.2004, 21:33
Цитата(Satana @ 11.11.2004, 08:32)
var
txt, Excel,WB:variant;

begin
  Excel:=CreateOleObject('Excel.Application'); //Связываем объект
  Excel.WorkBooks.Open(OpenDialog1.FileName); //Загружаем книгу
  WB:=Excel.WorkBooks[1].WorkSheets[1]; //Устанавливаем первый лист первой книги.
//Теперь мона читать и писать в эксель
WB.cells[1,1]:='чонить'; //Добавили в первую колонку первую строку значение.
//И точно так же мона читать из ячеек
txt:=WB.cells[1,1];

end;


А к Excel так обращаемся.
Так все таки как адресовать DBGrid по ячейкам?
Или остается юзать Table? Но тоже как? Там полей не 2 и не 3 а около 70

Автор: Satana 12.11.2004, 22:06
Jey_k А что делать? Придется писать запросы вида DataModule2.SQLDataSet1.FieldByName('some_field').asstring; и пихать их в ексель

Автор: Jey_k 13.11.2004, 12:58
Неужели никак нельзя реализовать следущее:

Цикл пока не конец таблицы
Цикл к от 1 до количества полей
Экселевская ячейка=значение поля(к)
конец цикла
конец цикла

Автор: Satana 13.11.2004, 13:09
Jey_k Конечно можно, я делал ет так:
Код

SQLDataSet1.CommandText:='SQL запрос';
SQLDataSet1.Open;
 while not SQLDataSet1.Eof do
    begin
        WB.cell[1,i]:=SQLDataSet1.FieldByName('Field_1').As<SomeType>;
        WB.cell[2,i]:=SQLDataSet1.FieldByName('Field_2').As<SomeType>;
...
        WB.cell[n,i]:=SQLDataSet1.FieldByName('Field_n').As<SomeType>;
        inc(i);
    end;

Писал не из дельфей, но должно работать...

Автор: Pakshin A. S. 13.11.2004, 13:09
Может поможет:
Код

...
    Excel.Visible:=False;
    Wb := Excel.WorkBooks.Add(1);
    Ws := Wb.WorkSheets[1];
    p:=Table1.GetBookmark;
    Table1.First;
    for i:=0 to Table1.FieldCount-1 do
     Ws.Cells[1,i+1]:=Table1.Fields[i].DisplayLabel;
    j:=2;
    while not Table1.Eof do
     begin
      for i:=0 to Table1.FieldCount-1 do
        Ws.Cells[j, i+1] := Table1.Fields[i].AsVariant;
      Table1.Next;
      inc(j);
     end;
    Table1.GotoBookmark(p);
    Table1.FreeBookmark(p);
    Excel.Visible := True;
   finally
    Excel := Unassigned;
    Excel := null;
   end;

Автор: Jey_k 13.11.2004, 13:31
Pakshin A. S.
Благодарю, помогло, все работает. Правда медленно, 10000 полей прога минут пять если не больше скидыват в Эксель будет.

Еще вот вопрос
Цитата
Excel.WorkBooks.Open(OpenDialog1.FileName); //Загружаем книгу


Это мы используем готовую книгу, а создать как если там ее нету?

Автор: Pakshin A. S. 13.11.2004, 14:03
Как мне объясняли, медленная работа - один из недостатков этого метода работы с Office...

Про книгу:
1) Для начала создали уже известным способом документ и сохранили его... потом уже можем открывать.
2) Если компонентик F1BOOK - нечто, типа Excel, даже то же самое.... smile Правда, работать не очень приятно....

Автор: <Spawn> 13.11.2004, 14:03
Попробуй
Код

Excel.WorkBooks.Add

Автор: Jey_k 13.11.2004, 14:36
<Spawn>
В качестве параметра имя файла?

Автор: Satana 16.11.2004, 13:33
Jey_k Чтобы быстро работало могу посоветовать использовать компоненту xlReport от Afalina Soft лично я в данный момент на нем остановился потому что он меня и по скорости и по простоте устраивает, но тебе потребуется лабать шаблоны...

Автор: Jey_k 16.11.2004, 14:42
Satana
Наверное это лишним не будет. Припости если не трудно.

Автор: Satana 16.11.2004, 14:46
Не совсем понял чего припостить то? Если нада могу тебе по почте переслать крякнутый только тогда в личку мыло свое дай...

Автор: Akella 7.12.2004, 10:11
http://forum.vingrad.ru/index.php?act=Search&CODE=show&searchid=8fe4cbf6f89e9e32121f5b914b0bbebc&search_in=posts&result_type=topics&highlite=excel

поищи по форуму в разных темах
Добавлено @ 10:12
я писал под Excel XP, после того, как скопировал программу на комп с Excel 2003 все также прекрасно работало smile

Автор: Jey_k 19.12.2004, 22:10
Спасибо всем. Все получилось.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)