Чтение данных из ячейки.
Написав этот заголовок, я подумал о том, как часто я “беру” данные из книги. Это случается весьма редко, ибо Excel я использую как средство построения отчетов. То есть, намного чаще эти данные я туда передаю. Поэтому хотелось бы описать не столько чтение данных, сколько способы обращения к ячейкам. Я использую разные способы обращения к ячейкам от привычного в Excel Cells(x,y) до коллекции Names. Вот некоторые примеры:
procedure TForm1.btnReadDataClick(Sender: TObject);
var Value: OLEVariant;
ISheet: Excel8TLB._Worksheet;
begin
if Assigned(IWorkbook) then
try
ISheet := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet;
try
case rgWhatRead.ItemIndex of
0: Value := ISheet.Cells.Item[2, 1].Value;
1: Value := ISheet.Range['A2', EmptyParam].Value;
2: Value := ISheet.Range['TestCell', EmptyParam].Value;
3: Value := IWorkbook.Names.Item(’TestCell’, EmptyParam,
EmptyParam).RefersToRange.Value;
end;
ShowMessage(Value);
finally
ISheet := nil;
end;
except
raise Exception.Create(’Не могу прочитать данные!’);
end;
end;
На главную форму проекта я добавил кнопку, по которой можно прочитать данные из ячейки “А2″ открытой книги, и RadioGroup к ней, чтобы выбрать способ получения этих данных. Из приведенного кода видна одна из “гнуснейших” моих привычек - освобождать все полученные интерфейсы явно (ISheet := nil). Я не могу побороть ее уже долгое время, поэтому прошу прощения у мастеров программирования на Delphi за то, что эта строчка здесь абсолютно лишняя.
Самый повторяющийся вопрос в моей почте, это вопрос о Cells. Почему-то многие уверены, что конструкция Cells[x, y].Value должна работать. В VBA это так. Но при раннем связывании это не соответствует истине. Свойство Cells объявлено у всех интерфейсов как
property Cells: Range read Get_Cells;
Отсюда видно, что это область (Range). И нет там никаких индексов, чтобы пробовать писать [x, y]. Один из корреспондентов мне написал, что он как-то обращался с этой проблемой к Наталье Елмановой, и она ему не помогла, написав, что “есть предположение, что кодогенератор Delphi их как-то не так “переваривает”, генерируя XXX_TLB.pas, но полной уверенности нет”. А дело в том, что “кодогенератор” правильно генерирует свойства _Defaul и Item (у многих интерфейсов в Excel Type Library есть такое свойство) у интерфейса Range. Вот только свойство _Default должно быть свойством по умолчанию. Поэтому стандартное объявление этих свойств
property _Default[RowIndex: OleVariant; ColumnIndex: OleVariant]: OleVariant dispid 0;
property Item[RowIndex: OleVariant; ColumnIndex: OleVariant]: OleVariant dispid 170;
можно исправить на такой вариант
property _Default[RowIndex: OleVariant; ColumnIndex: OleVariant]: OleVariant dispid 0; default;
property Item[RowIndex: OleVariant; ColumnIndex: OleVariant]: OleVariant dispid 170;
и смело писать Cells[x, y].Value.
Понятное дело, что это нехорошо - редактировать код, полученный автоматически из умного “кодогенератора” Delphi. Но “Там”, ведь, тоже люди работают и ошибаются они не реже наших. Кстати, в импортированной Excel Type Library (независимо от версии Delphi - 4 или 5) некоторые свойства, имеющие dispid 0, почему-то все-таки объявлены как default. Почему?!
В приведенном выше примере кода я показал не только использование Cells. К ячейкам можно получить доступ и через свойство Range интерфейса Worksheet. Это свойство объявлено как
property Range[Cell1: OleVariant; Cell2: OleVariant]: Range read Get_Range;
В Cell1 / Cell2 можно передать ячейки (только в формате А1, RC вызовет исключение), описывающие границы области - левый верхний угол и правый нижний. Я же использовал только указание одной ячейки, мне необходимой. Где-то в Рунете я встретил предположение о том, что, если передать в оба параметра “A1″, то в выбранный Range попадет вся колонка. Сначала я подумал, - “А почему не вся строка?!” Но, решил, все-таки проверить это предположение - в область попала одна ячейка.
В Excel можно присваивать имена любым ячейкам и даже наборам ячеек. Это можно сделать, либо используя “комбо-бокс”, который находится левее строки формул, либо пункт меню “Вставка\Имя\Присвоить”. Ячейке “А2″ я присвоил имя “TestCell” и, используя все то же свойство Range листа, получил значение ячейки по этому имени.
И последний вариант, без которого я не смог бы обойтись при создании всех своих отчетов, это использование коллекции Names книги. Не смотря на некоторую неуклюжесть кода, этот способ я использую довольно часто. Почему? Потому, что очень часто использую именованные ячейки и области, разбросанные по разным листам и даже книгам. Но останавливаться на нем смысла не вижу, оставляя благодарному читателю возможность обратиться непосредственно к первоисточнику - справке по Excel VBA.
Январь
15,
2008
— Рубрика: Delphi
Метки: Excel VBA, данные, ячейки
