Delphi считает то что в excel

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Праздники ещё не закончились, работать лень, но надо как-то уже прекращать заниматься кишкоблудством и начинать работать в полную силу. Ну, а чтобы как-то себя расшевелить и начать уже работу в блоге, решил первый пост сделать простым — снова сказать несколько слов про 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 +.xlselse 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.ColCount1 do
      IntlXls.Sheets[0].Columns[IntlCol].PixelWidth :=
        FLinkReport.ColWidths[IntlCol];
    // заносим высоты строк
    for IntlRow := 0 to FLinkReport.Cells.RowCount1 do
      IntlXls.Sheets[0].Rows[IntlRow].Height := FLinkReport.RowHeights
        [IntlRow] * 14;
    // проходим по всем строкам
    for IntlRow := 0 to FLinkReport.Cells.RowCount1 do
    begin
      // проходим по всем колонкам
      for IntlCol := 0 to FLinkReport.Cells.ColCount1 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.Width1, IntlRow + Range.Height1);
          // пользователь нажал кнопку прерывания экспорта?
          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.

купить книгу delphi на ЛитРес

3.7
3
голоса

Рейтинг статьи

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Вначале рассмотрим вариант чтения данных использованием которого грешат те, кто только начинает свое знакомство с 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’а.

Вот и всё, Удачи!

Umar Egamberdie

1 / 1 / 3

Регистрация: 20.12.2015

Сообщений: 328

1

09.11.2017, 08:49. Показов 4952. Ответов 18

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// создаем объект Excel
  ExlApp := CreateOleObject('Excel.Application');
  // делаем окно Excel невидимым
  ExlApp.Visible := false;
  // открываем файл XLSFile
  ExlApp.Workbooks.Open(XLSFile);
  // создаем объект Sheet(страница) и указываем номер листа (1)
  // в книге, с которого будем осуществлять чтение
  Sheet := ExlApp.Workbooks[ExtractFileName(XLSFile)].WorkSheets[1];
  // активируем последнюю ячейку на листе
  Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
  // Возвращает номер последней строки
  r := ExlApp.ActiveCell.Row;
  // Возвращает номер последнего столбца
  c := ExlApp.ActiveCell.Column;
  // устанавливаем кол-во столбцов и строк в StringGrid
  StringGrid1.RowCount := r;
  StringGrid1.ColCount := c;
  // считываем значение из каждой ячейки и копируем в нашу таблицу
  for j := 1 to r do
    for i := 1 to c do
      StringGrid1.Cells[i - 1, j - 1] := Sheet.Cells[j, i];

как тут можно исправить код чтобы считывал определенный диапазон строк и столбцов, а то считывает весь лист, это долго получается по времени 2-3 мин, и еще как сделать что бы при считывание на экране появилось Dowland или Landing типо такого



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

09.11.2017, 08:49

18

droider

Эксперт Pascal/Delphi

4884 / 2756 / 849

Регистрация: 04.10.2012

Сообщений: 10,054

09.11.2017, 10:22

2

Цитата
Сообщение от Umar Egamberdie
Посмотреть сообщение

исправить код чтобы считывал определенный диапазон строк и столбцов…долго получается по времени 2-3 мин

ответил уже в предыдущей теме.

Цитата
Сообщение от Umar Egamberdie
Посмотреть сообщение

на экране появилось Dowland или Landing

возьмите TStatusBar и на нем выводите сообщение типа

Delphi
1
StatusBar1.Panels[1].Text :='Подождите, идет импорт файла Excel ...';



0



1 / 1 / 3

Регистрация: 20.12.2015

Сообщений: 328

09.11.2017, 12:05

 [ТС]

3

Цитата
Сообщение от droider
Посмотреть сообщение

StatusBar

хорошая штучка, в будущем пригодиться.

Цитата
Сообщение от droider
Посмотреть сообщение

на экране появилось Dowland или Landing

про это имел введу другое (другое в картинке)

Миниатюры

Считывание из Excel
 



0



Matan!

Модератор

1436 / 1013 / 228

Регистрация: 31.05.2013

Сообщений: 6,645

Записей в блоге: 6

09.11.2017, 12:25

4

Стало интересно. Вот так работает:

Delphi
1
2
3
4
5
6
7
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  ProgressBar1.Position := ProgressBar1.Position + 1;
 
  if (ProgressBar1.Position >= 20) then
    Timer1.Enabled := False;
