Здесь, на самом деле, есть подвох. Например, если в Excel для ячейки exSheet.Cells[1, 1] выбран формат «Числовой» и в ней записано какое-нибудь число, то при проверке:
Delphi | ||
|
возникнет исключение EVariantTypeCastError с сообщением: «Could not convert variant of type (String) into type (Double)» — невозможно преобразовать строку к типу Variant с содержимым типа Double.
Решить эту проблему можно двумя способами:
1.
Вместо вариантного значения ячейки (Value), проверить текстовое представление (Text):
Delphi | ||
|
2.
Проверить — является ли вариантное значение ячейки пустым вариантом:
Delphi | ||
|
Добавлено через 15 минут
Да, кстати, есть очень важная поправка. Предположим, в Excel сброшен параметр: «Показывать нули в ячейках, которые содержат нулевые значения» и при этом в ячейке задано значение = 0 (ноль). Тогда, если судить о пустоте ячейки по пустоте текста, то мы получим неверный результат. Т .к., в этом случае текст ячейки будет пуст, но ячейка пустой не является — в ней записан ноль.
Поэтому, есть только один правильный способ проверки ячейки на пустоту — через проверку на пустоту вариантного значения:
Delphi | ||
|
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Продолжаем копаться в листах Excel и изучать особенности работы с ними. Сегодня мы рассмотри свойства объекта WorkSheet.
Основными свойствами, которые Вы с большой вероятностью будете использовать в своей работе с Excel в Delphi являются:
- Cells — ячейки
- Columns — столбцы
- Name — название листа
- Range — диапазон ячеек
- Rows — сроки
- StandartHeight — высота строк «по умолчанию»
- StandartWidth — ширина столбцов «по умолчанию»
- UsedRange — задействованный диапазон ячеек
- Comments — комментарии
Всего у листа рабочей книги Excel насчитывается 54 различных свойств, но, как показвает практика, для использования Excel в Dephi достаточно 9-15 различных свойств листа, чтобы получить необходимый результат, обеспечивающий удобство и наглядность представляемых данных.
Рассмотрим применение указанных выше свойств листа Worksheet при работе с Excel в Delphi.
1. Свойство Cells
Возвращает объект диапазона, который представляет собой все ячейки на листе (а не только клетки, которые используются в настоящее время)
Пример вызова:
MyExcel.ActiveWorkBook.ActiveSheet.Cells
Однако использование свойства Cells возможно (и более практично) в другом виде. Вы можете указать сразу за словом Cells номера столбца и строки и, таким образом, получить доступ к конкретной ячейке листа. Например, забегая немного вперед, посмотрим, как можно удалить формулы из ячейки:
MyExcel.ActiveWorkBook.ActiveSheet.Cells[5,3].ClearContents
Выполнив такую операцию Вы удалите из ячейки С5 формулу (или любое другое содержимое). Как можно заметить, в отличие от работы с таблицами StringGrid Delphi, здесь вначале указывается номер строки, а затем номер столбца (у String Grid напротив — сначала указывается номер столбца, а затем номер строки).
Аналогичным образом Вы можете записать в ячейку данные:
MyExcel.ActiveWorkBook.ActiveSheet.Cells[5,3]:='Пример текста'
Ну, а чтобы показать использование этого свойства на примере, давайте напишем простенькую процедуру копирования таблицы StringGrid в любую область листа Worksheet Excel.
procedure WriteTable(FirstCol, FirstRow:integer; Grid: TStringGrid); var col,row:integer; begin try for col := 0 to Grid.ColCount - 1 do for row := 0 to Grid.RowCount - 1 do MyExcel.ActiveWorkBook.ActiveSheet.Cells[FirstRow+row+1, FirstCol+col+1]:=Grid.Cells[col, row]; except raise Exception.Create('Запись таблицы завершилась ошибкой') end; end;
Здесь в качестве параметров процедуры необходимо задать: номера первого столбца (FirstCol) и первой строки (FirstRow) на листе Excel, начиная с которых необходимо копировать данные из таблицы StringGrid (Grid). Заметьте, что вызов свойств Cells у StringGrid и WorkSheet происходит по-разному (см. индексы ячейки).
Естественно, что представленная процедура может с легкостью применяться при копировании небольших таблиц. Однако при импорте больших объемов данных в Excel эта процедура будет очень сильно тормозить работы основной программы. Более скоростной способ импорта данных из Excel в Delphi и наоборот мы рассмотрим позже, при рассмотрении объекта Range.
2. Свойство Columns
Возвращает объект диапазона, который представляет собой все столбцы на активном листе. Если активный документ не является листом (а, например, диаграммой), то вызов свойства Columns приводит к исключительной ситуации.
Пример вызова:
MyExcel.ActiveWorkBook.ActiveSheet.Columns
Это свойство удобно использовать при редактировании столбцов данных. Например вот так:
MyExcel.ActiveWorkBook.ActiveSheet.Columns[1].Font.Bold
Вы сможете изменить шрифт в столбце А на полужирный. Также Вы можете изменять внешний вид столбцов, перерисовывать границы ячеек и т.д.
3. Свойство Name
С этим свойством мы уже сталкивались. Свойство Name возвращает имя рабочего листа книги.
Пример вызова:
MyExcel.ActiveWorkBook.ActiveSheet.Name:='Новое название листа'
Так мы изменили имя текущего активного листа Excel. Кроме этого, свойство Name удобо использовать при поиске необходимого листа.
4. Свойство Range
Возвращает объект, представляющий собой одну ячейку или диапазон ячеек.
Пример вызова:
MyExcel.ActiveWorkBook.ActiveSheet.Range['A1']:='Hello World'
Так, мы получили доступ к ячейке А1 и записали в неё текст. А следующий фрагмент кода демонстрирует быстрый способ экспорта данных из листа Excel в Delphi:
var Numbers : Variant; data: string; i: integer; begin ... Numbers:=MyExcel.ActiveSheet.Range[Num+IntToStr(FirstRows), Num+IntToStr(Rows)].Value; for i:=1 to MyExcel.ActiveSheet.UsedRange.Rows.Count do data:=Numbers[i,1] ... end;
Так, мы за одно обращение к листу считали столбец данных и в дальнейшем, не используя напрямую объект WorkSheet, обработали все данные в вариантном массиве Numbers. Этот способ чтения данных с листа Excel является наиболее скоростным из всех известных мне в настоящее время. Если знаете способ более скоростной — буду очень рад, если поделитесь им.
5. Свойство Rows
Это свойство аналогично свойству Columns, но в отличие от него, возвращает объект, представляющий собой строку листа. С помощью этого свойства Вы также можете изменять внешний вид ячеек листа, изменять шрифт и т.д.
6. Свойства StandartHeight и StandartWidth
Эти свойства позволяют получить значения высоты и ширины ячеек листа «по умолчанию». Свойство доступно только для чтения, т.е. вызов:
MyExcel.ActiveWorkBook.ActiveSheet.StandartHeight:=14
Приведет к исключительной ситуации. Вы можете использовать это свойство, например, когда необходимо гарантировано установить значения высоты и ширины строк в значения «по умолчанию»
7. Свойство UsedRange
Возвращает диапазон занятых ячеек листа. Свойство очень удобно использовать, когда необходимо узнать количество занятых строк и столбцов на листе:
Rows:=MyExcel.ActiveSheet.UsedRange.Rows.Count; Columns:=MyExcel.ActiveSheet.UsedRange.Columns.Count;
и далее, используя эти данные быстро прочитать весь занятый диапазон в вариантный массив для дальнейшей обработки.
Это свойство возвращает коллекцию комментариев на листе.
Например:
MyExcel.ActiveSheet.Comments[2].Delete
удалит второй комментарий из коллекции, а:
MyExcel.ActiveSheet.Range("e5").AddComment('Текст комментария')
добавит в ячейку е5 новый комментарий.
Итак, резюмируем. Сегодня мы узнали: как записать данные в ячейку листа Excel, как прочитать данные из диапазона ячеек, как скопировать таблицу из Delphi в Excel, как быстро экспортировать данные из Excel в Delphi.
В следующий раз займемся работой с ячейками листа, а именно научимся копировать таблицы из Delphi в Excel один-к-одному с сохранением всех цветов, границ ячеек и т.д., а также, попробуем строить диаграммы, которые опять же очень часто требуются при разработке бизнес-приложений.
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Поиск данных на листе.
Предлагаю поискать все ячейки, содержащие строку (или
подстроку) «Text», и изменить цвет фона этих ячеек. Для этого я использовал
методы Find и FindNext. На форму была добавлена кнопка, в обработчике которой
появился следующий код:
procedure TForm1.btnFindClick(Sender: TObject); var ISheet: Excel8TLB._Worksheet; IFirst, IRange: Excel8TLB.Range; FirstAddress, CurrentAddress: string; UsedRange: OLEVariant; begin if Assigned(IWorkbook) then try ISheet := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; try UsedRange := ISheet.UsedRange[0]; IDispatch(IFirst) := UsedRange.Find(What:='Text', LookIn := xlValues, SearchDirection := xlNext); if Assigned(IFirst) then begin IRange := IFirst; FirstAddress := IFirst.Address[EmptyParam, EmptyParam, xlA1, EmptyParam, EmptyParam]; repeat IRange.Interior.ColorIndex := 37; IDispatch(IRange) := UsedRange.FindNext(After := IRange); CurrentAddress := IRange.Address[EmptyParam, EmptyParam, xlA1, EmptyParam, EmptyParam]; until FirstAddress = CurrentAddress; end; finally IRange := nil; IFirst := nil; ShowExcel; end; except raise Exception.Create('Не могу чего-то сделать!'); end; end;
Думаю, у каждого увидевшего этот код возникнет ощущение
неудовлетворенности. Да, в выделенной красным строке никаким ранним связыванием
и не пахнет. Более того, если вы попробуете вызвать метод Find с указанными
параметрами, заменив остальные на EmptyParam, вы получите исключение. Есть места
в Excel Type Library, работающие с ошибками. Я знаю достаточно этих мест. В
таких случаях я использую приведенный здесь прием. Я проверяю работоспособность
кода в редакторе VBA, а затем перехожу на позднее связывание. Так мне удалось
обойти несколько серьезных, по моему мнению, ошибок в Excel TLB. Раннее
связывание не должно быть догмой хотя бы из-за этого. Более того, перейдя
полностью на ранее связывание, мы получим более компактный, а следовательно и
читаемый код:
procedure TForm1.btnFindClick(Sender: TObject); var ISheet: Excel8TLB._Worksheet; UsedRange, Range: OLEVariant; FirstAddress: string; begin if Assigned(IWorkbook) then try ISheet := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; UsedRange := ISheet.UsedRange[0]; Range := UsedRange.Find(What:='Text', LookIn := xlValues, SearchDirection := xlNext); if not VarIsEmpty(Range) then begin FirstAddress := Range.Address; repeat Range.Interior.ColorIndex := 37; Range := UsedRange.FindNext(After := Range); until FirstAddress = Range.Address; ShowExcel; end; except raise Exception.Create('Не могу чего-то сделать!'); end; end;
Перемещение данных между листами.
Несколько раз меня спросили о том, как перемещать данные между
листами. Я бы сделал это вот так:
procedure TForm1.btnMoveDataClick(Sender: TObject); var ISheetSrc, ISheetDst: Excel8TLB._Worksheet; IRangeSrc, IRangeDst: Excel8TLB.Range; begin if Assigned(IWorkbook) then try ISheetSrc := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; ISheetDst := IWorkbook.Worksheets.Add(EmptyParam, ISheetSrc, 1, EmptyParam, 0) as _Worksheet; IRangeSrc := ISheetSrc.Range['TestRange2', EmptyParam]; IRangeDst := ISheetDst.Range['D4', EmptyParam]; IRangeSrc.Copy(IRangeDst); finally IRangeDst := nil; IRangeSrc := nil; ISheetDst := nil; ISheetSrc := nil; end; end;
Метод Copy интерфейса Range принимает в качестве параметра
любой другой Range. Причем, совсем не важно, совпадают ли размеры источника и
получателя, так как данные копируются начиная с левой верхней ячейки получателя
в количестве, определенном размером источника. (О, завернул!) Для затравки
хотелось бы показать код, который выполняет ту же задачу, но через буфер обмена
(а вдруг в Word вставлять будем):
procedure TForm1.btnMoveDataClick(Sender: TObject); var ISheetSrc, ISheetDst: Excel8TLB._Worksheet; IRangeSrc, IRangeDst: Excel8TLB.Range; begin if Assigned(IWorkbook) then try ISheetSrc := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; ISheetDst := IWorkbook.Worksheets.Add(EmptyParam, ISheetSrc, 1, EmptyParam, 0) as _Worksheet; IRangeSrc := ISheetSrc.Range['TestRange2', EmptyParam]; IRangeDst := ISheetDst.Range[ 'D4', EmptyParam]; IRangeSrc.Copy(EmptyParam); // так кладем в Clipboard ISheetDst.Paste(IRangeDst, EmptyParam, 0); // а вот так достаем оттуда finally IRangeDst := nil; IRangeSrc := nil; ISheetDst := nil; ISheetSrc := nil; end; end;
Проект — SampleExcel (в архиве с данной
статьёй).
Часть 5. Передача данных разного типа.
Как и прежде, я беру проект-пример из предыдущей своей статьи
и переделываю его. Напомню, что в нем используется импортированная в Delphi 4
библиотека типов Excel (правда, исходный код я пишу уже в Delphi 5). Свои
примеры я тестирую с помощью Excel 2000 с установленным пакетом обновлений
Service Release 1. Впрочем, я уверен, что все примеры вы сможете откомпилировать
в Delphi 4 и использовать с Excel 97 SR2 и Excel 2000 без SR1. Обращаю внимание
на установку SR2 для Excel 97. Это обязательное условие, так как без этого
обновления Excel содержит очень неприятную ошибку, периодически возникающую при
закрытии книг. Поэтому, пожалуйста, будьте внимательны, господа!
Какие данные мы используем?..
«Всяческие»! Да, каждый из нас использует в своих приложениях
все многообразие типов данных, с которыми способен справиться компилятор и
операционная система. В принципе, можно было бы описать решение проблемы для
всего этого «многообразия». Но! Я всегда утверждал и буду утверждать, что типы
данных, для которых нельзя написать Cell.Value = NewValue, бесполезно
использовать в Excel. Я не «влюблен» в Excel. Но я твердо уверен в том, что
Excel в сегодняшнем его состоянии — одно из мощнейших средств анализа
корпоративных данных. И я до сих пор не могу найти другого применения картинкам
в книгах Excel, кроме как наведение красоты. Поэтому я остановлюсь только на
способах передачи целых и вещественных чисел, строк, дат и логических значений.
В общем, всего того, что так надоело нам в наш быстротекущий media-век.
Важно! Проект-пример содержит одну форму, в
обработчиках OnCreate и OnDestroy которой автоматически создается и
освобождается Excel.Application. Причем, для этого я использовал методы из
предыдущих примеров — CreateExcel, ShowExcel и ReleaseExcel. Особое внимание
хочу обратить на ReleaseExcel, с помощью которого освобождается интерфейс
Excel.Application. Если же необходимо закрыть Excel, вызывайте перед
освобождением интерфейса метод Quit этого интерфейса (у себя я закомментировал
эту строку). На форму я поместил таблицу (TTable) из DBDEMOS — CUSTOMER.DB.
Чтобы видеть хоть что-то, я использовал для этой таблицы DBGrid и навигатор. В
правой части формы вы увидите кнопку со странным названием «Send data» и группу
переключателей под ней. С помощью этой группы вы сможете выбрать один из
рассмотренных в этой статье вариантов передачи данных в Excel (данные я беру из
вышеназванной таблицы). После выбора варианта передачи и нажатия кнопки в Excel
создается новая книга на основе шаблона Test.xls — книги, которую я прилагаю
вместе с проектом. В эту книгу из таблицы переносятся значения полей из всех
записей. При переносе я измеряю количество миллисекунд, затраченных на этот
перенос, и помещаю это количество в ячейку A1 созданной книги.
И еще. При создании примера я старался избегать лишнего кода,
который в любом другом случае добавил бы законченность алгоритмам. Меня стоило
бы основательно поругать за то, что я не запоминаю закладок при проходе по
таблице, использую значения полей, забывая о DisplayText, и просто переношу
значения в книгу без какого-либо форматирования ячеек. Наверняка, вы найдете еще
несколько моментов, которые я совсем упустил из вида. Попросту, красота кода
уступила свое место желанию сосредоточиться на единственной цели — эффективной
передаче данных. Единственное, что я сделал, так это избавился от возможности
вмешательства пользователя в процесс переноса данных, отключив (и включив затем)
у Excel свойства Interactive и ScreenUpdating, а также вызвав DisableControls
для набора данных.
Какие же варианты я предложу на суд читателя? Вариантов и
возможностей передачи данных в Excel существует достаточно много — от очень
«заумных» (BIFF) до экзотических (сохраним в текстовый файл и затем его
откроем). Все они имеют какие-то свои достоинства и недостатки. В этой статье я
расскажу об одних из самых простых и эффективных решениях этой проблемы
(название раздела все-таки обязывает — HelloWorld!). Правда, первый описанный
здесь способ, у меня ничего кроме зубной боли не вызывает. Итак…
Не делайте так — клиническая смерть!
Собственно, об этом варианте я мог бы и не писать. Во-первых,
я встречал его в большинстве книг и статей, посвященных этой теме. Во-вторых, я,
на самом деле, думаю, что так делать нельзя. Речь идет о тривиальном переносе
данных с помощью обычного присваивания свойству ячейки Value нового значения.
Тем не менее, я надеюсь что, описывая этот вариант, мне удастся обратить ваше
внимание на несколько важных вещей.
Первый переключатель на форме (с заголовком «Value :=»)
скрывает за собой вызов процедуры ToNewValue. Вот ее исходный код:
procedure TForm1.ToNewValue(ISheet: IxlWorksheet); var Row, Column, i: integer; begin tblCust.First; Row := StartRow; tblCust.First; while not tblCust.EOF do begin Column := StartColumn; for i := 0 to tblCust.Fields.Count - 1 do begin ISheet.Cells.Item[Row, Column].Value := FieldToVariant(tblCust.Fields[i]); Inc(Column); end; Inc(Row); tblCust.Next; end; end;
Что в ней особенного? Да, это обычный проход по всей таблице
(First; while not EOF do Next;) и по всем ее полям (вложенный for). Но!
Во-первых, в этом примере я всегда начинаю переносить данные с ячейки,
определенной константами StartRow и StartColumn. Во-вторых, ожидаемый вами
оператор присваивания «Cell.Value := Field.Value» я заменил на «Cell.Value :=
FieldToVariant(Field)». То есть, в отличие от классического, «из учебников»,
примера я использую свою функцию получения вариантного значения поля.
Если присмотреться к исходному тексту функции FieldToVariant,
function FieldToVariant(Field: TField): OLEVariant; begin Result := ''; case Field.DataType of ftString, ftFixedChar, ftWideString, ftMemo, ftFmtMemo: Result := '''' + Field.AsString; ftSmallint, ftInteger, ftWord, ftLargeint, ftAutoInc: Result := Field.AsInteger; ftFloat, ftCurrency, ftBCD: Result := Field.AsFloat; ftBoolean: Result := Field.AsBoolean; ftDate, ftTime, ftDateTime: Result := Field.AsDateTime; end; end;
то можно разглядеть причину. Кроме достаточно глупых
«AsInteger», «AsFloat» и пр. я добавляю в начало значений строковых полей
одиночную кавычку. Вы, наверняка, помните, что ввод в формулу ячейки первым
символом одиночной кавычки заставляет Excel принимать остальные символы как
текст. Но, это касается формул ячеек, а не их значений!? Попробуйте убрать
добавление этой кавычки и перекомпилировать проект. Конечно, и в этом варианте
все будет работать. Но (предлагаю кощунственный метод) отредактируйте поле
«Company» в первой записи таблицы, введя туда строку «3/7». Не увидите ли вы в
полученной книге вместо этой строки дату или результат деления (зависит от
языковых настроек ОС)? Столь же некорректный результат будет получен и при
попытке передачи строки «0001», которая будет воспринята как число 1. Благо,
одиночная кавычка в начале строки решает эту проблему даже при присваивании в
Value (а не в Formula).
Впрочем, я не намерен долго останавливаться на этом варианте.
Все дело в значении ячейки A1 в полученной книге. На моем компьютере перенос
всей таблицы занял более 4 секунд. И это на не более полусотне записей. А что
было бы, если бы количество записей перевалило за пару десятков тысяч? Кстати,
повторные запуски показали колебание этого времени в пределах от трех до пяти
секунд. Думаю, что такие колебания были связаны только с файловым кэшем ОС. Так
что, «Не делайте так!»
Больному уже лучше. Правда, он все еще в реанимации.
На что же уходит время в предыдущем варианте? Все просто!
Львиная доля времени уходит на вызовы интерфейсов внешнего COM-сервера. И, не
смотря на то, что мы используем ранее связывание с библиотекой типов, это так.
Еще мой любимый классик (Калверт, знаете ли) писал о нетерпимости к вызовам
интерфейсов внешних OLE-серверов в больших циклах. Как видите, классик прав.
Наша задача — избавиться от вызова Cell.Value в цикле. И это
решаемо с помощью вариантных массивов. Вот так:
procedure TForm1.ToVarArray(ISheet: IxlWorksheet); var Row, Column, i: integer; IR1, IR2: IxlRange; Arr: OLEVariant; begin Arr := VarArrayCreate([1, tblCust.RecordCount, 1, tblCust.Fields.Count], varVariant); Row := 1; tblCust.First; while not tblCust.EOF do begin Column := 1; for i := 0 to tblCust.Fields.Count - 1 do begin Arr[Row, Column] := FieldToVariant(tblCust.Fields[i]); Inc(Column); end; Inc(Row); tblCust.Next; end; IDispatch(IR1) := ISheet.Cells.Item[StartRow, StartColumn]; IDispatch(IR2) := ISheet.Cells.Item[StartRow + tblCust.RecordCount - 1, StartColumn + tblCust.Fields.Count - 1]; ISheet.Range[IR1, IR2].Value := Arr; end;
Здесь я использую вариантный массив Arr, который
предварительно создается с размерами таблицы (количество записей на количество
полей). Благо Microsoft построила очень четкую схему работы с вариантными
массивами и интерфейсами, их «понимающими» (этим и пользуюсь). Из кода видно,
что я по-прежнему прохожу всю таблицу, запоминая в элементах массива значения
полей, полученных из вышеописанной функции FieldToVariant. Мы, ведь, снова
используем варианты, и проблема строки «3/7» остается. Последние три строки
процедуры позволяют получить верхнюю левую и нижнюю правую ячейки области, в
которую будут перенесены данные. А, затем, одним присваиванием в «Область.Value»
я переношу данные из массива в ячейки этой области. Хорош способ, не правда ли?
Код максимально прост. Время, полученное в ячейке A1 на порядок меньше. Правда,
есть несколько проблем.
Главное, что бросилось бы в глаза опытного
Delphi-разработчика, это создание массива в начале процедуры. Известно ли
количество записей SQL-запроса после его открытия? Не всегда (FechAll). Хорошо,
можно создать пустой массив и делать ему VarArrayRedim. Вряд ли! Так как
количество записей — есть первое измерение вариантного массива (необходимо здесь
тире или нет???). А я не нашел до сих пор способа изменить первую размерность
вариантного массива при наличии второй. Может, кто подскажет начинающему (про
начинающего — правда)!!! Возможно, было бы правильно создать массив массивов
(понимаете о чем я?). Но, что-то не заладилось там, Наверху. Поэтому такое
решение не проходит. Точнее проходит, но как-то не очень хорошо — попробуйте!
Тем не менее, этот вариант вполне «живуч» при осторожном его
использовании и на небольших объемах данных. Скорость нормальная, проблем с
«3/7» нет. В общем, больной будет жить!
Часть 6. Передача данных используя буфер обмена и DDE.
Clipboard.
Совсем недавно мне пришло очередное гневное послание на тему
буфера обмена — Clipboard. Объясню. XL Report очень долго использовал только
буфер обмена для передачи данных из приложения в Excel. Дело в том, что при
таком варианте (а я его здесь опишу) достигается практически максимальная
скорость переноса данных. Дело в том, что в буфер обмена «кладется» длинная
строка, содержащая строковые значения полей набора данных (AsString),
разделенные символом табуляции. Записи отделяются друг от друга переводом строки
(#10). Собственно, этот формат известен в научных кругах как CSV (разделитель
между значениями). Долгое время это меня устраивало, пока XL Report
использовался только нашими разработчиками и ограниченным кругом клиентов фирмы.
Но тут мы решили выложить это решение в Сеть. И…
Каюсь. Я никак не беспокоился за сохранность содержимого
буфера обмена. Понятное дело, это не очень правильно. Но, так было. Так есть и
сейчас. Правда, по другим причинам. Для того, чтобы «выжать» из Excel
максимальное быстродействие, приходится использовать определенные методы и
свойства его интерфейсов. А их использование не оставляет ничего, кроме как
уничтожение содержимого буфера обмена. В общем, сейчас я покажу максимально
возможное (в этой статье!!!) решение по переносу данных — CSV. Итак:
procedure TForm1.ToCSV(ISheet: IxlWorksheet); var i: integer; IR1, IR2: IxlRange; Buff: String; begin Buff := ''; tblCust.First; while not tblCust.EOF do begin for i := 0 to tblCust.Fields.Count - 1 do begin Buff := Buff + FieldToStr(tblCust.Fields[i]); if i < (tblCust.Fields.Count - 1) then Buff := Buff + #9; end; tblCust.Next; if not tblCust.EOF then Buff := Buff + #10; end; BufferToClipboard(Buff); try IDispatch(IR1) := ISheet.Cells.Item[StartRow, StartColumn]; IDispatch(IR2) := ISheet.Cells.Item[StartRow + tblCust.RecordCount - 1, StartColumn + tblCust.Fields.Count - 1]; OLEVariant(ISheet.Range[IR1, IR2]).PasteSpecial; finally Clipboard.Clear; end; end;
Как я и писал выше, в строковый буфер Buff собирается вся
таблица. Строковые значения полей я разделяю символом табуляции, а в «конце»
записи добавляю перевод строки. Все значения я заключаю дополнительно в двойные
кавычки. Затем вызовом процедуры BufferToClipboard я помещаю содержимое этой
переменной в буфер обмена и делаю «хитрый» вызов PasteSpecial для области, в
которую будут помещены данные. Вот и все?! Нет, есть еще проблемы.
Во-первых, процедура BufferToClipboard — вещь не стандартная.
Она создана как альтернатива методу SetTextBuf класса TClipboard. Наверняка, все
знают что в VCL доступна глобальная переменная Clipboard, экземпляр класса
TClipboard, инкапсулирующего свойства и методы доступа к этому самому буферу
обмена. И, собственно, вызов SetTextBuf позволяет поместить строку в буфер. Но!
SetTextBuf помещает в буфер обмена текст в формате CF_TEXT —
обычный текст с однобайтовым представлением символов, что не есть хорошо.
Точнее, это совсем не хорошо, если вы работаете с «русскими буквами» на разных
операционных системах от MS, причем, разных с точки зрения локализации. Именно
тогда и возникают у пользователей вопросы при попытке прочитать некий набор
«закорючек», отдаленно напоминающих письмена племени зибару. Поэтому я
предпочитаю UNICODE, вставка которого в буфер обмена и реализована в этой
процедуре. Ее текст я не буду приводить в этой статье, так как это потребует
лишних для этого объяснений. Сама процедура присутствует в исходных текстах
проекта-примера. Поэтому знатоков этого дела отсылаю к ним, а таким начинающим,
как и я, просто рекомендую ее использовать в последующих своих разработках (при
необходимости).
UNICODE — это первая проблема, которая была решена. Но при
использовании CSV есть и другие. И, главная, из них — «3/7». Без вмешательства в
содержимое поля (аналогично добавлению одиночной кавычки при вариантах) ее
нельзя обойти никак. Я добавляю пробел. Да, тривиального пробела вполне хватает
для решения этой проблемы. И замеченная вами функция FieldToStr как раз это и
делает.
По поводу «хитрого» PasteSpecial. При «правильном» вызове
метода PasteSpecial интерфейса Range я столкнулся с неразрешимыми проблемами.
Поэтому я привел к варианту область и заставил ОС и сам Excel самостоятельно
разбираться с тем, что и с какими параметрами я вызываю. Часто, при разработке с
библиотеками типов от MS такой ход экономит время и, главное, сохраняет здоровье
и нормальное состояние нервной системы. Не используйте его все время, но и не
пренебрегайте им. Итак, при использовании CSV и буфера обмена мы достигли
«громаднейшей» скорости передачи данных, обойдя при этом несколько проблем.
Недостатки, которые заметят критики и просто опытные
разработчики. Переданное строковое значение «0001» предстает перед изумленным
пользователем числом 1. Это можно обойти только через предварительное
форматирование конкретной ячейки в текстовый формат. Подчеркиваю,
предварительно, то есть перед переносом данных. И, по-прежнему, содержимое
буфера обмена не сохраняется. Более того, оно затем нагло очищается вызовом
Clipboard.Clear. «Мы его теряем!»
DDE.
Думаю, вы уже заметили, что один из переключателей вариантов
имеет название, состоящее из зловещего сочетания букв — DDE. Первое, что вы
можете почувствовать при виде этих букв, — это застоялый запах плесени и
старения. Да, DDE — пережиток старого доброго времени (а, кажется, это было
совсем недавно — «как молоды мы были»), времени DOS-резидентов, командной
строки, капитана Нортона и первых (не смотря на их номер — 3.0) «форточек».
Черт, тут жизнь уже проходит, а DDE все еще жив. И слава Богу! Ведь, мы решим
«главную» проблему — сохранение содержимого буфера обмена. Вот так:
procedure TForm1.ToDDE(ISheet: IxlWorksheet); var xlDDE: TDDEClientConv; i: integer; IR1, IR2, IRange: IxlRange; Buff: string; begin Buff := ''; tblCust.First; while not tblCust.EOF do begin for i := 0 to tblCust.Fields.Count - 1 do begin Buff := Buff + FieldToStr(tblCust.Fields[i]); if i < (tblCust.Fields.Count - 1) then Buff := Buff + #9; end; tblCust.Next; if not tblCust.EOF then Buff := Buff + #10; end; IDispatch(IR1) := ISheet.Cells.Item[StartRow, StartColumn]; IDispatch(IR2) := ISheet.Cells.Item[StartRow + tblCust.RecordCount - 1, StartColumn + tblCust.Fields.Count - 1]; IRange := ISheet.Range[IR1, IR2]; xlDDE := TDDEClientConv.Create(Self); try if xlDDE.SetLink('EXCEL', ISheet.Name) then xlDDE.PokeData(OLEVariant(IRange).Address[ReferenceStyle:=xlR1C1], PChar(Buff)); finally xlDDE.Free; end; end;
Все реже я встречаю книги, где было бы описано взаимодействие
приложений посредством DDE. Многие и вовсе думают, что DDE уже давно умер. Но,
нет, «жив курилка». И, более того, это одно из самых быстрых решений по передаче
данных в Excel. И, что самое интересное, Excel по-прежнему поддерживает DDE и
все DDE-команды, которые стали доступны со времен версии 4.0. И по-прежнему
будет несказанно рад тот счастливчик, который обнаружит в непроходимых джунглях
Сети файл под названием «excel40macro.hlp», ибо там он найдет все, что нужно для
быстрой и качественной работы с Excel. Это вам не интерфейсы «пользовать». Но,
вернемся к исходному тексту.
В этой процедуре я, как было описано выше, прохожу по всей
таблице, собирая в строковый буфер значения полей, разделенные символом
табуляции. Записи же разделяются символом перевода строки. Затем я получаю
интерфейс на область, куда необходимо поместить данные из таблицы. Это первая
часть кода. Далее — самое интересное.
Переменная xlDDE используется для доступа к Excel посредством
DDE. Если опустить теорию, напрямую обратившись к практике, то можно увидеть
следующий алгоритм ее использования. Во-первых, создается экземпляр класса
TDDEClientConv. Во-вторых, вызовом SetLink происходит соединение через DDE с
запущенным Excel. SetLink возвращает true, если это соединение успешно. А далее
происходит вызов метода PokeData, одним из параметров которого является
строковый буфер Buff. Второй параметр — это адрес области в формате R1C1. Вот и
все. Думаю, это работает и у вас. Скорость сравнима с CSV через буфер обмена.
Плюс, здесь буфер обмена мы совсем не используем. Но!
Попробуйте несколько раз подряд быстро нажать кнопку «Send
data» с этим вариантом передачи данных. У меня Excel просто виснет. Точнее, он
что-то делает, загружая на все сто процессор. Благо, Windows NT безболезненно
позволяет снять задачу. Тем, у кого Win9x, повезло меньше и, видимо, им придется
перезагрузиться. Почему это происходит? Меня смутила вот эта строка в реализации
TDDEClientConv:
hdata := DdeClientTransaction(Pointer(hszDat), DWORD(-1), FConv, hszItem, FDdeFmt, XTYP_POKE, TIMEOUT_ASYNC, nil);
Точнее параметр TIMEOUT_ASYNC, позволяющий передавать данные
асинхронно. Вот и сыплется Excel, не выдерживая реализации DDE-клиента от
Borland/Inprise. Впрочем, Borland тоже не причем. Для себя я создал потомка
класса TDDEClientConv, добавив ему новый метод xlPokeData, в котором просто
заменил эту строку на:
Const xddeTransactionTimeOut = 100000; ... hdata := DdeClientTransaction(Pointer(hszDat), DWORD(-1), Conv, hszItem, CF_XLTABLE, XTYP_POKE, xddeTransactionTimeOut, nil); ...
И все в порядке — работает.
Я не стану описывать подробности взаимодействия процессов
через DDE по, думаю, понятным вам причинам. Все это давно описано в классике
жанра — документации по Delphi. Тем не менее, по-прежнему остается проблема со
строкой «0001». И останется она при этом варианте нерешенной, так как здесь
используются строковые представления всех значений полей. И где же выход,
спросите вы? Выход прост.
Из всего вышесказанного я бы хотел сделать один вывод. Если
есть желание получить максимальное быстродействие, то необходимо использовать
DDE. Впрочем, для меня это уже аксиома. Единственное, чего здесь не достает, так
это такого формата, чтобы…
Чтобы в нем использовались native представления данных, где
число было бы не строкой, а привычным набором из четырех (восьми) байт. Ведь,
напомню, целые и вещественные числа и даты — это, в конечном счете, вещественное
число в Excel. Для себя я решение нашел — Fast Table Format. Но это уже не из
этой статьи…
Демо-Проект — SampleExcel3 (в архиве с данной
статьёй).
Часть 7: Пример обмена данными с Excel используя VCL и OLE.
Автор: Bird Feniks.
VCL.
В Delphi 5 и выше, для обмена данными между Вашим приложением
и Excel можно использовать компонент TExcelApplication, доступный на Servers
Page в Component Palette.
Создаем новый проект. На форму кладем TStringGrid, заполняем
его некоторыми данными и добавляем две кнопки, с названиями «To Excel» и «From
Excel». Так же на форму кладем компонент TExcelApplication и в свойстве «Name»
указываем «XLApp», а свойство «ConnectKind» меняем на «ckNewInstance».
Когда нам необходимо работать с Excel, то обычно мы открываем
ExcelApplication, затем открываем WorkBook и в конце используем WorkSheet.
Итак, несомненный интерес представляет для нас листы
(WorkSheets) в книге (WorkBook). Давайте посмотрим как всё это работает.
Посылка данных в Excel.
Это можно сделать с помощью следующей процедуры :
procedure TForm1.BitBtnToExcelOnClick(Sender: TObject); var WorkBk : _WorkBook; // определяем WorkBook WorkSheet : _WorkSheet; // определяем WorkSheet I, J, K, R, C : Integer; IIndex : OleVariant; TabGrid : Variant; begin if GenericStringGrid.Cells[0,1] <> '' then begin IIndex := 1; R := GenericStringGrid.RowCount; C := GenericStringGrid.ColCount; // Создаём массив-матрицу TabGrid := VarArrayCreate([0,(R - 1),0,(C - 1)],VarOleStr); I := 0; // Определяем цикл для заполнения массива-матрицы repeat for J := 0 to (C - 1) do TabGrid[I,J] := GenericStringGrid.Cells[J,I]; Inc(I,1); until I > (R - 1); // Соединяемся с сервером TExcelApplication XLApp.Connect; // Добавляем WorkBooks в ExcelApplication XLApp.WorkBooks.Add(xlWBatWorkSheet,0); // Выбираем первую WorkBook WorkBk := XLApp.WorkBooks.Item[IIndex]; // Определяем первый WorkSheet WorkSheet := WorkBk.WorkSheets.Get_Item(1) as _WorkSheet; // Сопоставляем Delphi массив-матрицу с матрицей в WorkSheet Worksheet.Range['A1',Worksheet.Cells.Item[R,C]].Value := TabGrid; // Заполняем свойства WorkSheet WorkSheet.Name := 'Customers'; Worksheet.Columns.Font.Bold := True; Worksheet.Columns.HorizontalAlignment := xlRight; WorkSheet.Columns.ColumnWidth := 14; // Заполняем всю первую колонку WorkSheet.Range['A' + IntToStr(1),'A' + IntToStr(R)].Font.Color := clBlue; WorkSheet.Range['A' + IntToStr(1),'A' + IntToStr(R)].HorizontalAlignment := xlHAlignLeft; WorkSheet.Range['A' + IntToStr(1),'A' + IntToStr(R)].ColumnWidth := 31; // Показываем Excel XLApp.Visible[0] := True; // Разрываем связь с сервером XLApp.Disconnect; // Unassign the Delphi Variant Matrix TabGrid := Unassigned; end; end;
Получение данных из Excel.
Это можно сделать с помощью следующей процедуры :
procedure TForm1.BitBtnFromExcelOnClick(Sender: TObject); var WorkBk : _WorkBook; WorkSheet : _WorkSheet; K, R, X, Y : Integer; IIndex : OleVariant; RangeMatrix : Variant; NomFich : WideString; begin NomFich := 'C:MyDirectoryNameOfFile.xls'; IIndex := 1; XLApp.Connect; // Открываем файл Excel XLApp.WorkBooks.Open(NomFich,EmptyParam,EmptyParam,EmptyParam,EmptyParam, EmptyParam,EmptyParam,EmptyParam,EmptyParam, EmptyParam,EmptyParam, EmptyParam,EmptyParam,0); WorkBk := XLApp.WorkBooks.Item[IIndex]; WorkSheet := WorkBk.WorkSheets.Get_Item(1) as _WorkSheet; // Чтобы знать размер листа (WorkSheet), т.е. количество строк и количество // столбцов, мы активируем его последнюю непустую ячейку WorkSheet.Cells.SpecialCells(xlCellTypeLastCell,EmptyParam).Activate; // Получаем значение последней строки X := XLApp.ActiveCell.Row; // Получаем значение последней колонки Y := XLApp.ActiveCell.Column; // Определяем количество колонок в TStringGrid GenericStringGrid.ColCount := Y; // Сопоставляем матрицу WorkSheet с нашей Delphi матрицей RangeMatrix := XLApp.Range['A1',XLApp.Cells.Item[X,Y]].Value; // Выходим из Excel и отсоединяемся от сервера XLApp.Quit; XLApp.Disconnect; // Определяем цикл для заполнения TStringGrid K := 1; repeat for R := 1 to Y do GenericStringGrid.Cells[(R - 1),(K - 1)] := RangeMatrix[K,R]; Inc(K,1); GenericStringGrid.RowCount := K + 1; until K > X; // Unassign the Delphi Variant Matrix RangeMatrix := Unassigned; end;
OLE.
Ниже представлен пример создания новой таблицы в Excel 2000:
uses ComObj, ActiveX; var Row, Col: integer; DestRange: OleVariant; Excel: Variant; begin Excel := CreateOleObject('Excel.Application.9'); Excel.Visible := True; Excel.WorkBooks.Add; //Создать новую таблицу //Можно помещать текст и значения в диапазон ячеек //Поместить слово тест в диапазон ячеек Excel.ActiveSheet.Range['A2', 'B3'].Value := 'Тест'; //Или число Excel.ActiveSheet.Range['A4', 'B5'].Value := 42; //А вот так задаётся формула Excel.ActiveSheet.Range['A10', 'A11'].Formula := '=RAND()'; //Можно задавать номера ячеек и столбцов Excel.ActiveSheet.Cells.Item[1, 1].Value := 'Первая ячейка'; Row:=1; Col:=3; Excel.ActiveSheet.Cells.Item[Row, Col].Value := 'Другая ячейка'; //Можно скопировать данный из одного диапазона ячеек в другой DestRange := Excel.Range['D6', 'F10']; Excel.Range['A1', 'C5'].Copy(DestRange); //Можно задавать параметры шрифта в определённой ячейке Excel.Range['A2', 'A2'].Font.Size := 20; Excel.Range['A2', 'A2'].Font.FontStyle := 'Bold'; Excel.Range['A2', 'A2'].Font.Color := clFuchsia; Excel.Range['A2', 'A2'].Font.Name := 'Arial'; //Можно ещё и так изменить цвет диапазона ячеек Excel.Range['B2', 'C6'].Interior.Color := RGB(223, 123, 123); end;
Далее представлен пример открытия и закрытия таблицы:
uses ComObj, ActiveX; var Excel: Variant; WBk : OleVariant; SaveChanges: OleVariant; begin Excel := CreateOleObject('Excel.Application.9'); Excel.Visible := True; //Открыть существующую таблицу WBk := Excel.WorkBooks.Open('C:Test.xls'); ... WBk.Close(SaveChanges := True); Excel.Quit; end;
Проблема при проверке значения ячейки в Excel через Delphi
- Подписаться на тему
- Сообщить другу
- Скачать/распечатать тему
|
|
Junior Рейтинг (т): нет |
Добрый день! Столкнулся с такой проблемой мне нужно проверить значение ячейки в Excel, а именно какой номер квартала находиться в нужной мне ячейке, так же нужно проверить не пустая ли это ячейка написал следующий код: if (Excel.ActiveWorkBook.WorkSheets[1].Cells[i+6, 10].value<>1) and (Excel.ActiveWorkBook.WorkSheets[1].Cells[i+6, 10].value<>2) and (Excel.ActiveWorkBook.WorkSheets[1].Cells[i+6, 10].value<>3) and (Excel.ActiveWorkBook.WorkSheets[1].Cells[i+6, 10].value<>4) and (Excel.ActiveWorkBook.WorkSheets[1].Cells[i+6, 10].value<>») then Выдает следующую ошибку «Could not convert variant of type (String) into type double « Как можно еще сделать подобную проверку, может у меня не правильный подход к этому?! Так есть вариант написать такую проверку в макросе в отдельном файле, но возникают такие вопросы: Сообщение отредактировано: bas_sanya — 03.07.08, 08:15 |
vladimir74 |
|
а сразу вынимать значения как double не пробывал? Еще лучше если эти значения часто проверяются, сначала перегнать значения во временные переменные double при этом проверить чтоб там небыло строк, а потом сравнивать переменные…. |
0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
0 пользователей:
- Предыдущая тема
- Delphi: Система, Windows API
- Следующая тема
[ Script execution time: 0,0337 ] [ 16 queries used ] [ Generated: 13.04.23, 22:37 GMT ]
Now write codes using above variables on a Button click or other appropriate event.
1. Create and connect with an Excel Application…
myxlApp := TExcelApplication.Create(Nil);
myxlApp.Connect;
myxlApp.Visible[LCID] := True; // will show newly connected Excel application // most of case not required //
2. Close and Free the Excel application….
myxlApp.Disconnect;
myxlApp.Quit;
FreeAndNil(myxlApp);
3. Add a Workbook
myxlApp.Workbooks.Add(EmptyParam, LCID); //it will also add a default sheet to workbok//
myxlBook := TExcelWorkbook.Create(myxlApp);
myxlBook.ConnectTo(myxlApp.ActiveWorkbook);
4. Disconnect Workbook before close
myxlBook.Close(True,’C:jitendraExcelTest1.xlsx’); //Saves the changes to mentioned file//
myxlBook.Disconnect;
FreeAndNil(myxlBook);
5. Add new Worksheet
myxlSheet11 := TExcelWorksheet.Create(myxlBook);
myxlSheet11.ConnectTo(myxlBook.ActiveSheet as _worksheet); //connecting with the default worksheet//
myxlSheet11.Name := ‘Class 11’;
6. Disconnect worksheet before close
myxlSheet11.Disconnect;
FreeAndNil(myxlSheet11);
7. Adding a new Worksheet to the Workbook
myxlBook.Worksheets.Add(EmptyParam, EmptyParam, EmptyParam, EmptyParam, LCID);
myxlSheet12 := TExcelWorksheet.Create(myxlBook);
myxlSheet12.ConnectTo(myxlBook.ActiveSheet as _worksheet);
myxlSheet12.Name := ‘Class 12’;
8. Access Sheets by Index or Name
(myxlApp.Worksheets[0] as _Worksheet).Activate(LCID);
Or
(myxlApp.Worksheets[‘Sheet1’] as _Worksheet).Activate(LCID);
9. Assign values to Cell by using Cell or Range property
myxlApp.Cells.Item[1,1] := ‘Value 1’; //with row, col number//
myxlApp.Range[‘A3′,’A3’].Value := ‘value 2’; //with cell from, to names//
myxlSheet11.Cells.Item[1,5] := ‘JITENDRA’; //with row, col number//
myxlSheet11.Range[‘E3′,’E3’].Value := ‘7834911261’; //with cell from, to names//
10. Change font format of an Excel Range
with myxlSheet11.Range[‘A1’, ‘B3’] do
begin
Font.Name := ‘Verdana’;
Font.Size := 15;
Font.Bold := True;
Font.Strikethrough := True;
Font.Color := clRed;
end;
11. Change Background Color of cells
with myxlSheet11.Range[‘A1’, ‘A1’].Interior.Color := clYellow;
myxlSheet11.Range[‘A5’, ‘D7’].Merge(False);// merge cells and fill color in merged cells//
myxlSheet11.Range[‘A5’, ‘D7’].Interior.Color := clRed;
12. Merge Cells in a range
myxlSheet11.Range[‘A5’, ‘D7’].Merge(False); //False by default if True it would merge cells row by row//
myxlSheet11.Range[‘A5’, ‘D7’].Value := ‘Merged data’;
13. Change Column width and Row height
myxlSheet11.Range[‘B5’, ‘B5’].ColumnWidth := 5; //single column B//
myxlSheet11.Range[‘J5’, ‘L8’].ColumnWidth := 15; //multiple column J,K,L//
myxlSheet11.Range[‘B5’, ‘B5’].RowHeight := 50; //single row 5//
myxlSheet11.Range[‘J10’, ‘J15’].RowHeight := 50; //multiple row 10-15//
14. Open the workbook that already exists:
myxlApp.Workbooks.Open ( ‘C:jitendraExcelTest1.xlsx’
EmptyParam , EmptyParam , EmptyParam , EmptyParam ,
EmptyParam , EmptyParam , EmptyParam , EmptyParam ,
EmptyParam , EmptyParam , EmptyParam , EmptyParam , 0 );
15. Copy and Paste Data from one cell to another in same sheet…
a.
myxlSheet11.UsedRange[LCID].Copy(myxlSheet11.Range[‘J10’, ‘J10’]);
myxlSheet11.Range[‘A5’, ‘D7’].Copy(myxlSheet11.Range[‘J10’, ‘J10’]);
b.
myxlSheet11.UsedRange[LCID].Copy(EmptyParam);
myxlSheet11.Range[‘J10’, ‘J10’].PasteSpecial(xlPasteAll, xlPasteSpecialOperationNone, EmptyParam, EmptyParam);
myxlSheet11.Range[‘A5’, ‘D7’].Copy(EmptyParam);
myxlSheet11.Range[‘J10’, ‘J10’].PasteSpecial(xlPasteAll, xlPasteSpecialOperationNone, EmptyParam, EmptyParam);
16. Copy and Paste Data from one Sheet to another sheet.
a.
myxlSheet11.UsedRange[LCID].Copy(myxlSheet12.Range[‘J10’, ‘J10’]);
myxlSheet11.Range[‘A5’, ‘D7’].Copy(myxlSheet12.Range[‘J10’, ‘J10’]);
b.
myxlSheet11.UsedRange[LCID].Copy(EmptyParam);
myxlSheet12.Range[‘J10’, ‘J10’].PasteSpecial(xlPasteAll, xlPasteSpecialOperationNone,EmptyParam, EmptyParam);
myxlSheet11.Range[‘A5’, ‘D7’].Copy(EmptyParam);
myxlSheet12.Range[‘J10’, ‘J10’].PasteSpecial(xlPasteAll, xlPasteSpecialOperationNone,EmptyParam, EmptyParam);
17. Insert new columns before b1
myxlSheet11.Range[‘b1’, ‘b1’].Columns.Insert(xlShiftToRight); // we can use xlShiftToLeft//
18. Insert new rows above b2
myxlSheet11.Range[‘b2’, ‘b2’].Rows.Insert(xlShiftDown); // we can use xlShiftUp//
19. Clear a Selected Range Content or Format
myxlSheet11.Range[‘b3’, ‘b10’].ClearContents;
myxlSheet11.Range[‘b3’, ‘b10’].ClearFormats;
20.Save, Save as a Sheet / Workbook
myxlSheet11.SaveAs(‘Filename’);
myxlBook.Save;
21. Print Preview / Print of a Sheet / Workbook
myxlSheet11.PrintPreview;
myxlSheet11.PrintOut;
myxlBook.PrintPreview;
myxlBook.PrintOut;
22. Set Sheet PageSetup
myxlSheet11.PageSetup.
A. header:
myxlSheet11.PageSetup.CenterHeader := » The report shows » ;
B. footer:
myxlSheet11.PageSetup.CenterFooter := » The & P » ;
The C. header into the top margin 2cm:
myxlSheet11.PageSetup.HeaderMargin := 2 / 0.035 ;
D. footer bottom margin 3cm:
myxlSheet11.PageSetup.HeaderMargin := 3 / 0.035 ;
E. top margin 2cm:
myxlSheet11.PageSetup.TopMargin := 2 / 0.035 ;
The bottom edge of the f. from the 2cm:
myxlSheet11.PageSetup.BottomMargin := 2 / 0.035 ;
G. left 2cm:
myxlSheet11.PageSetup.LeftMargin := 2 / 0.035 ;
On the right side of the H. from the 2cm:
myxlSheet11.PageSetup.RightMargin := 2 / 0.035 ;
I. pages horizontally:
myxlSheet11.PageSetup.CenterHorizontally := 2 / 0.035 ;
The J. page vertically:
myxlSheet11.PageSetup.CenterVertically := 2 / 0.035 ;
K. print cell line:
myxlSheet11.PageSetup.PrintGridLines := True ;
23. Auto Fill of Range. Fills value 1-10 in p1:p10
myxlSheet11.Range[‘p1’, ‘p1’].Value := 1;
myxlSheet11.Range[‘p2’, ‘p2’].Value := 2;
myxlSheet11.Range[‘p1’, ‘p1’].AutoFill(myxlSheet11.Range[‘p1’, ‘p10’], xlFillSeries);
Other fill options
xlFillCopy
xlFillDays
xlFillDefault
xlFillFormats
xlFillMonths
xlFillSeries
xlFillValues
xlFillWeekdays
xlFillYears
xlGrowthTrend
xlLinearTrend
24. Change Border style of cells in a range
myxlSheet11.Range[‘p3’, ‘p4’].Borders.Color := clRed;
myxlSheet11.Range[‘p3’, ‘p4’].Borders.LineStyle := xlDouble;
myxlSheet11.Range[‘p3’, ‘p4’].Borders.Item[xlEdgeLeft].Color := clBlue;
myxlSheet11.Range[‘p3’, ‘p4’].Borders.Item[xlEdgeRight].Color := clBlue;
Other line styles.
xlContinuous
xlDash
xlDashDot
xlDashDotDot
xlDot
xlDouble
xlSlantDashDot
xlLineStyleNone
25. Fill pattern style of cells in a range
myxlSheet11.Range[‘p3’, ‘p4’].Interior.Pattern := xlPatternCrissCross;
myxlSheet11.Range[‘p3’, ‘p4’].Interior.PatternColor := clBlue;
Other pattern styles
xlPatternAutomatic
xlPatternChecker
xlPatternCrissCross
xlPatternDown
xlPatternGray16
xlPatternGray25
xlPatternGray50
xlPatternGray75
xlPatternGray8
xlPatternGrid
xlPatternHorizontal
xlPatternLightDown
xlPatternLightHorizontal
xlPatternLightUp
xlPatternLightVertical
xlPatternNone
xlPatternSemiGray75
xlPatternSolid
xlPatternUp
xlPatternVertical
26. Add calculation function SUM/AVG/MAX/COUNT etc..
myxlSheet11.Range[‘k1’, ‘k1’].Formula := ‘=Sum(p3:p8)’;
myxlSheet11.Range[‘k3’, ‘k3’].Formula := ‘=Avg(p3:p8)’;
myxlSheet11.Range[‘k5’, ‘k5’].Formula := ‘=Max(p3:p8)’;
myxlSheet11.Range[‘k7’, ‘k7’].Formula := ‘=Count(p3:p8)’;