Содержание
- Чтение данных из Excel
- Быстрая обработка данных Excel в Delphi
- Чтение данных из Excel
Чтение данных из Excel
Вначале рассмотрим вариант чтения данных использованием которого грешат те, кто только начинает свое знакомство с Excel в Delphi — чтение данных из каждой ячейки по отдельности. Тестовая процедура с таким вариантом чтения может выглядеть следующим образом: Счётчик будет в итоге содержать время чтения и вывода в StringGrid данных.
Для теста этого варианта был создан лист Excel, содержащий 143 строки и 142 столбца с данными, т.е. 20306 ячеек с данными.
На время чтения ушло 12 секунд.
12 секунд на чтение…а если будет 1000 строк и 1000 столбцов? Так можно и не дождаться окончания операции.
Если внимательно посмотреть на процедуру, представленную выше, то можно видеть, что в цикле мы каждый раз при каждой итерации вначале получаем диапазон, занятый данными, затем в этом диапазоне получаем определенную ячейку и только потом считываем значение в ячейке. На самом деле столько лишних операций для чтения данных с листа не требуется. Тем более, когда данные располагаются непрерывным массивом. Более выгодным в этом случае вариантом чтения будет чтение данных сразу из всего диапазона в массив.
На деле реализация этого варианты работы окажется даже проще, чем представленного выше. Смотрите сами. Вот вариант чтения данных целым диапазоном: Здесь мы ввели всего одну переменную FData типа Variant. В эту переменную мы прочитали за 1 операцию весь диапазон, занятый данными. После того как диапазон прочитан FData будет содержать матрицу, каждый элемент которой будет типом данных, определенным в Excel.
Время выполнения операции 0.022 секунды!
Как видите, прирост скорости оказался колоссальным, учитывая даже то, что в счётчик попало время обновления StringGrid’а.
Источник
Быстрая обработка данных Excel в Delphi
Праздники ещё не закончились, работать лень, но надо как-то уже прекращать заниматься кишкоблудством и начинать работать в полную силу. Ну, а чтобы как-то себя расшевелить и начать уже работу в блоге, решил первый пост сделать простым — снова сказать несколько слов про Excel . Дело в том, что с момента выхода поста под названием «Работа с Excel в Delphi . Основы основ.» прошло практически полтора года и этот пост (почему-то вопреки всем ожиданиям) очень прочно закрепился в выдаче поисковиков. Это, конечно хорошо, но этот пост (читай название) дает лишь небольшое представление о том как работать с Excel в Delphi . Никто ведь не изучает сразу квантовую механику с первого класса? Сначала учимся основам вообще — математика, физика и т.д. Так я решил поступить в начале рассказа про Excel — сначала дать общее представление, а потом по-тихоньку раскрывать тему более подробно и детально. Но поисковики немного спутали карты, подняв пост выше других про Excel . Соответственно, те из посетителей, кто уже имеют представление о работе с Excel, видя представленные в статье примеры, возмущаются по поводу того, что чтение данных в этом случае будет происходить медленно. И я не спорю, да проход по каждой ячейке листа — это жуткие тормоза. А ускорить процесс чтения можно и необходимо. Поэтому можно считать, что эта статья — расширение к основам.
За полтора года мне предлагали кучу вариантов того как ускорить чтение данных с листа Excel — от использования MSXML и других готовых библиотек до самопальных процедур и функций. Что ж, любую задачу можно решить несколькими способами. Рассмотрим несколько вариантов и определимся какой из вариантов окажется наиболее быстрым. Ну, а какой вариант окажется более удобным — это уже каждый решит для себя сам.
Чтение данных из Excel
Вначале рассмотрим вариант чтения данных использованием которого грешат те, кто только начинает свое знакомство с Excel в Delphi — чтение данных из каждой ячейки по отдельности. Тестовая процедура с таким вариантом чтения может выглядеть следующим образом:
procedure TForm16.SlowVariant;
var Rows, Cols, i,j: integer;
WorkSheet: OLEVariant;
d: TDateTime;
begin
//открываем книгу
ExcelApp.Workbooks.Open(edFile.Text);
//получаем активный лист
WorkSheet:=ExcelApp.ActiveWorkbook.ActiveSheet;
//определяем количество строк и столбцов таблицы
Rows:=WorkSheet.UsedRange.Rows.Count;
Cols:=WorkSheet.UsedRange.Columns.Count;
StringGrid1.RowCount:=Rows;
StringGrid1.ColCount:=Cols;
//засекаем время начала чтения
d:=Now;
//выводим данные в таблицу
for I := 0 to Rows-1 do
for j := 0 to Cols-1 do
StringGrid1.Cells[J,I]:=WorkSheet.UsedRange.Cells[I+1,J+1].Value;
Label2.Caption:=’Время чтения всего листа: ‘+FormatDateTime(‘hh:mm:ss:zzz’,
Now()-d);
end;
Счётчик будет в итоге содержать время чтения и вывода в StringGrid данных. Можно было бы сделать счётчик исключительно на чтение данных с листа, но я решил не перегружать исходник лишними переменными. Если будет желание — можете переписать чуть-чуть исходник и получить «чистое» время чтения.
Для теста этого варианта был создан лист Excel, содержащий 143 строки и 142 столбца с данными, т.е. 20306 ячеек с данными. На рисунке ниже представлено значение счётчика после чтения данных:
12 секунд на чтение. а если будет 1000 строк и 1000 столбцов? Так можно и не дождаться окончания операции.
Если внимательно посмотреть на процедуру, представленную выше, то можно видеть, что в цикле мы каждый раз при каждой итерации вначале получаем диапазон, занятый данными, затем в этом диапазоне получаем определенную ячейку и только потом считываем значение в ячейке. На самом деле столько лишних операций для чтения данных с листа не требуется. Тем более, когда данные располагаются непрерывным массивом. Более выгодным в этом случае вариантом чтения будет чтение данных сразу из всего диапазона в массив.
На деле реализация этого варианты работы окажется даже проще, чем представленного выше. Смотрите сами. Вот вариант чтения данных целым диапазоном:
procedure TForm16.RangeRead;
var Rows, Cols, i,j: integer;
WorkSheet: OLEVariant;
FData: OLEVariant;
d: TDateTime;
begin
//открываем книгу
ExcelApp.Workbooks.Open(edFile.Text);
//получаем активный лист
WorkSheet:=ExcelApp.ActiveWorkbook.ActiveSheet;
//определяем количество строк и столбцов таблицы
Rows:=WorkSheet.UsedRange.Rows.Count;
Cols:=WorkSheet.UsedRange.Columns.Count;
//считываем данные всего диапазона
FData:=WorkSheet.UsedRange.Value;
//засекаем время начала чтения
d:=Now;
//выводим данные в таблицу
for I := 0 to Rows-1 do
for j := 0 to Cols-1 do
StringGrid1.Cells[J,I]:=FData[I+1,J+1];
Label2.Caption:=’Время чтения всего листа: ‘+FormatDateTime(‘hh:mm:ss:zzz’,
Now()-d);
end;
Здесь мы ввели всего одну переменную FData типа Variant. В эту переменную мы прочитали за 1 операцию весь диапазон, занятый данными. После того как диапазон прочитан FData будет содержать матрицу, каждый элемент которой будет типом данных, определенным в Excel.
Смотрим на время выполнения операции:
Как видите, прирост скорости оказался колоссальным, учитывая даже то, что в счётчик попало время обновления StringGrid’а.
Здесь было бы уместно показать и обратный метод работы с Excel, т.е. запись данных на лист Excel с использованием вариантного массива.
Запись данных в Excel
В случае, если нам необходимо записать большой объем данных на лист Excel нам необходимо провести обратную операцию, т.е. вначале создать вариантный массив, затем записать в этот массив данные после чего записать весь массив одной операцией в Excel. Для примера я написал процедуру, которая считывает большой объем данных из StringGrid и записывает эти данные на второй лист открытой книги Excel:
procedure TForm16.WriteData;
var i,j: integer;
FData: Variant;
Sheet,Range: Variant;
begin
//создаем вариантный массив
FData:=VarArrayCreate([1,StringGrid1.RowCount,1,StringGrid1.ColCount],varVariant);
//заполняем массив данными из StringGrid
for i:=1 to VarArrayHighBound(FData,1) do
for j:=1 to VarArrayHighBound(FData,2) do
FData[i,j]:=StringGrid1.Cells[J-1,I-1];
<активируем второй лист книги>
//открываем книгу
ExcelApp.Workbooks.Open(edFile.Text);
//активируем
Sheet:=ExcelApp.ActiveWorkBook.Sheets[2];
Sheet.Activate;
//выделяем диапазон для вставки данных
Range:=Sheet.Range[Sheet.Cells[1,1],Sheet.Cells[VarArrayHighBound(FData,1),VarArrayHighBound(FData,2)]];
//вставляем данные
Range.Value:=FData;
//показываем окно Excel
ExcelApp.Visible:=True;
end;
Здесь мы вначале создаем двумерный вариантный массив, используя метод VarArrayCreate, после чего заполняем массив данным и передаем этот массив в Excel. Обратите внимание, что при записи в Excel не используются никакие циклы — запись происходит в 2 простых действия:
выделяем диапазон, используя в качестве границ диапазона первую и последнюю ячейки
присваиваем диапазону значение из массива.
Для полноты картины ниже на рисунке представлено значение счётчика, который отсчитал время от момента создания массива до активации приложения Excel включительно:
Естественно, что с ростом объема данных будет расти и время выполнения операции. Так, например, лист, содержащий 1000 строк и 256 столбцов с данными заполнялся около 7 секунд. Если для Вас такое время неприемлемо, то представленная выше процедура может быть немного ускорена использованием пары методов VarArrayLock() и VarArrayUnLock(), но при этом следует учитывать, что матрица FData будет транспонирована.
Что ещё стоит сказать по поводу чтения/записи данных в Excel ? Наверное то, что предложенные выше методы работы в обязательном порядке требуют наличия установленного Excel на том компьютере где запускается Ваша программа. В связи с этим обстоятельством может потребоваться более универсальный способ работы с Excel. Здесь, опять же, может быть несколько вариантов работы, но я покажу, а точнее укажу только на один из них — с использованием библиотека XLSReadWrite.
Про эту библиотеку мне поведал один из читателей блога в комментарии как раз-таки к посту «»Работа с Excel в Delphi. Основы основ». Чтобы лишний раз Вас не переправлять на комментарий с примером использования этой библиотеки, я с разрешения GS (ник автора кода) просто опубликую здесь уже готовые примеры использования библиотеки XLSReadWrite:
Упрощенный пример для Delphi 7
var
IntlXls: TXLSReadWriteII2;
I, J: Integer;
begin
// создаем объект
IntlXls := TXLSReadWriteII2.Create(nil);
// название книги
IntlXls.Sheets[0].Name := » Название моего отчета «;
// добавляем необходимое количество строк и колонок
IntlXls.Sheets[0].Rows.AddIfNone(0, 10000);
IntlXls.Sheets[0].Columns.AddIfNone(0, 100);
// добавляем и заносим ширины ячеек (значение в пикселях)
for I := 0 to 99 do
IntlXls.Sheets[0].Columns[I].PixelWidth := 150;
// заносим высоты строк (значение здесь не в пикселях, поэтому нужно корректировать)
for I := 0 to 9999 do
IntlXls.Sheets[0].Rows[I].Height := 20 * 14;
// настраиваем
for J := 0 to 9999 do
for I := 0 to 99 do
begin
// заносим числовое значение
// если нужно например занести строку, то использовать AsString
IntlXls.Sheets[0].AsFloat[I, J] := J + I / 100;
// выравнивание по горизонтали (доступно chaLeft, chaCenter, chaRight)
IntlXls.Sheets[0].Cell[I, J].HorizAlignment := chaLeft;
// выравнивание по вертикали (доступно cvaTop, cvaCenter, cvaBottom)
IntlXls.Sheets[0].Cell[I, J].VertAlignment := cvaTop;
// шрифт
IntlXls.Sheets[0].Cell[I, J].FontName := » Arial «;
IntlXls.Sheets[0].Cell[I, J].FontSize := 12;
IntlXls.Sheets[0].Cell[I, J].FontStyle := [];
IntlXls.Sheets[0].Cell[I, J].FontColor := TColorToClosestXColor(clBlue);
IntlXls.Sheets[0].Cell[I, J].Rotation := 0;
// жирное начертание
with IntlXls.Sheets[0].Cell[I, J] do
FontStyle := FontStyle + [xfsBold];
// наклонное начертание
with IntlXls.Sheets[0].Cell[I, J] do
FontStyle := FontStyle + [xfsItalic];
// цвет фона
IntlXls.Sheets[0].Cell[I, J].FillPatternForeColor :=
TColorToClosestXColor(clYellow);
// бордюр слева (аналогично и остальные бордюры)
IntlXls.Sheets[0].Cell[I, J].BorderLeftColor :=
TColorToClosestXColor(clBlack);
IntlXls.Sheets[0].Cell[I, J].BorderLeftStyle := cbsThin;
// объединение ячеек (здесь объединяются две ячейки по горизонтали)
if I = 49 then
IntlXls.Sheets[0].MergedCells.Add(I, J, I + 1, J);
end;
IntlXls.SaveToFile(» c: demo.xls «);
IntlXls.Free;
end;
Полный пример работы с библиотекой:
function ExportToExcelXls(var AFileName: string): Integer;
var
IntlXls: TXLSReadWriteII2;
IntlCol: Integer;
IntlRow: Integer;
IntlMainCol: Integer;
IntlMainRow: Integer;
begin
// инициализируем статус
prgrbrStatus.Max := FLinkReport.RowCount;
prgrbrStatus.Position := 0;
pnlStatus.Visible := TRUE;
pnlStatus.Refresh;
// добавлено в конце имени файла расширение «.XLS»?
if Length(AFileName) 0
then
// добавляем
AFileName := AFileName + «.xls «;
// файл уже существует?
if FileExists(AFileName) then
// спросим
if Application.MessageBox
(PChar(» Файл » » + AFileName + » » уже существует.Перезаписать ? «),
» Внимание «, MB_TASKMODAL + MB_ICONQUESTION + MB_YESNO + MB_DEFBUTTON2)
<> IDYES then
// выходим
begin
// код ошибки
Result := UNIRPT_GENERATE_ABORT;
// выходим
Exit;
end; // if
// создаем объект
IntlXls := TXLSReadWriteII2.Create(nil);
// все делаем защищаясь
try
// название книги
IntlXls.Sheets[0].Name := FLinkReport.Caption;
// добавляем необходимое количество строк и колонок
IntlXls.Sheets[0].Rows.AddIfNone(0, FLinkReport.Cells.RowCount + 1);
IntlXls.Sheets[0].Columns.AddIfNone(0, FLinkReport.Cells.ColCount + 1);
// добавляем и заносим ширины ячеек
for IntlCol := 0 to FLinkReport.Cells.ColCount — 1 do
IntlXls.Sheets[0].Columns[IntlCol].PixelWidth :=
FLinkReport.ColWidths[IntlCol];
// заносим высоты строк
for IntlRow := 0 to FLinkReport.Cells.RowCount — 1 do
IntlXls.Sheets[0].Rows[IntlRow].Height := FLinkReport.RowHeights
[IntlRow] * 14;
// проходим по всем строкам
for IntlRow := 0 to FLinkReport.Cells.RowCount — 1 do
begin
// проходим по всем колонкам
for IntlCol := 0 to FLinkReport.Cells.ColCount — 1 do
begin
// определяем главную ячейку
IntlMainCol := IntlCol + FLinkReport.Cells[IntlCol, IntlRow].Range.Left;
IntlMainRow := IntlRow + FLinkReport.Cells[IntlCol, IntlRow].Range.Top;
// заносим оформление
with FLinkReport.Cells[IntlMainCol, IntlMainRow] do
begin
// главная ячейка?
if (IntlMainCol = IntlCol) and (IntlMainRow = IntlRow) then
// да, заносим текст и его оформление
begin
// значение
try
// если значение — число то заносим его как число
IntlXls.Sheets[0].AsFloat[IntlCol, IntlRow] := StrToFloat(Value);
except
// иначе заносим его как строку
IntlXls.Sheets[0].AsString[IntlCol, IntlRow] := Value;
end;
// выравнивание по горизонтали
case HorizAlign of
haLeft:
// выравнивание слева
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].HorizAlignment
:= chaLeft;
haCenter:
// выравнивание по центру
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].HorizAlignment :=
chaCenter;
haRight:
// выравнивание справа
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].HorizAlignment
:= chaRight;
end; // case
// выравнивание по вертикали
case VertAlign of
vaTop:
// выравнивание сверху
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].VertAlignment
:= cvaTop;
vaCenter:
// выравнивание в центре
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].VertAlignment :=
cvaCenter;
vaBottom:
// выравнивание снизу
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].VertAlignment :=
cvaBottom;
end; // case
// шрифт
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FontName := Font.Name;
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FontSize := Font.Size;
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FontCharset :=
Font.Charset;
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FontStyle := [];
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FontColor :=
TColorToClosestXColor(Font.Color);
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].Rotation := Font.Angle;
// есть жирное начертание?
if Font.IsBold then
// есть
with IntlXls.Sheets[0].Cell[IntlCol, IntlRow] do
FontStyle := FontStyle + [xfsBold];
// есть наклонное начертание?
if Font.IsItalic then
// есть
with IntlXls.Sheets[0].Cell[IntlCol, IntlRow] do
FontStyle := FontStyle + [xfsItalic];
// цвет фона
if Color <> clWindow then
// цвет задан
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FillPatternForeColor :=
TColorToClosestXColor(Color);
end // if
else
// просто активизируем ячейку (иначе ниже невозможно добавить бордюры)
IntlXls.Sheets[0].AsString[IntlCol, IntlRow] := «;
// бордюр слева есть?
with Borders.Left do
if LineHeight > 0 then
// настраиваем
begin
// цвет
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderLeftColor :=
TColorToClosestXColor(Color);
// толщина
if LineHeight = 1 then
// тонка
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderLeftStyle
:= cbsThin
else if LineHeight in [1, 2] then
// средняя толщина
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderLeftStyle :=
cbsMedium
else
// толстая
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderLeftStyle
:= cbsHair;
end; // if, with
// бордюр сверху есть?
with Borders.Top do
if LineHeight > 0 then
// настраиваем
begin
// цвет
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderTopColor :=
TColorToClosestXColor(Color);
// толщина
if LineHeight = 1 then
// тонка
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderTopStyle
:= cbsThin
else if LineHeight in [1, 2] then
// средняя толщина
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderTopStyle :=
cbsMedium
else
// толстая
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderTopStyle
:= cbsHair;
end; // if, with
// бордюр справа есть?
with Borders.Right do
if LineHeight > 0 then
// настраиваем
begin
// цвет
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderRightColor :=
TColorToClosestXColor(Color);
// толщина
if LineHeight = 1 then
// тонка
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderRightStyle
:= cbsThin
else if LineHeight in [1, 2] then
// средняя толщина
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderRightStyle :=
cbsMedium
else
// толстая
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderRightStyle
:= cbsHair;
end; // if, with
// бордюр снизу есть?
with Borders.Bottom do
if LineHeight > 0 then
// настраиваем
begin
// цвет
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderBottomColor :=
TColorToClosestXColor(Color);
// толщина
if LineHeight = 1 then
// тонка
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderBottomStyle
:= cbsThin
else if LineHeight in [1, 2] then
// средняя толщина
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderBottomStyle :=
cbsMedium
else
// толстая
IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderBottomStyle
:= cbsHair;
end; // if, with
// объединение нужно?
if ((Range.Width > 1) or (Range.Height > 1)) and
((IntlMainCol = IntlCol) and (IntlMainRow = IntlRow)) then
// объединяем
IntlXls.Sheets[0].MergedCells.Add(IntlCol, IntlRow,
IntlCol + Range.Width — 1, IntlRow + Range.Height — 1);
// пользователь нажал кнопку прерывания экспорта?
if btnCancel.Tag = 2 then
// да, выходим
Break;
end; // with
end; // for
// обновляем статус
prgrbrStatus.Position := prgrbrStatus.Position + 1;
Application.ProcessMessages;
// пользователь нажал кнопку прерывания экспорта?
if btnCancel.Tag = 2 then
// да, выходим
Break;
end; // for
// пользователь нажал кнопку прерывания экспорта?
if btnCancel.Tag <> 2 then
// нет
begin
// на левый верхний угол
IntlXls.Sheet[0].TopRow := 0;
IntlXls.Sheet[0].LeftCol := 0;
IntlXls.Sheet[0].Selection.ActiveRow := 0;
IntlXls.Sheet[0].Selection.ActiveCol := 0;
// статус
prgrbrStatus.Position := prgrbrStatus.Max;
Application.ProcessMessages;
// записываем в файл
IntlXls.FileName := AFileName;
IntlXls.Write;
// все успешно
Result := UNIRPT_OK;
end // if
else
// да
Result := UNIRPT_GENERATE_ABORT;
finally
// освобождаем память
IntlXls.Free;
end; // try..finally
end; // function ExportToExcelXls
Вот такой подробный пример предоставил нам GS в своем комментарии. Спасибо ему за это. Мне же в заключении остается только добавить и подчеркнуть, что самые правильные ответы и примеры к вопросам, касающимся работы с Excel содержаться в Справке для разработчиков в самом Excel и надо только воспользоваться поиском. Например, если вам довольно часто приходится перетаскивать данные из базы данных в Excel и в работе используется ADO, то специально для таких случаев в справке рассказывается про интересный метод объекта Range под названием CopyFromRecordset, а если вам надо разукрасить свою таблицу Excel в разные цвета и установить разные виды границ ячеек, то специально для таких случаев в справке приводится подробные перечень всех перечислителей Excel’я. В общем много чего есть — надо только этим воспользоваться и все получится. Ну, а если не получится, то милости прошу — задавайте вопросы здесь или на нашем форуме.
Источник
Вначале рассмотрим вариант чтения данных использованием которого грешат те, кто только начинает свое знакомство с Excel в Delphi — чтение данных из каждой ячейки по отдельности. Тестовая процедура с таким вариантом чтения может выглядеть следующим образом:
procedure TForm16.SlowVariant; var Rows, Cols, i,j: integer; WorkSheet: OLEVariant; d: TDateTime; begin //открываем книгу ExcelApp.Workbooks.Open(edFile.Text); //получаем активный лист WorkSheet:=ExcelApp.ActiveWorkbook.ActiveSheet; //определяем количество строк и столбцов таблицы Rows:=WorkSheet.UsedRange.Rows.Count; Cols:=WorkSheet.UsedRange.Columns.Count; StringGrid1.RowCount:=Rows; StringGrid1.ColCount:=Cols; //засекаем время начала чтения d:=Now; //выводим данные в таблицу for I := 0 to Rows-1 do for j := 0 to Cols-1 do StringGrid1.Cells[J,I]:=WorkSheet.UsedRange.Cells[I+1,J+1].Value; Label2.Caption:='Время чтения всего листа: '+FormatDateTime('hh:mm:ss:zzz', Now()-d); end;
Счётчик будет в итоге содержать время чтения и вывода в StringGrid данных.
Для теста этого варианта был создан лист Excel, содержащий 143 строки и 142 столбца с данными, т.е. 20306 ячеек с данными.
На время чтения ушло 12 секунд.
12 секунд на чтение…а если будет 1000 строк и 1000 столбцов? Так можно и не дождаться окончания операции.
Если внимательно посмотреть на процедуру, представленную выше, то можно видеть, что в цикле мы каждый раз при каждой итерации вначале получаем диапазон, занятый данными, затем в этом диапазоне получаем определенную ячейку и только потом считываем значение в ячейке. На самом деле столько лишних операций для чтения данных с листа не требуется. Тем более, когда данные располагаются непрерывным массивом. Более выгодным в этом случае вариантом чтения будет чтение данных сразу из всего диапазона в массив.
На деле реализация этого варианты работы окажется даже проще, чем представленного выше. Смотрите сами. Вот вариант чтения данных целым диапазоном:
procedure TForm16.RangeRead; var Rows, Cols, i,j: integer; WorkSheet: OLEVariant; FData: OLEVariant; d: TDateTime; begin //открываем книгу ExcelApp.Workbooks.Open(edFile.Text); //получаем активный лист WorkSheet:=ExcelApp.ActiveWorkbook.ActiveSheet; //определяем количество строк и столбцов таблицы Rows:=WorkSheet.UsedRange.Rows.Count; Cols:=WorkSheet.UsedRange.Columns.Count; //считываем данные всего диапазона FData:=WorkSheet.UsedRange.Value; StringGrid1.RowCount:=Rows; StringGrid1.ColCount:=Cols; //засекаем время начала чтения d:=Now; //выводим данные в таблицу for I := 0 to Rows-1 do for j := 0 to Cols-1 do StringGrid1.Cells[J,I]:=FData[I+1,J+1]; Label2.Caption:='Время чтения всего листа: '+FormatDateTime('hh:mm:ss:zzz', Now()-d); end;
Здесь мы ввели всего одну переменную FData типа Variant. В эту переменную мы прочитали за 1 операцию весь диапазон, занятый данными. После того как диапазон прочитан FData будет содержать матрицу, каждый элемент которой будет типом данных, определенным в Excel.
Время выполнения операции 0.022 секунды!
Как видите, прирост скорости оказался колоссальным, учитывая даже то, что в счётчик попало время обновления StringGrid’а.
Вот и всё, Удачи!
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Праздники ещё не закончились, работать лень, но надо как-то уже прекращать заниматься кишкоблудством и начинать работать в полную силу. Ну, а чтобы как-то себя расшевелить и начать уже работу в блоге, решил первый пост сделать простым — снова сказать несколько слов про Excel. Дело в том, что с момента выхода поста под названием «Работа с Excel в Delphi. Основы основ.» прошло практически полтора года и этот пост (почему-то вопреки всем ожиданиям) очень прочно закрепился в выдаче поисковиков. Это, конечно хорошо, но этот пост (читай название) дает лишь небольшое представление о том как работать с Excel в Delphi. Никто ведь не изучает сразу квантовую механику с первого класса? Сначала учимся основам вообще — математика, физика и т.д. Так я решил поступить в начале рассказа про Excel — сначала дать общее представление, а потом потихоньку раскрывать тему более подробно и детально. Но поисковики немного спутали карты, подняв пост выше других про Excel. Соответственно, те из посетителей, кто уже имеют представление о работе с Excel, видя представленные в статье примеры, возмущаются по поводу того, что чтение данных в этом случае будет происходить медленно. И я не спорю, да проход по каждой ячейке листа — это жуткие тормоза. А ускорить процесс чтения можно и необходимо. Поэтому можно считать, что эта статья — расширение к основам.
За полтора года мне предлагали кучу вариантов того как ускорить чтение данных с листа Excel — от использования MSXML и других готовых библиотек до самопальных процедур и функций. Что ж, любую задачу можно решить несколькими способами. Рассмотрим несколько вариантов и определимся какой из вариантов окажется наиболее быстрым. Ну, а какой вариант окажется более удобным — это уже каждый решит для себя сам.
Вначале рассмотрим вариант чтения данных использованием которого грешат те, кто только начинает свое знакомство с Excel в Delphi — чтение данных из каждой ячейки по отдельности. Тестовая процедура с таким вариантом чтения может выглядеть следующим образом:
procedure TForm16.SlowVariant; var Rows, Cols, i,j: integer; WorkSheet: OLEVariant; d: TDateTime; begin //открываем книгу ExcelApp.Workbooks.Open(edFile.Text); //получаем активный лист WorkSheet:=ExcelApp.ActiveWorkbook.ActiveSheet; //определяем количество строк и столбцов таблицы Rows:=WorkSheet.UsedRange.Rows.Count; Cols:=WorkSheet.UsedRange.Columns.Count; StringGrid1.RowCount:=Rows; StringGrid1.ColCount:=Cols; //засекаем время начала чтения d:=Now; //выводим данные в таблицу for I := 0 to Rows-1 do for j := 0 to Cols-1 do StringGrid1.Cells[J,I]:=WorkSheet.UsedRange.Cells[I+1,J+1].Value; Label2.Caption:='Время чтения всего листа: '+FormatDateTime('hh:mm:ss:zzz', Now()-d); end;
Счётчик будет в итоге содержать время чтения и вывода в StringGrid данных. Можно было бы сделать счётчик исключительно на чтение данных с листа, но я решил не перегружать исходник лишними переменными. Если будет желание — можете переписать чуть-чуть исходник и получить «чистое» время чтения.
Для теста этого варианта был создан лист Excel, содержащий 143 строки и 142 столбца с данными, т.е. 20306 ячеек с данными. На рисунке ниже представлено значение счётчика после чтения данных:
12 секунд на чтение…а если будет 1000 строк и 1000 столбцов? Так можно и не дождаться окончания операции.
Если внимательно посмотреть на процедуру, представленную выше, то можно видеть, что в цикле мы каждый раз при каждой итерации вначале получаем диапазон, занятый данными, затем в этом диапазоне получаем определенную ячейку и только потом считываем значение в ячейке. На самом деле столько лишних операций для чтения данных с листа не требуется. Тем более, когда данные располагаются непрерывным массивом. Более выгодным в этом случае вариантом чтения будет чтение данных сразу из всего диапазона в массив.
На деле реализация этого варианты работы окажется даже проще, чем представленного выше. Смотрите сами. Вот вариант чтения данных целым диапазоном:
procedure TForm16.RangeRead; var Rows, Cols, i,j: integer; WorkSheet: OLEVariant; FData: OLEVariant; d: TDateTime; begin //открываем книгу ExcelApp.Workbooks.Open(edFile.Text); //получаем активный лист WorkSheet:=ExcelApp.ActiveWorkbook.ActiveSheet; //определяем количество строк и столбцов таблицы Rows:=WorkSheet.UsedRange.Rows.Count; Cols:=WorkSheet.UsedRange.Columns.Count; //считываем данные всего диапазона FData:=WorkSheet.UsedRange.Value; StringGrid1.RowCount:=Rows; StringGrid1.ColCount:=Cols; //засекаем время начала чтения d:=Now; //выводим данные в таблицу for I := 0 to Rows-1 do for j := 0 to Cols-1 do StringGrid1.Cells[J,I]:=FData[I+1,J+1]; Label2.Caption:='Время чтения всего листа: '+FormatDateTime('hh:mm:ss:zzz', Now()-d); end;
Здесь мы ввели всего одну переменную FData типа Variant. В эту переменную мы прочитали за 1 операцию весь диапазон, занятый данными. После того как диапазон прочитан FData будет содержать матрицу, каждый элемент которой будет типом данных, определенным в Excel.
Смотрим на время выполнения операции:
Как видите, прирост скорости оказался колоссальным, учитывая даже то, что в счётчик попало время обновления StringGrid’а.
Здесь было бы уместно показать и обратный метод работы с Excel, т.е. запись данных на лист Excel с использованием вариантного массива.
Запись данных в Excel
В случае, если нам необходимо записать большой объем данных на лист Excel нам необходимо провести обратную операцию, т.е. вначале создать вариантный массив, затем записать в этот массив данные после чего записать весь массив одной операцией в Excel. Для примера я написал процедуру, которая считывает большой объем данных из StringGrid и записывает эти данные на второй лист открытой книги Excel:
procedure TForm16.WriteData; var i,j: integer; FData: Variant; Sheet,Range: Variant; begin //создаем вариантный массив FData:=VarArrayCreate([1,StringGrid1.RowCount,1,StringGrid1.ColCount],varVariant); //заполняем массив данными из StringGrid for i:=1 to VarArrayHighBound(FData,1) do for j:=1 to VarArrayHighBound(FData,2) do FData[i,j]:=StringGrid1.Cells[J-1,I-1]; {активируем второй лист книги} //открываем книгу ExcelApp.Workbooks.Open(edFile.Text); //активируем Sheet:=ExcelApp.ActiveWorkBook.Sheets[2]; Sheet.Activate; //выделяем диапазон для вставки данных Range:=Sheet.Range[Sheet.Cells[1,1],Sheet.Cells[VarArrayHighBound(FData,1),VarArrayHighBound(FData,2)]]; //вставляем данные Range.Value:=FData; //показываем окно Excel ExcelApp.Visible:=True; end;
Здесь мы вначале создаем двумерный вариантный массив, используя метод VarArrayCreate, после чего заполняем массив данным и передаем этот массив в Excel. Обратите внимание, что при записи в Excel не используются никакие циклы — запись происходит в 2 простых действия:
- выделяем диапазон, используя в качестве границ диапазона первую и последнюю ячейки
- присваиваем диапазону значение из массива.
Для полноты картины ниже на рисунке представлено значение счётчика, который отсчитал время от момента создания массива до активации приложения Excel включительно:
Естественно, что с ростом объема данных будет расти и время выполнения операции. Так, например, лист, содержащий 1000 строк и 256 столбцов с данными заполнялся около 7 секунд. Если для Вас такое время неприемлемо, то представленная выше процедура может быть немного ускорена использованием пары методов VarArrayLock() и VarArrayUnLock(), но при этом следует учитывать, что матрица FData будет транспонирована.
Что ещё стоит сказать по поводу чтения/записи данных в Excel? Наверное то, что предложенные выше методы работы в обязательном порядке требуют наличия установленного Excel на том компьютере где запускается Ваша программа. В связи с этим обстоятельством может потребоваться более универсальный способ работы с Excel. Здесь, опять же, может быть несколько вариантов работы, но я покажу, а точнее укажу только на один из них — с использованием библиотека XLSReadWrite.
Про эту библиотеку мне поведал один из читателей блога в комментарии как раз-таки к посту «»Работа с Excel в Delphi. Основы основ«. Чтобы лишний раз Вас не переправлять на комментарий с примером использования этой библиотеки, я с разрешения GS (ник автора кода) просто опубликую здесь уже готовые примеры использования библиотеки XLSReadWrite:
Упрощенный пример для Delphi 7
var IntlXls: TXLSReadWriteII2; I, J: Integer; begin // создаем объект IntlXls := TXLSReadWriteII2.Create(nil); // название книги IntlXls.Sheets[0].Name := ‘ Название моего отчета ’; // добавляем необходимое количество строк и колонок IntlXls.Sheets[0].Rows.AddIfNone(0, 10000); IntlXls.Sheets[0].Columns.AddIfNone(0, 100); // добавляем и заносим ширины ячеек (значение в пикселях) for I := 0 to 99 do IntlXls.Sheets[0].Columns[I].PixelWidth := 150; // заносим высоты строк (значение здесь не в пикселях, поэтому нужно корректировать) for I := 0 to 9999 do IntlXls.Sheets[0].Rows[I].Height := 20 * 14; // настраиваем for J := 0 to 9999 do for I := 0 to 99 do begin // заносим числовое значение // если нужно например занести строку, то использовать AsString IntlXls.Sheets[0].AsFloat[I, J] := J + I / 100; // выравнивание по горизонтали (доступно chaLeft, chaCenter, chaRight) IntlXls.Sheets[0].Cell[I, J].HorizAlignment := chaLeft; // выравнивание по вертикали (доступно cvaTop, cvaCenter, cvaBottom) IntlXls.Sheets[0].Cell[I, J].VertAlignment := cvaTop; // шрифт IntlXls.Sheets[0].Cell[I, J].FontName := ‘ Arial ’; IntlXls.Sheets[0].Cell[I, J].FontSize := 12; IntlXls.Sheets[0].Cell[I, J].FontStyle := []; IntlXls.Sheets[0].Cell[I, J].FontColor := TColorToClosestXColor(clBlue); IntlXls.Sheets[0].Cell[I, J].Rotation := 0; // жирное начертание with IntlXls.Sheets[0].Cell[I, J] do FontStyle := FontStyle + [xfsBold]; // наклонное начертание with IntlXls.Sheets[0].Cell[I, J] do FontStyle := FontStyle + [xfsItalic]; // цвет фона IntlXls.Sheets[0].Cell[I, J].FillPatternForeColor := TColorToClosestXColor(clYellow); // бордюр слева (аналогично и остальные бордюры) IntlXls.Sheets[0].Cell[I, J].BorderLeftColor := TColorToClosestXColor(clBlack); IntlXls.Sheets[0].Cell[I, J].BorderLeftStyle := cbsThin; // объединение ячеек (здесь объединяются две ячейки по горизонтали) if I = 49 then IntlXls.Sheets[0].MergedCells.Add(I, J, I + 1, J); end; IntlXls.SaveToFile(‘ c: demo.xls ’); IntlXls.Free; end;
Полный пример работы с библиотекой:
function ExportToExcelXls(var AFileName: string): Integer; var IntlXls: TXLSReadWriteII2; IntlCol: Integer; IntlRow: Integer; IntlMainCol: Integer; IntlMainRow: Integer; begin // инициализируем статус prgrbrStatus.Max := FLinkReport.RowCount; prgrbrStatus.Position := 0; pnlStatus.Visible := TRUE; pnlStatus.Refresh; // добавлено в конце имени файла расширение ‘.XLS’? if Length(AFileName) < 5 then // добавляем AFileName := AFileName + ‘.xls ’ else if AnsiCompareText(Copy(AFileName, Length(AFileName)— 3, 4), ‘.xls ’) <> 0 then // добавляем AFileName := AFileName + ‘.xls ’; // файл уже существует? if FileExists(AFileName) then // спросим if Application.MessageBox (PChar(‘ Файл « ‘ + AFileName + ‘ » уже существует.Перезаписать ? ’), ‘ Внимание ’, MB_TASKMODAL + MB_ICONQUESTION + MB_YESNO + MB_DEFBUTTON2) <> IDYES then // выходим begin // код ошибки Result := UNIRPT_GENERATE_ABORT; // выходим Exit; end; // if // создаем объект IntlXls := TXLSReadWriteII2.Create(nil); // все делаем защищаясь try // название книги IntlXls.Sheets[0].Name := FLinkReport.Caption; // добавляем необходимое количество строк и колонок IntlXls.Sheets[0].Rows.AddIfNone(0, FLinkReport.Cells.RowCount + 1); IntlXls.Sheets[0].Columns.AddIfNone(0, FLinkReport.Cells.ColCount + 1); // добавляем и заносим ширины ячеек for IntlCol := 0 to FLinkReport.Cells.ColCount — 1 do IntlXls.Sheets[0].Columns[IntlCol].PixelWidth := FLinkReport.ColWidths[IntlCol]; // заносим высоты строк for IntlRow := 0 to FLinkReport.Cells.RowCount — 1 do IntlXls.Sheets[0].Rows[IntlRow].Height := FLinkReport.RowHeights [IntlRow] * 14; // проходим по всем строкам for IntlRow := 0 to FLinkReport.Cells.RowCount — 1 do begin // проходим по всем колонкам for IntlCol := 0 to FLinkReport.Cells.ColCount — 1 do begin // определяем главную ячейку IntlMainCol := IntlCol + FLinkReport.Cells[IntlCol, IntlRow].Range.Left; IntlMainRow := IntlRow + FLinkReport.Cells[IntlCol, IntlRow].Range.Top; // заносим оформление with FLinkReport.Cells[IntlMainCol, IntlMainRow] do begin // главная ячейка? if (IntlMainCol = IntlCol) and (IntlMainRow = IntlRow) then // да, заносим текст и его оформление begin // значение try // если значение — число то заносим его как число IntlXls.Sheets[0].AsFloat[IntlCol, IntlRow] := StrToFloat(Value); except // иначе заносим его как строку IntlXls.Sheets[0].AsString[IntlCol, IntlRow] := Value; end; // выравнивание по горизонтали case HorizAlign of haLeft: // выравнивание слева IntlXls.Sheets[0].Cell[IntlCol, IntlRow].HorizAlignment := chaLeft; haCenter: // выравнивание по центру IntlXls.Sheets[0].Cell[IntlCol, IntlRow].HorizAlignment := chaCenter; haRight: // выравнивание справа IntlXls.Sheets[0].Cell[IntlCol, IntlRow].HorizAlignment := chaRight; end; // case // выравнивание по вертикали case VertAlign of vaTop: // выравнивание сверху IntlXls.Sheets[0].Cell[IntlCol, IntlRow].VertAlignment := cvaTop; vaCenter: // выравнивание в центре IntlXls.Sheets[0].Cell[IntlCol, IntlRow].VertAlignment := cvaCenter; vaBottom: // выравнивание снизу IntlXls.Sheets[0].Cell[IntlCol, IntlRow].VertAlignment := cvaBottom; end; // case // шрифт IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FontName := Font.Name; IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FontSize := Font.Size; IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FontCharset := Font.Charset; IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FontStyle := []; IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FontColor := TColorToClosestXColor(Font.Color); IntlXls.Sheets[0].Cell[IntlCol, IntlRow].Rotation := Font.Angle; // есть жирное начертание? if Font.IsBold then // есть with IntlXls.Sheets[0].Cell[IntlCol, IntlRow] do FontStyle := FontStyle + [xfsBold]; // есть наклонное начертание? if Font.IsItalic then // есть with IntlXls.Sheets[0].Cell[IntlCol, IntlRow] do FontStyle := FontStyle + [xfsItalic]; // цвет фона if Color <> clWindow then // цвет задан IntlXls.Sheets[0].Cell[IntlCol, IntlRow].FillPatternForeColor := TColorToClosestXColor(Color); end // if else // просто активизируем ячейку (иначе ниже невозможно добавить бордюры) IntlXls.Sheets[0].AsString[IntlCol, IntlRow] := »; // бордюр слева есть? with Borders.Left do if LineHeight > 0 then // настраиваем begin // цвет IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderLeftColor := TColorToClosestXColor(Color); // толщина if LineHeight = 1 then // тонка IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderLeftStyle := cbsThin else if LineHeight in [1, 2] then // средняя толщина IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderLeftStyle := cbsMedium else // толстая IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderLeftStyle := cbsHair; end; // if, with // бордюр сверху есть? with Borders.Top do if LineHeight > 0 then // настраиваем begin // цвет IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderTopColor := TColorToClosestXColor(Color); // толщина if LineHeight = 1 then // тонка IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderTopStyle := cbsThin else if LineHeight in [1, 2] then // средняя толщина IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderTopStyle := cbsMedium else // толстая IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderTopStyle := cbsHair; end; // if, with // бордюр справа есть? with Borders.Right do if LineHeight > 0 then // настраиваем begin // цвет IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderRightColor := TColorToClosestXColor(Color); // толщина if LineHeight = 1 then // тонка IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderRightStyle := cbsThin else if LineHeight in [1, 2] then // средняя толщина IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderRightStyle := cbsMedium else // толстая IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderRightStyle := cbsHair; end; // if, with // бордюр снизу есть? with Borders.Bottom do if LineHeight > 0 then // настраиваем begin // цвет IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderBottomColor := TColorToClosestXColor(Color); // толщина if LineHeight = 1 then // тонка IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderBottomStyle := cbsThin else if LineHeight in [1, 2] then // средняя толщина IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderBottomStyle := cbsMedium else // толстая IntlXls.Sheets[0].Cell[IntlCol, IntlRow].BorderBottomStyle := cbsHair; end; // if, with // объединение нужно? if ((Range.Width > 1) or (Range.Height > 1)) and ((IntlMainCol = IntlCol) and (IntlMainRow = IntlRow)) then // объединяем IntlXls.Sheets[0].MergedCells.Add(IntlCol, IntlRow, IntlCol + Range.Width — 1, IntlRow + Range.Height — 1); // пользователь нажал кнопку прерывания экспорта? if btnCancel.Tag = 2 then // да, выходим Break; end; // with end; // for // обновляем статус prgrbrStatus.Position := prgrbrStatus.Position + 1; Application.ProcessMessages; // пользователь нажал кнопку прерывания экспорта? if btnCancel.Tag = 2 then // да, выходим Break; end; // for // пользователь нажал кнопку прерывания экспорта? if btnCancel.Tag <> 2 then // нет begin // на левый верхний угол IntlXls.Sheet[0].TopRow := 0; IntlXls.Sheet[0].LeftCol := 0; IntlXls.Sheet[0].Selection.ActiveRow := 0; IntlXls.Sheet[0].Selection.ActiveCol := 0; // статус prgrbrStatus.Position := prgrbrStatus.Max; Application.ProcessMessages; // записываем в файл IntlXls.FileName := AFileName; IntlXls.Write; // все успешно Result := UNIRPT_OK; end // if else // да Result := UNIRPT_GENERATE_ABORT; finally // освобождаем память IntlXls.Free; end; // try..finally end; // function ExportToExcelXls
Вот такой подробный пример предоставил нам GS в своем комментарии. Спасибо ему за это. Мне же в заключении остается только добавить и подчеркнуть, что самые правильные ответы и примеры к вопросам, касающимся работы с Excel содержаться в Справке для разработчиков в самом Excel и надо только воспользоваться поиском. Например, если вам довольно часто приходится перетаскивать данные из базы данных в Excel и в работе используется ADO, то специально для таких случаев в справке рассказывается про интересный метод объекта Range под названием CopyFromRecordset, а если вам надо разукрасить свою таблицу Excel в разные цвета и установить разные виды границ ячеек, то специально для таких случаев в справке приводится подробные перечень всех перечислителей Excel’я. В общем много чего есть — надо только этим воспользоваться и все получится. Ну, а если не получится, то милости прошу — задавайте вопросы здесь или на нашем форуме.
Книжная полка
Название:Разработка приложений Microsoft Office 2007 в Delphi Описание Описаны общие подходы к программированию приложений MS Office. Даны программные методы реализации функций MS Excel, MS Word, MS Access и MS Outlook в среде Delphi. |
3.7
3
голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Тут иногда бывают вопросы о том, как можно из Delphi работать с документами Excel. Решил написать такую инструкцию, где рассказано об основных действиях.
Для работы с OLE нужно к строке Uses добавить модуль ComObj. Так же нужно объявить переменную типа Variant.
Delphi | ||
|
Что бы начать работу с Экселем, нужно создать OLE объект:
Ap := CreateOleObject(‘Excel.Application’);
После этого нужно либо создать новую книгу:
Ap.Workbooks.Add;
либо открыть файл:
Ap.Workbooks.Open(<имя файла>);
Что бы открыть файл только для чтения, нужно указать:
Ap.Workbooks.Open(<имя файла>,0,True);
где True и указывает, что файл открывается только для чтения.
По умолчанию окно Excel не будет отображаться… что бы оно появилось, нужно выполнить
Ap.Visible := True;
Но это желательно делать в последний момент, т.к. когда окно видимое, то все изменения в нём происходят медленнее. Поэтому, лучше оставить его невидимым, сделать там все необходимые изменения, и только после этого сделать его видимым или закрыть. Если вы его оставите невидимым, то процесс EXCEL.EXE останется висеть в памяти, даже когда будет закрыто ваше приложение.
Что бы закрыть Excel, выполните Ap.Quit или Ap.Application.Quit. Честно говоря, я не знаю, чем они отличаются.
Что бы при закрытии не выдавался запрос на сохранение файла, можно отключить сообщения:
Ap.DisplayAlerts := False;
Что бы записать или прочитать содержимое ячейки можно использовать Ap.Range[<имя ячейки>] или Ap.Cells[<позиция по Y>,<позиция по X>]
Ap.Range[‘D1’] := ‘Ляляля’;
Ap.Cells[1,4] := ‘Ляляля’;
Эти две строки выполняют одно и тоже действие: записывают строку «Ляляля» в ячейку D1
Читать значение из ячейки таким же образом:
S := Ap.Range[‘D1’];
или
S := Ap.Cells[1,4];
Так же можно записывать значение сразу в несколько ячеек… можно перечислить через точку с запятой или указать диапазон через двоеточие:
Delphi | ||
|
Изменение свойств текста
Всё это можно применять как к отдельным ячейкам, так и к группам ячеек, строк, столбцов и т.п. Я буду показывать примеры на Ap.Cells… но Вам никто не мешает использовать Ap.Range[‘D5’], Ap.Range[‘A2:E8’], Ap.Columns[‘B:F’] и т.п.
Delphi | ||
|
Изменение цвета фона ячеек:
Delphi | ||
|
Наверное, вы обращали внимание, что в новом документе появляются 3 листа (их список отображается внизу программы Excel). По умолчанию, мы работаем с активным листом (сразу после создания это первый лист). Но при желании, мы можем использовать и другие листы. Доступ к ним осуществляется с помощью Worksheets[<номер листа>]. Обратите внимание, что нумеруются они начиная с 1 (а не с 0, как привыкли все программисты).
Delphi | ||
|
Свойства страницы
Delphi | ||
|
Ниже приведён более полный список размеров бумаги из модуля ExcelXP:
Delphi | ||
|
Распечатать
Delphi | ||
|
Выделение
Excel.Range[Excel.Cells[1, 1], Excel.Cells[5, 3]].Select;
а также любые другие комбинации выбора ячейки с окончанием .select — выбор 1 или группы ячеек
С выбранными ячейками возможны следующие преобразования:
1) объединение ячеек
Excel.Selection.MergeCells:=True;
2) перенос по словам
Excel.Selection.WrapText:=True;
3) горизонтальное выравнивание
Excel.Selection.HorizontalAlignment:=3;
при присваивании значения 1 используется выравнивание по умолчанию, при 2 — выравнивание слева, 3 — по центру, 4 — справа.
4) вериткальное выравнивание
Excel.Selection.VerticalAlignment:=1;
присваиваемые значения аналогичны горизонтальному выравниванию.
5) граница для ячеек
Excel.Selection.Borders.LineStyle:=1;
При значении 1 границы ячеек рисуются тонкими сплошными линиями.
Кроме этого можно указать значения для свойства Borders, например, равное 3. Тогда установится только верхняя граница для блока выделения:
Excel.Selection.Borders[3].LineStyle:=1;
Значение свойства Borders задает различную комбинацию граней ячеек.
В обоих случаях можно использовать значения в диапазоне от 1 до 10. ]
//9 и 11 — лучшие
\\\\\\\\\\\\\\\\
Установка пароля для активной книги может быть произведена следующим образом:
Delphi | ||
|
где pass — устанавливаемый пароль на книгу.
Снятие пароля с книги аналогично, использовуем команду
Delphi | ||
|
где pass — пароль, установленный для защиты книги.
Установка и снятие пароля для активного листа книги Excel производится командами
Delphi | ||
|
где pass — пароль, установленный для защиты книги.
Вспомогательные операции в EXCEL
Удаление строк со сдвигом вверх:
Delphi | ||
|
при выполнении данных действий будут удалены строки с 5 по 15.
Установка закрепления области на активном листе Excel
Delphi | ||
|
Спасибо VampireKB за дополнения
В данном обзоре рассмотрены
основные конструкции,
позволяющие получить доступ к
книге Excel из DELPHI.
Организация доступа к книге
EXCEL
Для
взаимодействия с MS excel в
программе необходимо
использовать модуль ComObj
uses ComObj;
и объявить переменную для
доступа к MS excel следующего
типа:
var Excel:
Variant;
Инициализация
переменной Excel в простейшем
случае можно осуществить так:
Excel := CreateOleObject(‘Excel.Application’);
Создание
новой книги:
Excel.Workbooks.Add;
Открытие
существующей книги (где
path
— путь к фалу с расширением xls.):
Excel.Workbooks.Open[path];
Открытие
существующей книги только для
чтения:
Excel.Workbooks.Open[path, 0,
True];
Закрытие
Excel:
Excel.ActiveWorkbook.Close;
Excel.Application.Quit;
Блокировка
запросов (подтвеждений,
уведомлений) Excel, например,
запретить запрос на сохранение
файла:
Excel.DisplayAlerts:=False;
Отображаем
Excel на экране:
Excel.Visible := True;
или скрываем:
Excel.Visible := False;
Печать
содержимого активного листа
excel:
Excel.ActiveSheet.PrintOut;
Чтение/запись данных в EXCEL
Доступ к
ячейке в текущей книге Excel
можно осуществить следующим
образом:
Excel.Range[‘B2′]:=’Привет!’;-
для записи значения в ячейку или
s:=Excel.Range[‘B2’]; —
для чтения,
где B2
— адрес ячейки.
Или используя стиль ссылок R1C1:
Excel.Range[excel.Cells[2, 2]]:=’Привет!’;,
где [2, 2]
— координата ячейки.
Вообще, ячейке Excel можно
присваивать любое значение
(символьное, целое, дробное,
дата) при этом Excel установит
форматирование в ячейке
применяемое по умолчанию.
Формат ячеек в EXCEL
Выделить
(выбрать) группу ячеек для
последующей работы можно так:
Excel.Range[Excel.Cells[1, 1],
Excel.Cells[5, 3]].Select;
или
Excel.Range[‘A1:C5’].Select;
при этом будет выделена область
находящаяся между ячейкой A1 и
C5.
После
выполнения выделения можно
установить:
1) объединение ячеек
Excel.Selection.MergeCells:=True;
2) перенос по словам
Excel.Selection.WrapText:=True;
3) горизонтальное выравнивание
Excel.Selection.HorizontalAlignment:=3;
при присваивании значения 1
используется выравнивание по
умолчанию, при 2 — выравнивание
слева, 3 — по центру, 4 —
справа.
4) вериткальное выравнивание
Excel.Selection.VerticalAlignment:=1;
присваиваемые значения
аналогичны горизонтальному
выравниванию.
5) граница для ячеек
Excel.Selection.Borders.LineStyle:=1;
При значении 1 границы ячеек
рисуются тонкими сплошными
линиями.
Кроме этого можно указать
значения для свойства Borders,
например, равное 3. Тогда
установится только верхняя
граница для блока выделения:
Excel.Selection.Borders[3].LineStyle:=1;
Значение свойства Borders задает
различную комбинацию граней
ячеек.
В обоих случаях можно
использовать значения в
диапазоне от 1 до 10.
Использование паролей в
EXCEL
Установка
пароля для активной книги может
быть произведена следующим
образом:
try
// попытка установить пароль
Excel.ActiveWorkbook.protect(‘pass’);
except
// действия при неудачной попытке установить пароль
end;
где pass — устанавливаемый
пароль на книгу.
Снятие пароля
с книги аналогично, использовуем
команду
Excel.ActiveWorkbook.Unprotect(‘pass’);
где pass — пароль, установленный
для защиты книги.
Установка и
снятие пароля для активного
листа книги Excel производится
командами
Excel.ActiveSheet.protect(‘pass’);
// установка пароля
Excel.ActiveSheet.Unprotect(‘pass’);
// снятие пароля
где pass — пароль, установленный
для защиты книги.
Вспомогательные операции в
EXCEL
Удаление
строк со сдвигом вверх:
Excel.Rows[‘5:15’].Select;
Excel.Selection.Delete;
при выполнении данных действий
будут удалены строки с 5 по 15.
Установка
закрепления области на активном
листе Excel
// снимаем закрепление области,
если оно было задано
Excel.ActiveWindow.FreezePanes:=False;
// выделяем нужную ячейку, в данном случае D3
Excel.Range[‘D3’].Select;
// устанавливаем закрепление области
Excel.ActiveWindow.FreezePanes:=True;
Удачной работы!
Источник:
В данном обзоре рассмотрены
основные конструкции,
позволяющие получить доступ к
книге Excel из DELPHI.
Организация доступа к книге
EXCEL
Для
взаимодействия с MS excel в
программе необходимо
использовать модуль ComObj
uses ComObj;
и объявить переменную для
доступа к MS excel следующего
типа:
var Excel:
Variant;
Инициализация
переменной Excel в простейшем
случае можно осуществить так:
Excel := CreateOleObject(‘Excel.Application’);
Создание
новой книги:
Excel.Workbooks.Add;
Открытие
существующей книги (где
path
— путь к фалу с расширением xls.):
Excel.Workbooks.Open[path];
Открытие
существующей книги только для
чтения:
Excel.Workbooks.Open[path, 0,
True];
Закрытие
Excel:
Excel.ActiveWorkbook.Close;
Excel.Application.Quit;
Блокировка
запросов (подтвеждений,
уведомлений) Excel, например,
запретить запрос на сохранение
файла:
Excel.DisplayAlerts:=False;
Отображаем
Excel на экране:
Excel.Visible := True;
или скрываем:
Excel.Visible := False;
Печать
содержимого активного листа
excel:
Excel.ActiveSheet.PrintOut;
Чтение/запись данных в EXCEL
Доступ к
ячейке в текущей книге Excel
можно осуществить следующим
образом:
Excel.Range[‘B2′]:=’Привет!’;-
для записи значения в ячейку или
s:=Excel.Range[‘B2’]; —
для чтения,
где B2
— адрес ячейки.
Или используя стиль ссылок R1C1:
Excel.Range[excel.Cells[2, 2]]:=’Привет!’;,
где [2, 2]
— координата ячейки.
Вообще, ячейке Excel можно
присваивать любое значение
(символьное, целое, дробное,
дата) при этом Excel установит
форматирование в ячейке
применяемое по умолчанию.
Формат ячеек в EXCEL
Выделить
(выбрать) группу ячеек для
последующей работы можно так:
Excel.Range[Excel.Cells[1, 1],
Excel.Cells[5, 3]].Select;
или
Excel.Range[‘A1:C5’].Select;
при этом будет выделена область
находящаяся между ячейкой A1 и
C5.
После
выполнения выделения можно
установить:
1) объединение ячеек
Excel.Selection.MergeCells:=True;
2) перенос по словам
Excel.Selection.WrapText:=True;
3) горизонтальное выравнивание
Excel.Selection.HorizontalAlignment:=3;
при присваивании значения 1
используется выравнивание по
умолчанию, при 2 — выравнивание
слева, 3 — по центру, 4 —
справа.
4) вериткальное выравнивание
Excel.Selection.VerticalAlignment:=1;
присваиваемые значения
аналогичны горизонтальному
выравниванию.
5) граница для ячеек
Excel.Selection.Borders.LineStyle:=1;
При значении 1 границы ячеек
рисуются тонкими сплошными
линиями.
Кроме этого можно указать
значения для свойства Borders,
например, равное 3. Тогда
установится только верхняя
граница для блока выделения:
Excel.Selection.Borders[3].LineStyle:=1;
Значение свойства Borders задает
различную комбинацию граней
ячеек.
В обоих случаях можно
использовать значения в
диапазоне от 1 до 10.
Использование паролей в
EXCEL
Установка
пароля для активной книги может
быть произведена следующим
образом:
try
// попытка установить пароль
Excel.ActiveWorkbook.protect(‘pass’);
except
// действия при неудачной попытке установить пароль
end;
где pass — устанавливаемый
пароль на книгу.
Снятие пароля
с книги аналогично, использовуем
команду
Excel.ActiveWorkbook.Unprotect(‘pass’);
где pass — пароль, установленный
для защиты книги.
Установка и
снятие пароля для активного
листа книги Excel производится
командами
Excel.ActiveSheet.protect(‘pass’);
// установка пароля
Excel.ActiveSheet.Unprotect(‘pass’);
// снятие пароля
где pass — пароль, установленный
для защиты книги.
Вспомогательные операции в
EXCEL
Удаление
строк со сдвигом вверх:
Excel.Rows[‘5:15’].Select;
Excel.Selection.Delete;
при выполнении данных действий
будут удалены строки с 5 по 15.
Установка
закрепления области на активном
листе Excel
// снимаем закрепление области,
если оно было задано
Excel.ActiveWindow.FreezePanes:=False;
// выделяем нужную ячейку, в данном случае D3
Excel.Range[‘D3’].Select;
// устанавливаем закрепление области
Excel.ActiveWindow.FreezePanes:=True;
Удачной работы!