end;

Добавлено через 3 минуты
А лучше так:

Delphi
1
2
3
4
5
6
7
8
9
10
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  ProgressBar1.Position := ProgressBar1.Position + 10;
 
  if (ProgressBar1.Position >= ProgressBar1.Max) then
  begin
    Timer1.Enabled := False;
    ShowMessage('Привет!:)');
  end;
end;



0



1 / 1 / 3

Регистрация: 20.12.2015

Сообщений: 328

09.11.2017, 13:39

 [ТС]

5

Matan!, попробовал как вы предлагали программа пишет

Access violation at address 0053AC0E in module ‘Project1.exe’



0



Эксперт Pascal/Delphi

4884 / 2756 / 849

Регистрация: 04.10.2012

Сообщений: 10,054

09.11.2017, 14:10

6

Цитата
Сообщение от Umar Egamberdie
Посмотреть сообщение

имел введу другое

а это «другое» должно выводиться при загрузке программы или при импорте файла Excel?



0



1 / 1 / 3

Регистрация: 20.12.2015

Сообщений: 328

09.11.2017, 14:12

 [ТС]

7

Цитата
Сообщение от droider
Посмотреть сообщение

а это другое должно выводиться при загрузке программы или при импорте файла Excel?

при импорте



0



droider

Эксперт Pascal/Delphi

4884 / 2756 / 849

Регистрация: 04.10.2012

Сообщений: 10,054

09.11.2017, 14:26

8

Цитата
Сообщение от Umar Egamberdie
Посмотреть сообщение

при импорте

тогда вариант от Matan! Вам не подойдет, т.к. количество строк в файле может быть разным.

Добавлено через 10 минут
Когда-то я делал так

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
procedure TMSEKMainForm.ExcelImport1Click(Sender: TObject);
const xlCellTypeLast=$000000B;
var
Excel:Variant;
i, j:Integer;
begin
if not OpenDialog1.Execute then Exit;
Excel :=CreateOleObject('Excel.Application');
Excel.DisplayAlerts :=False;//отключаем запросы Excel
Excel.WorkBooks.Open(OpenDialog1.FileName); //открываем книгу Excel
i :=2; //считываем данные со 2-й строки книги
j := Excel.ActiveCell.SpecialCells(xlCellTypeLast).Row;// последняя непустая строка
Gauge1.MaxValue :=j;
// Процедура загрузки
While i<>j+1 do begin //до последней заполненной строки Excel документа
Table.Insert; // соответственно добавляем значения
//в поля таблицы БД
//...
Gauge1.Progress :=Gauge1.Progress+1;//показываем процесс после добавления блока значений
Inc(i); //переходим на следующую строку в Excel
end;
Table.Post; //после считывания файла, сохраняем записи изменения в базе
Gauge1.Progress :=Gauge1.MinValue; //обнуляем шкалу
 
 //отвязываем Excel
Excel.WorkBooks.Close;
Excel.Quit;
Excel := Unassigned;
end;

Вместо TProgressBar я использовал в проекте TGauge (загрузка в %).



2



1 / 1 / 3

Регистрация: 20.12.2015

Сообщений: 328

09.11.2017, 14:30

 [ТС]

9

Цитата
Сообщение от droider
Посмотреть сообщение

тогда вариант от Matan! Вам не подойдет

а есть другие варианты?. Для чего это делаю? просто отслеживать импортирование файла, оно импортируется но долго и кажется что завис, + что бы скучно не было просто смотреть туда



0



Эксперт Pascal/Delphi

4884 / 2756 / 849

Регистрация: 04.10.2012

Сообщений: 10,054

09.11.2017, 14:32

10

На форме процесс импорта отображается так

Миниатюры

Считывание из Excel
 



0



Эксперт Pascal/Delphi

4884 / 2756 / 849

Регистрация: 04.10.2012

Сообщений: 10,054

09.11.2017, 14:33

11

Цитата
Сообщение от Umar Egamberdie
Посмотреть сообщение

а есть другие варианты?

я написал выше. Обновите страницу и читайте.



0



1 / 1 / 3

Регистрация: 20.12.2015

Сообщений: 328

09.11.2017, 14:42

 [ТС]

12

droider, ооопа какая крутая штучка, т.к. я понимаю у вас импортируется только Row?



0



Эксперт Pascal/Delphi

4884 / 2756 / 849

Регистрация: 04.10.2012

