Модераторы: MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Примеры работы с MS Excel 
:(
    Опции темы
Alex
Дата 21.3.2005, 18:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4147
Регистрация: 25.3.2002
Где: Москва

Репутация: 1
Всего: 162



В секции uses стоит так ExcelXP,{Excel2000, Excel97} крайней мере у меня, т.к. некоторые параметры при работе с разными версиями отличаются, например при открытии файла в версии XP больше параметров, чем в версии `97. 
На форме лежит компонента Ex1 типа TExcelApplication со страницы Servers, свойства AutoConnect и AutoQuit :=False, свойство ConnectKind:=ckRunningOrNew, 

Код

//объявления переменных 
var 
WorkBk : _WorkBook; //  определяем WorkBook 
WorkSheet : _WorkSheet; //  определяем WorkSheet 
Range:OleVariant;// 

begin 
... 
    Ex1.Connect;//открываем сам Excel 
    //открываем существующий файл, в разных версиях разное кол-во параметров 
    Ex1.Workbooks.Open(FileName,EmptyParam,EmptyParam,EmptyParam,EmptyParam, 
      EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam, EmptyParam,EmptyParam, 
      EmptyParam,EmptyParam,EmptyParam, LOCALE_USER_DEFAULT); 
//параметры для версии XP - имя файла, пути на ссылки в файле(UpdateLinks),Откывать ли  
//только для чтения, Формат, Пароль, WriteResPassword - ?, Игнорировать ли рекомендации  
//только для чтения, Origin - ?, Delimiter - символ-разделитель целой и дробной частей, Editable-? 
    Ex1.Application.EnableEvents := false;//отключаем реакцию Excel`я на события 

//так ищем название рабочей книги, т.к. Excel может уже быть открыт с другой книгой 
//поиск начинаем с единицы 
  For i:=1 to ex1.Workbooks.Count do begin 
    if ex1.Workbooks.Item[i].Name='MyFile.xls' then break; 
  end; 
 // Выбираем WorkBook 
  WorkBk := ex1.WorkBooks.Item[iInd]; 

  // Определяем WorkSheet 
 //если кол-во листов больше 1, иначе нет смысла искать 
//memoSheets - TMemo - с ключевыми фразами, напрмер, 
//Лист 1, Мой лист, Данные,  
  if WorkBk.Worksheets.Count>1 then begin 

    For x:=0 to memoSheets.Lines.Count-1 do begin 
     For q:=1 to WorkBk.Worksheets.Count do begin 
       WorkSheet:=WorkBk.WorkSheets.Get_Item(q) as _WorkSheet; 
       if WorkSheet.Name = memoSheets.Lines[x] then begin 
         //нашли лист 
         bNaydeno:=True; 
         WorkSheet.Activate(LOCALE_USER_DEFAULT);//активируем лист 
       end; 
       if bNaydeno= true then break; 
     end; 
     if bNaydeno=true then break; 
    end;//for 
  end else//if 
    WorkSheet:=WorkBk.WorkSheets.Get_Item(1) as _WorkSheet;; 

------------------ 
//Поиск последней строки... 
//можно заранее ставить в файле какую-нибудь метку, напрмер 99999 
//функция Find будет показана ниже 
iNameRow,iLastRow: Integer 
sNameCol: String 
  if Find('99999',iNameRow,sNameCol, WorkSheet) then begin 
   iLastRow:=iNameRow-1;//в столбце с наименованием ищем "99999"-конец импорта 
  end else begin     //и запоминаем в iRows 
   try//если не находим 99999 то ищем последнюю незаполненную ячейку 
     WorkSheet.Cells.SpecialCells(xlCellTypeLastCell,EmptyParam).Activate; 
     // Получаем значение последней строки 
     iLastRow:=(ex1.ActiveCell.Row)-1; 
    except 
      try 
        WorkSheet.Cells.SpecialCells(xlCellTypeLastCell,EmptyParam).Select; 
        // Получаем значение последней строки 
        iLastRow:=(ex1.ActiveCell.Row); 
      except 
        iLastRow:=0; 
      end;//try-except 
    end;//try-except 
  end;
 
memoNames - TMemo с наименованиями столбцов, т.к. в моем проекте у разных поставщиков  
Код

//могут столбцы называться по-разному, например, Товар, Наименование, Наименование товара 
  //ищем наименование 
  For r:=0 to memoNames.Lines.Count-1 do begin 
    bNaydeno:=False; 
    if Find(memoNames.Lines[r],iNameRow,sNameCol,WorkSheet) then begin 
      ... 
     break; 
    end;//if Find(memoNames.Lines[r],iNameRow,sNameCol) then begin 
  end;//For r:=0 to memoNames.Lines.Count-1 do begin 
//так ищем все нужные столбцы, запоминая столбец в каждую отдельную переменную 

//начинаем импорт со строки iNameRow 

//в конце могут начаться пустые строки, если неправльно 
//определилась последняя незаполненная ячейка 
//тогда нужно прервать цикл импорта 
     if (WorkSheet.Cells.Item[iNameRow,sNameCol].Value='') or 
      (WorkSheet.Cells.Item[iNameRow,sNameCol].Value=' ') then 
      Inc(iStop)//если пустая строка, то увеличиваем на 1 
     else 
      iStop:=0;//если следующая не пустая то обнуляем и продолжаем импорт 
     //если начались пустые строки то прекращаем импорт 
     if iStop>4 then break; 
//sg1-TStringGrid 
     //наименование препарата 
     sg1.Cells[1,e]:=WorkSheet.Cells.Item[iNameRow,sNameCol].Value; 
     //цена 
     sg1.Cells[2,e]:=WorkSheet.Cells.Item[iNameRow,sPriceCol].Value; 
//DelProb функция удаления всего лишнего, кроме цифр, точек и запятых 
//навыходе получаем вместо "2 305 585,85" "2305585,85" 
     sg1.Cells[2,e]:=DelProb(sg1.Cells[2,e]);//удаляем пробелы 
     //производитель 
     sg1.Cells[3,e]:=WorkSheet.Cells.Item[iNameRow,sProdCol].Value; 
     Inc(iNameRow); 
//добавляем строки к StringGrid только если они нужны 
     if sg1.RowCount=e then sg1.RowCount:=sg1.RowCount+1; 

     //прерываем по желанию пользователя 
     if fmMain.vAbort=False then begin//прерываем операцию 
          ... 
       try 
        Ex1.Workbooks.Close(LOCALE_USER_DEFAULT); 
        Ex1.Disconnect; 
        Ex1.Quit; 
       except 
       end;//try-except 

       Exit; 
      end;//if fmMain.vAbort=False then begin 


//так закрываем Excel 
try 
  Ex1.Quit; 
  Ex1.Disconnect; 
 except 
  ShowMessage('Ошибка закрытия Excel'); 
//обнуляем переменную Range 
 VarClear(Range);
 



sText - текст для поиска 
iRow - строка, в которой найдено значение 
sCol - колонка, в которой найдено значение 
UsedRange.Find - параметры для поиска, типа What:=sText, ищем в справке по Excel`ю 

Код

Function TfmImpExcel.Find(sText:String;Var iRow:Integer;Var sCol:String;WorkSheetF:_WorkSheet):Bool; 
Var 
UsedRange, Range: OLEVariant; 
t,y:Integer;//вспомогат для импорта 
FirstAddress: string; 
begin //поиск начали 
 Result:=False; 
 UsedRange := WorkSheetF.Range['A1','Z5000'];//диапазон поиска, напрмер от 'F25' до 'G30' 
 Range := UsedRange.Find(What:=sText, LookIn := xlValues, LookAt := xlWhole,SearchDirection := xlNext); 
 if not VarIsClear(Range) then begin 
   try 
     FirstAddress := Range.Address; 
     //вычисляем номер строки из полученного адреса(абсолютные координаты) 
     //он начинается после второго значка доллара 
     //формат найденной строки,что-то типа $A$2 (абсолютные координаты) 
     t:=PosEx('$',FirstAddress,2); 
     iRow:=StrToInt(Copy(FirstAddress,t+1,length(FirstAddress)-t)); 
     //вычисляем номер столбца из полученного адреса(абсолютные координаты) 
     //буква начинается со второго символа 
     y:=PosEx('$',FirstAddress,2); 
     sCol:=Copy(FirstAddress,2,y-2); 
     Result:=true; 
     VarClear(Range); 
     VarClear(UsedRange); 
   except 
     Result:=False; 
   end;//try-except 
 end;//if 
end;
 

Еще несколько примеров, используя Ole 
Excel:Variant - глобальная переменная 

Код

... 
begin 
//вначале проверяем, не открыт ли Excel  и закрываем 
if not VarIsEmpty(Excel) then begin 
 Excel.Quit; 
 Excel := Unassigned; 
end;//if 

   Try//открываем Excel и создаем раб.книгу 
     Excel:=CreateOleObject('Excel.Application'); 
     /кол-во листов в новой книге 
     Excel.SheetsInNewWorkbook:=1;// 
     //добавляем раб.книгу 
     Excel.WorkBooks.Add; 
     //в переменную "загоняем" текущий лист 
     Sheets:=Excel.Workbooks[1].Sheets[1]; 
   Except 
     SysUtils.beep; 
     ShowMessage('Не могу открыть Excel!'); 
     Exit; 
   end;//try-except 

   //рисуем border 
//сначала определяем диапазон 
   Range:=Sheets.Range['B1']; 
   Range.Borders[4].LineStyle := 1;//Range.Borders[4] - можно ставить от 1 до 8 - точно не мпомню 

     //рисуем border вокруг ячейки (обрамление) 
     Range.Borders[1].LineStyle := 1; 
     Range.Borders[2].LineStyle := 1; 
     Range.Borders[3].LineStyle := 1; 
     Range.Borders[4].LineStyle := 1; 

   //присваиваем значение яцейке 
   Sheets.Cells[2,2]:=Edit1.Text;// формат Sheets.Cells[№ строки,№ колонки] 
   //так выполняем выравнивание в диапазоне 
   //присваиваем диапазону координаты ячейки 
   Range:=Sheets.Cells[2,2];//можно переменные Range:=Sheets.Cells[iRow,iCol]; 
   Range.HorizontalAlignment := xlCenter; 
   Range.VerticalAlignment := xlCenter; 
   //форматируем шрифт 
   Sheets.Cells[iRow,3]:='ЗАЯВКА'; 
   Range:=Sheets.Cells[iRow,3]; 
   Range.Font.Bold:=True; 

//с присваиванием значения ячейке могут быть проблемы, т.к. Excel думает, что он очень умный 
//и вместо числа может переформатировать в дату вида 12дек2004, что бы такого не случилось,  
//можно заранее отформатировать ячейку в нужный формат (дата, число, валюта, текстовый) 
//все форматы можно узнать в Excel`е, с пом. макросов, просмотрев затем код, созданный самим 
//Excel`ем 
//#,##0.000$ - денежный 
//[$-FC19]dd mmmm yyyy г/;@ - дата 
//h:mm;@ - время 
//0.00% - проценты 
//# ??/?? - простые дроби 21/25 
//[<=9999999]###-####;(###) ###-#### - номер телефона 
//@ - текстовый формат, если указывать такой формат и присваивать 
//числовое значение, а затем складывать, то ничего не выйдет 

//передаваемая строки из Delphi может отличаться, нужно эксперементировать
 
tZay - TTable 
dbGridZay - DBGrid 
vRow - integer 
Код

   while not tZay.Eof do begin 
     For iColCount:=0 to dbGridZay.Columns.Count-1 do begin 
       Range:=Sheets.Cells[vRow,iColCount+1]; 
       Case tZay.FieldByName(dbGridZay.Columns[iColCount].FieldName).DataType of 
         ftFloat   : begin 
                       Range.NumberFormat := '0,000'; 
                       Sheets.Cells[vRow,iColCount+1]:= 
                       tZay.FieldByName(dbGridZay.Columns[iColCount].FieldName).AsFloat 
                     end; 
         ftString  : begin 
                       Range.NumberFormat := '@'; 
                       Sheets.Cells[vRow,iColCount+1]:= 
                       tZay.FieldByName(dbGridZay.Columns[iColCount].FieldName).AsString; 
                     end; 
         ftInteger : begin 
                       Range.NumberFormat := '0'; 
                       Sheets.Cells[vRow,iColCount+1]:= 
                       tZay.FieldByName(dbGridZay.Columns[iColCount].FieldName).AsInteger; 
                     end; 
         ftAutoinc : begin 
                       Range.NumberFormat := '0'; 
                       Sheets.Cells[vRow,iColCount+1]:= 
                       tZay.FieldByName(dbGridZay.Columns[iColCount].FieldName).AsInteger; 
                     end; 

         ftDate    : begin 
                       Range.NumberFormat := '@'; 
                       dDate:=tZay.FieldByName(dbGridZay.Columns[iColCount].FieldName).AsDateTime; 
                       Sheets.Cells[vRow,iColCount+1]:=FormatDateTime('dd.mm.yyyy',dDate); 
                     end 
       else 
         Range.NumberFormat := '@'; 
         Sheets.Cells[vRow,iColCount+1]:= 
         tZay.FieldByName(dbGridZay.Columns[iColCount].FieldName).AsString; 
       end;//case-else
 

  
удаляем лишние столбцы (по умолчанию со сдвигом влево) 


dbGridZay - DBGrid 
Код

   For iColCount:= dbGridZay.Columns.Count-1 downto 0 do begin 
     if dbGridZay.Columns[iColCount].Visible=False then begin 
       UsedRange := Sheets.Range['A1','Z100'];//диапазон поиска заголовка 
       Range := UsedRange.Find(What:=dbGridZay.Columns[iColCount].title.Caption, LookIn := xlValues, LookAt := xlWhole,SearchDirection := xlNext); 
       if not VarIsEmpty(Range) then begin 
         try 
           FirstAddress := Range.Address; 
           s:=StringReplace(FirstAddress,'$','',[rfReplaceAll]); 
           [b]Range:=Sheets.Range[s+':'+Copy(s,1,1)+IntToStr(vRow)];[/b] 
           [b]Range.Delete;[/b] 
         except 

         end;//try 
       end;//if not VarIsEmpty(Range)then begin 
     end;//if dbGridZay.Columns[iColCount].Visible=False then begin 
   end;//for delete 


//Объединение ячеек 
Sheet.Range[...].Merge(Across)
 


Относительно LOCALE_USER_DEFAULT 
Теоретически, в MSDN написано: "Indicates that the parameter is a locale ID (LCID)". Одни (Чарльз Калверт) предлагают в качестве его использовать 0, как идентификатор языка по умолчанию, другие - результат функции GetUserDefaultLCID. В некоторых случаях, чаще в связке Windows 2000 + Excel 2000, оба решения не проходят. Причем, выдается сообщение о попытке "использовать библиотеку старого формата..." Поэтому, рекомендуем в качестве lcid использовать значение константы LOCALE_USER_DEFAULT. 

Относительно открытия существующих рабочих книг 

Вот как описан метод Open в импортированной библиотеке типов: 
Код

function Open(const Filename: WideString; UpdateLinks: OleVariant; ReadOnly: OleVariant;  
Format: OleVariant; Password: OleVariant; WriteResPassword: OleVariant;  
IgnoreReadOnlyRecommended: OleVariant; Origin: OleVariant; 
Delimiter: OleVariant; Editable: OleVariant; Notify: OleVariant; 
Converter: OleVariant; AddToMru: OleVariant; lcid: Integer): Workbook; safecall;
 

Что вам из всего этого может понадобиться: 
· FileName 
Имя открываемого файла, желательно с полным путем, иначе Excel будет искать этот файл в каталоге по умолчанию; 
· AddToMru 
True - если необходимо запомнить файл в списке последних открытых файлов; 
· IgnoreReadOnlyRecommended 
Если файл рекомендован только для чтения, то при открытии Excel выдает соответствующее предупреждение. Чтобы его игнорировать, передайте в качестве данного параметра True. 
Используя позднее связывание 
При позднем связывании не нужно указывать все дополнительные параметры или LCID, можно просто написать вот так: 
Код

var  
Workbook: OLEVariant;  
...  
Workbook := Excel.WorkBooks.Open('C:\Test.xls');
  

Примечание: 
Если вы хотите получше узнать метод Open, например, как с его помощью открывать файлы текстовых форматов с разделителями, воспользуйтесь "пишущим" плеером VBA. Запишите макросы, а затем поправьте их по необходимости. 

Создание новой книги 

Используя раннее связывание 
Код

var 
IWorkbook: Excel8_TLB._Workbook;  
...  
IWorkbook := IExcel.Workbooks.Add(EmptyParam, xlLCID);
  

Передача в качестве первого параметра EmptyParam означает, что будет создана новая книга с количеством пустых листов, выставленным по умолчанию. Если в первом параметре вы передадите имя файла (с полным путем, иначе поиск осуществляется в каталоге по умолчанию), этот файл будет использован как шаблон для новой книги. Вы можете также передать одну из следующих констант: xlWBATChart, xlWBATExcel4IntlMacroSheet, xlWBATExcel4MacroSheet, или xlWBATWorksheet. В результате будет создана новая книга с единственным листом указанного типа. 
Внимание - важно! 
Excel не может держать открытыми несколько книг с одинаковыми названиями, даже если они лежат в разных каталогах, поэтому при создании файла по шаблону добавляет к имени файла новой книги номер (шаблон "test.xls" - новый файл "test1.xls"). 

Закрытие книги 

Используя раннее связывание 
Код

var 
SaveChanges: boolean;  
...  
SaveChanges := True; 
IWorkbook.Close(SaveChanges, EmptyParam, EmptyParam, xlLCID);
  

Если в качестве параметра SaveChanges вы передадите EmptyParam, Excel задаст вопрос, сохранять ли рабочую книгу. Второй параметр позволяет вам определить имя файла, а третий указывает, нужно ли отправлять книгу следующему получателю. 
Используя позднее связывание 
При позднем связывании нет необходимости указывать дополнительные параметры, поэтому вы можете просто написать: 

Код

Workbook.Close(SaveChanges := True);
 
или 
Код

Workbook.Close;
 


Как передать абсолютный адрес ячейки? 

Нужно использовать символ $ - Лист1!$A$1:$D$3' 

Так можно добавить новый модуль: 
Код

var 
IModule: VBIDE8_TLB.VBComponent; //с эти нужно поэксперементировать 
...  
IModule := IWorkbook.VBProject.VBComponents.Add( TOLEEnum(VBIDE8_TLB.vbext_ct_StdModule) ); 
IModule.Name :='MyModule1';
  

,поместить в него новую процедуру VBA: 

Код

IModule.CodeModule.AddFromString('PUBLIC SUB MySub1()'#13'Msgbox "Hello, World!"'#13'End sub'#13);
  

и запустить эту процедуру 

Код

OLEVariant(Excel).Run('MyModule1.MySub1');
  

Различные способы обращения к ячейкам 
Код

Var 
Value:Variant; 
... 
try  
//различные способы 
Value := ISheet.Cells.Item[2, 1].Value; 
Value := ISheet.Range['A2', EmptyParam].Value; 
Value := ISheet.Range['TestCell', EmptyParam].Value; 
Value := IWorkbook.Names.Item('TestCell', EmptyParam, EmptyParam).RefersToRange.Value; 
finally  
ISheet := nil;  
end;
  

Копирование данных в буфер обмена 

Код

var  
ISheetSrc, ISheetDst: Worksheet;//в разных версиях 
IRangeSrc, IRangeDst: Range; //могут объявляться по разному 
... 
IRangeSrc.Copy(IRangeDst); 


Метод Copy интерфейса Range принимает в качестве параметра любой другой Range, совпадение размеров источника и получателя необязательно. 
При копировании области убедитесь, что не редактируете ячейку, иначе возникнет исключение "Call was rejected by callee". 
Использование метода Copy без указания параметра destination скопирует ячейки в буфер обмена.


--------------------
Написать можно все - главное четко представлять, что ты хочешь получить в конце. 
PM Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: ActiveX/СОМ/CORBA"

Rrader
Girder

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами


  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Delphi
  • Вопросы по SQL и вопросы по базам данных, не связанные с Delphi, задавать здесь

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Rrader, Girder.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: ActiveX/СОМ/CORBA | Следующая тема »


 




[ Время генерации скрипта: 0.0696 ]   [ Использовано запросов: 23 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.