Сообщений: 10,054

09.11.2017, 14:45

13

Цитата
Сообщение от Umar Egamberdie
Посмотреть сообщение

у вас импортируется только Row?

Нет. У меня считываются значения из полей (колонок) книги Excel

до последней непустой (заполненной) строки

в документе, т.е. с хотя бы одной заполненной в ней ячейкой.



0



Umar Egamberdie

1 / 1 / 3

Регистрация: 20.12.2015

Сообщений: 328

09.11.2017, 15:06

 [ТС]

14

droider, можете помочь с моим кодом, просто не догадываюсь куда их расположить

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
procedure Xls_Open(XLSFile: string; StringGrid1, StringGrid2: TStringGrid);
const
  xlCellTypeLastCell = $0000000B;
var
  ExlApp, Sheet, Shit, FData: OleVariant;
  i, j, r, c, r1, c1, k: integer;
begin
  // создаем объект Excel
  ExlApp := CreateOleObject('Excel.Application');
  // делаем окно Excel невидимым
  ExlApp.Visible := false;
  // открываем файл XLSFile
  ExlApp.Workbooks.Open(XLSFile);
  // создаем объект Sheet(страница) и указываем номер листа (1)
  // в книге, с которого будем осуществлять чтение
  Sheet := ExlApp.Workbooks[ExtractFileName(XLSFile)].WorkSheets[1];
  // активируем последнюю ячейку на листе
  Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
  // Возвращает номер последней строки
  r := ExlApp.ActiveCell.Row;
  // Возвращает номер последнего столбца
  c := ExlApp.ActiveCell.Column;
  // устанавливаем кол-во столбцов и строк в StringGrid
  StringGrid1.RowCount := r;
  StringGrid1.ColCount := c;
  // считываем значение из каждой ячейки и копируем в нашу таблицу
  for j := 1 to r do
    for i := 1 to c do
      StringGrid1.Cells[i - 1, j - 1] := Sheet.Cells[j, i];
end:



0



Модератор

1436 / 1013 / 228

Регистрация: 31.05.2013

Сообщений: 6,645

Записей в блоге: 6

09.11.2017, 16:41

15

Цитата
Сообщение от Umar Egamberdie
Посмотреть сообщение

можете помочь с моим кодом

Что именно тебе непонятно? Для начала ExcelImport1 сделай.

droider, респект



0



Umar Egamberdie

1 / 1 / 3

Регистрация: 20.12.2015

Сообщений: 328

09.11.2017, 17:09

 [ТС]

16

Цитата
Сообщение от Matan!
Посмотреть сообщение

ExcelImport1

без этого не работает?, просто я новичок если начну заново делать то это долго будет

Добавлено через 2 минуты

Кликните здесь для просмотра всего текста

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
procedure Xls_Open(XLSFile: string; StringGrid1, StringGrid2: TStringGrid);
const
  xlCellTypeLastCell = $0000000B;
var
  ExlApp, Sheet, Shit, FData: OleVariant;
  i, j, r, c, r1, c1, k: integer;
begin
  // создаем объект Excel
  ExlApp := CreateOleObject('Excel.Application');
  // делаем окно Excel невидимым
  ExlApp.Visible := false;
  // открываем файл XLSFile
  ExlApp.Workbooks.Open(XLSFile);
  // создаем объект Sheet(страница) и указываем номер листа (1)
  // в книге, с которого будем осуществлять чтение
  Sheet := ExlApp.Workbooks[ExtractFileName(XLSFile)].WorkSheets[1];
  // активируем последнюю ячейку на листе
  Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
  // Возвращает номер последней строки
  r := ExlApp.ActiveCell.Row;
  // Возвращает номер последнего столбца
  c := ExlApp.ActiveCell.Column;
  // устанавливаем кол-во столбцов и строк в StringGrid
  StringGrid1.RowCount := r;
  StringGrid1.ColCount := c;
  // считываем значение из каждой ячейки и копируем в нашу таблицу
  for j := 1 to r do
    for i := 1 to c do
      StringGrid1.Cells[i - 1, j - 1] := Sheet.Cells[j, i];
end:

мне надо сюда впихать, так проще мне



0



Эксперт Pascal/Delphi

4884 / 2756 / 849

Регистрация: 04.10.2012

Сообщений: 10,054

09.11.2017, 17:46

17

Цитата
Сообщение от Umar Egamberdie
Посмотреть сообщение

ExcelImport1

у меня это просто название пункта меню (TMainMenu), который отвечает за выполнение импорта

Цитата
Сообщение от Umar Egamberdie
Посмотреть сообщение

я новичок

тогда рано Вы взялись за взаимодействие с Excel.



0



1 / 1 / 3

Регистрация: 20.12.2015

Сообщений: 328

10.11.2017, 04:47

 [ТС]

18

Цитата
Сообщение от droider
Посмотреть сообщение

тогда рано Вы взялись за взаимодействие с Excel.

если делаешь какой-то проект быстрее учишься чем пошаговый изучать Hello word. ну это кому как



0



Эксперт Pascal/Delphi

4884 / 2756 / 849

Регистрация: 04.10.2012

Сообщений: 10,054

10.11.2017, 09:42

19

Цитата
Сообщение от Umar Egamberdie
Посмотреть сообщение

если делаешь какой-то проект быстрее учишься

это само собой. Просто не нужно без разбора все смешивать в одну кучу.



0



  • Часть 1: Создание, отображение и удаление экземпляра Excel.
  • Часть 2: Лучшее решение — шаблоны.
  • Часть 3: Создание или открытие книги.
  • Часть 4: Работа с листами и ячейками.
  • Часть 5: Передача данных разного типа.
  • Часть 6: Передача данных используя буфер обмена и DDE.
  • Часть 7: Пример обмена данными с Excel используя VCL и OLE.
  • Часть 1: Управление Word-ом через OLE.
  • Часть 2: Подсчет статистики обычного текста, сносок и колонтитулов в документах.
  • Часть 3: Открытие документа используя VCL.
  • Часть 4: Работа с таблицами.
  • Часть 5: Работа с текстом, рисунками и списками.
Часть 1. Создание, отображение и удаление экземпляра Excel.

Собственно, цель этой статьи мне понятна — поделиться своим опытом с народом. Делюсь.

Итак, зачем нам, лучшим в мире программистам, нужен Excel, порождение «злого» гения Microsoft? Конечно, часто это лишнее — «юзать» Excel для отчетов. Напечатать «платежку» можно и в QReport-е. Но.

Есть заказчики, готовые отдать «кучищи» денег за то, что они будут знать все и всегда о своем предприятии. Да еще, чтоб это было красиво и со вкусом.

Потом я ему показал, как эту самую сводную таблицу в Сеть можно опубликовать. Сейчас просит, чтоб ему доступ из Германии сделали к этой табличке. Мы, конечно, рады стараться.

Я бы привел еще несколько примеров, но, думаю, читатели уже поняли меня. Excel — вещь практически незаменимая во всяческих анализах (не путать с поликлиникой). А для тех, кто не понял, я еще напишу. Отдельно.

Так как же с ним работать ?

А просто. Создал «Excel.Application», использовал его по назначению, «убил» и готово. Вот именно об этом я и попытаюсь написать здесь.

И еще. Эффективная работа с Excel-ом из Delphi-приложений немыслима без знания одной важной вещи. И имя ей — интерфейс. Мне, конечно, хотелось бы написать о принципах работы с интерфейсами здесь, в этой статье. Более того, я обещал сделать это самой Королеве. Но.

Мне ли (совсем еще не профессионалу — и это так!) пытаться сделать это лучше, чем классики этой области. Я честно признаюсь, что не смогу этого сделать быстро (в небольшом объеме) и качественно. Поэтому всякого, не знакомого еще с этой областью программирования, я с глубочайшими извинениями отсылаю к книге Чеппела «OLE Inside».

Достойную помощь (уже применительно к Delphi) может вам оказать «Delphi 4 Unleashed» Чарльза Калверта.

Создание экземпляра Excel.Application.

Этот достаточно простой код вы найдете практически во всех книгах, посвященных работе с интерфейсами. Как и везде, я напишу, что в результате выполнения этого кода создастся объект COM с CLSID-ом «» (читайте и перечитывайте Калверта, это не только укрепляет сон!).

Как показать Excel, если он, разумеется, создан ?

Вот здесь начинаются хитрости. Любой, читавший помощь по Excel VBA, скажет, что достаточно написать FIXLSApp.Visible := true. Не тут-то было. Я делаю так:

Знающие люди говорят, что это свойство отвечает за перерисовку окон Excel. Это все равно, что DisableControls у TDataSet. Добавляет скорости, если в нем false. И это правда что, если выключить его во время длительных пересчетов, то быстрее пересчитается. Но мы, ведь, не выключали его. Зачем тогда эта строка?

Делаем так: комметируем эту строку, запускаем демо, CreateExcel, ShowExcel, закрываем его (можно кнопкой с крестиком в правом верхнем углу окна, кому нравится — через меню «Файл/Выход»). Знающие люди скажут, что Excel на самом деле не закрыт. Интерфейс мы не освободили, поэтому в TaskManager мы его и увидим. Итак, Excel по-прежнему у нас в руках. Мы имеем право сделать ему снова Show.

После такого действия у меня возникает ощущение, что я переплатил за свою видеокарту. Фокус в Excel-е, но я по-прежнему наблюдаю форму демо-проекта. Видимо, программисты из MS не рассчитывали на то, что кто-то закроет Excel, вызванный через создание Excel.Application, а потом захочет увидеть его снова. Но я-то захотел?!

Спрячем Excel от посторонних глаз!
Закроем Excel корректно!

Ну вот, написал только про nil, а кода — на полстраницы. Опишу ситуацию.

специалист

Мнение эксперта

Витальева Анжела, консультант по работе с офисными программами

Со всеми вопросами обращайтесь ко мне!

Задать вопрос эксперту

Воспользуемся полученной информацией и ещё раз посмотрим, как в delphi записать в файл данные фиксированной длины и какие процедуры и функции для работы с файлами нам для этого понадобятся. Если же вам нужны дополнительные объяснения, обращайтесь ко мне!

ZIPФайл = Новый ЧтениеZipФайла ;
ZIPФайл . Открыть ( ФайлEXCEL );
ZIPФайл . ИзвлечьВсе ( ZIPКаталог , РежимВосстановленияПутейФайловZIP . Восстанавливать );
Возврат Истина;
Исключение
Возврат Ложь;
КонецПопытки;

Возврат Истина;
Как Считать Данные из Excel в Delphi • Предварительные замечания

Теперь свойство Width компонента DBGridEh1 выставляем в 638 (ширина грида). А его свойство ReadOnly, выставляем в True — чем запретим редактирование данных пользователем в таблице на прямую. Сохраняем все, запускаем проект…., и если все делалось внимательно, то наш грид должен принять вполне приличный видон.

Записываем XLS из Delphi c помощью FastReport

Итак, ваш документ содержит большие таблицы, многоуровневые списки, иллюстрации, карты, штрих-коды и вы думаете, как бы это перенести в Excel?
Не буду тут повторно останавливаться на создании отчёта — бросили на форму проекта TfrxReport, TfrxBIFFExport и TButton, прописали на кнопку вызов

— строим отчёт и запускаем окно предпросмотра того, что получилось.
Видим окно предварительного просмотра и кнопку “сохранить”

Выбор сохранения Excel 97/2000/XP file.

И, в принципе, как будет выглядеть результат: разбивать на страницы, оставив в изначальном виде, расположить всё на одной странице или же поделить на части с задаваемым количеством строк.

Можно указать, куда отправить Excel-файл (локально в память компьютера, на электронную почту или поместить в облако).

Открыть после экспорта – результирующий файл будет открыт сразу же после экспорта программой Microsoft Excel.

служебная информация в XLSЗащита XLS biff8 паролемдополнительные настройки XLS biff8

Служебная информация, которая также пойдёт в Excel-файл: название, автор, ключевые слова, версия документа, приложения, категория, менеджер и комментарий к файлу.

Безопасность — защита паролем документа (дополнительно можно указать подтверждение).

Если задать непустую строку пароля, то сгенерированный файл будет защищён паролем. Пароль пишется только символами Юникода и должен быть короче 256 символов.

Опции – настройка документа на большее визуальное соответствие с первоначальном вариантом (WYSIWYG), экспорт в таблицу картинок-изображений, отображения границ ячеек, выставлять размер страницы, удаление пустых строк (для экономии места в этом конкретном формате очень важная опция), экспорт формул.

Если не нужно столь подробно выставлять параметры, то можно оставить всё по умолчанию.

Delphi Office® — Автоматизация приложений MS® Office® для эффективного анализа результатов

Я бы привел еще несколько примеров, но, думаю, читатели уже поняли меня. Excel — вещь практически незаменимая во всяческих анализах (не путать с поликлиникой). А для тех, кто не понял, я еще напишу. Отдельно.

специалист

Мнение эксперта

Витальева Анжела, консультант по работе с офисными программами

Со всеми вопросами обращайтесь ко мне!

Задать вопрос эксперту

Поэтому всякого, не знакомого еще с этой областью программирования, я с глубочайшими извинениями отсылаю к книге Чеппела OLE Inside. Если же вам нужны дополнительные объяснения, обращайтесь ко мне!

Мне ли (совсем еще не профессионалу — и это так!) пытаться сделать это лучше, чем классики этой области. Я честно признаюсь, что не смогу этого сделать быстро (в небольшом объеме) и качественно. Поэтому всякого, не знакомого еще с этой областью программирования, я с глубочайшими извинениями отсылаю к книге Чеппела «OLE Inside».

Как создать файл в Excel 97(2000, XP file) — XLS из Delphi / C Builder / Lazarus? Fast Reports

Ранее я говорил про некоторые встроенные возможности BitBtn . Вот сейчас пришло время показать, как ими пользоваться. Выделяем поставленный нами на форму BitBtn , в Инспекторе объектов ищем атрибут Kind , и там уже выбираем желаемую кнопочку.

Довольно распространенная задача в программировании – загрузка данных в проект из внешнего файла. В отличие от загрузки из обычного текстового файла, загрузка из Excel, как и любого другого специального файла или подключение к базе данных, требует отдельного механизма реализации.

В данной статье рассматривается один из наиболее удобных способов работы с подгружаемыми из Excel данными. Значения всех ячеек страницы Excel вносятся в двумерный массив типа Variant. Затем с этим массивом уже можно работать любыми привычными способами.

В общем виде все сводится к подключению программы к файлу Excel, получению необходимого диапазона ячеек и присвоении вашему массиву значения заданного диапазона ячеек.

const
   xlCellTypeLastCell = $0000000B;
var
   ExcelApp, ExcelSheet: OLEVariant;
   MyMass: Variant;
   x, y: Integer;
begin
   // создание OLE-объекта Excel
   ExcelApp := CreateOleObject('Excel.Application');

   // открытие книги Excel
   ExcelApp.Workbooks.Open('C:my_excel.xls');

   // открытие листа книги
   ExcelSheet := ExcelApp.Workbooks[1].WorkSheets[1];

   // выделение последней задействованной ячейки на листе
   ExcelSheet.Cells.SpecialCells(xlCellTypeLastCell).Activate;

   // получение значений размера выбранного диапазона
   x := ExcelApp.ActiveCell.Row;
   y := ExcelApp.ActiveCell.Column;

   // присвоение массиву диапазона ячеек на листе
   MyMass := ExcelApp.Range['A1', ExcelApp.Cells.Item[X, Y]].Value;

   // закрытие книги и очистка переменных
   ExcelApp.Quit;
   ExcelApp := Unassigned;
   ExcelSheet := Unassigned;
end;

* Метод SpecialCells используется для выделения определенных ячеек на основании оценки их содержимого или других характеристик. Применяемое здесь значение параметра-константы xlCellTypeLastCell указывает методу выделить последнюю ячейку используемого диапазона, т.е. саму нижнюю правую ячейку в диапазоне, где введено хоть какое-то значение. Это позволяет копировать не все ячейки листа, а лишь диапазон, содержащий какие-либо данные.

Для использования команд работы с OLE-объектами для этого кода нужно добавить библиотеку:

uses
  ComObj;

После указанных операций данные введены в массив, из которого их можно перенести в компонент StringGrid или использовать их по своему усмотрению. Стоит заметить, что в полученном таким образом массиве данные индексы располагаются в следующем порядке: [номер строки, номер столбца]. Это видно из следующего примера вывода данных массива в компонент StringGrid.

// назначение размера StringGrid по размеру полученного диапазона ячеек
MyStringGrid.RowCount := x;
MyStringGrid.ColCount := y;

// заполнение таблицы StringGrid значениями массива
for x := 1 to MyStringGrid.ColCount do
  for y := 1 to MyStringGrid.RowCount do
      MyStringGrid.Cells[x-1, y-1] := MyMass[y, x];

Понравилась статья? Поделить с друзьями:
  • Delphi скопировать лист в excel на другой лист
  • Delphi работа с word шаблон
  • Delphi высота ячейки excel
  • Delphi выделить текст в word
  • Delphi работа с excel скачать