Статьи

Суперфункции (№20, 2003 год)
Возможность формирования ваше программой документов непосредственно в формате Word или Excel выгодно отличало бы ее от аналогов...

Суперфункции (№21, 2003 год)
Используя материалы первой и второй частей этой статьи, мы уже имеем возможность предоставить пользователю программу формирования документа в Word в законченном виде

Суперфункции (№22, 2003 год)
Тема третьей части статьи - создание таблиц в редакторе Word из приложений, написанных на Delphi


Перейти к описанию книги “Программирование документов и приложений MS Office в Delphi”


Суперфункции (№23, 2003 год)
Многие информационно-правовые системы содержат шаблоны документов в формате Word. Используя их и информацию статьи, вы можете легко и быстро создавать отчеты, если пишете программы на Delphi

Суперфункции (№24, 2003 год)
Используя доступ к Word.Application из приложений Delphi, можно вставлять в текст документа записи, рисунки и другие объекты...

Суперфункции (№25, 2003 год)
Начинаем создавать отчеты в Excel из приложений, разрабатываемых в Delphi...

Суперфункции (№26, 2003 год)
Рассмотрим формирование формата данных ячейки листа книги Excel

Суперфункции (№27, 2003 год)
Продолжим программирование свойств ячеек таблиц Excel...

Суперфункции (№28, 2003 год)
Эта часть посвящена функциям настройки общих параметров листа Excel, выбора и настройки принтера, подготовки листа и функциям печати

Суперфункции (№29, 2003 год)
В Excel есть возможность программировать отображение информации в виде диаграмм и графиков, и вы можете воспользоваться этим, чтобы сделать свою программу более информативной

Суперфункции (№31, 2003 год)
Продолжим программирование диаграмм в Excel...

Суперфункции (№34, 2003 год)
Создание DLL-библиотеки для работы с Word/Excel из приложений на Delphi

Суперфункции (№35, 2003 год)
Создание средствами Delphi DLL библиотек для использования в макросах Excel

Суперфункции (№37, 2003 год)
Ответы на вопросы


 

Суперфункции

Так как многие разрабатываемые приложения формируют множество выходных отчетных форм для печати, то возможность формирования ими документов непосредственно в формате Word или Excel выгодно отличало бы их от своих аналогов.

Каждый, кто серьезно занимается разработкой программного обеспечения, заинтересован, чтобы его произведение пользовалось успехом у пользователей. Поэтому он вынужден удовлетворять постоянно растущие их требования к программному обеспечению. Не секрет, что большинство пользователей начинали свое знакомство с компьютером с изучения текстового редактора Word и электронных таблиц Excel. К тому же эти редакторы имеют огромные возможности и постоянно совершенствуются, они получили широкое распространение, для них написано сотни томов обучающей литературы, их изучают во всех учебных заведениях, и, самое главное, они - очень удобный инструмент для создания текстовых документов любой сложности. Отсюда простой вывод: большинство пользователей положительно воспримут тот факт, что ваша программа будет формировать выходные документы в формате Word или Excel.

Теперь остановимся на постановке задачи, описанной в этой статье. Как формировать документ в формате Word? Очень просто. Текстовый редактор Word представляет собой COM-сервер и может получать и обрабатывать запросы от внешних программ. Все это позволяет организовать процесс управления и создания документа из внешней программы. Используя этот механизм, можно создать документ программно так же, как это делается вручную (посредством меню, кнопок и клавиатуры), но гораздо быстрей и эффектней.

Приступим к решению задачи. Как было сказано выше, Word является COM-сервером и может управляться внешними программами. Для этого Word предоставляет три объекта, через которые можно получить доступ к внутренним объектам Word`а и документов. Эти объекты - Word.Application, Word.Document и Word.Basic. Ко всем остальным объектам (текст, таблицы, кнопки, меню и др.) доступ возможен только через них.

Чтобы реализовать все эти возможности Word`а и для удобства своей работы мне пришлось разработать динамическую библиотеку процедур и функций, которую можно было использовать в различных своих приложениях для формирования и печати выходных документов. Зачем нужна такая библиотека, почему бы не вставлять программный код непосредственно в программу? Здесь причина в универсальности и гибкости использования библиотеки. Поэтому все ниже описанные коды легко могут быть оформлены в виде библиотеки для того, чтобы вы могли использовать ее непосредственно в своих приложениях, не теряя зря времени.

Чтобы почувствовать эффективность использования объектов Word, для начала попробуем написать несколько функций, которые позволят запустить Word, создать документ, изменить документ (записать текст), сохранить документ и закрыть Word. Для создания объекта и его использования применяем переменную W типа variant и библиотеку ComObj.

Рассмотрим следующий фрагмент кода:

uses ComObj;
var W:variant;
Function CreateWord:boolean;
begin
 CreateWord:=true;
 try
 W:=CreateOleObject('Word.Application');
 except
 CreateWord:=false;
 end;
End;

Для получения доступа к объекту Word.Application в нашей функции CreateWord используем конструктор CreateOleObject ('Word. Application'). Если редактор Word не установлен в системе, то будет сгенерирована ошибка, и мы получим значение функции = false, если Word установлен, и объект будет создан, то получим значение функции = true.

Эта функция создает объект (W), свойства и методы которого мы будем использовать в дальнейшем. Если выполнить нашу функцию CreateWord, то Word будет запущен, но не появится на экране, потому что по умолчанию он запускается в фоновом режиме. Чтобы его активировать (сделать видимым) или деактивировать (сделать невидимым), используйте свойство visible объекта W. Оформим это в виде функции VisibleWord. Скобки try except везде используются для обработки исключительных ситуаций.

Function VisibleWord (visible:boolean):boolean;
begin
 VisibleWord:=true;
 try
 W.visible:= visible;
 except
 VisibleWord:=false;
 end;
End;

Используя эту функцию, мы можем показывать или прятать Word с документами.

Следующим шагом будет создание документа. Для этого используем объект Documents объекта W. Этот объект имеет метод Add, используя который, и создаем новый документ. При этом, как альтернативный вариант, вместо двух операторов Doc_:=W.Documents; Doc_.Add; можем использовать один W.Documents.Add;.

Function AddDoc:boolean;
Var Doc_:variant;
begin
 AddDoc:=true;
 try
 Doc_:=W.Documents;
 Doc_.Add;
 except
 AddDoc:=false;
 end;
End;

Создали документ, что дальше? Следующим шагом, естественно, является запись любого текста непосредственно в документ. Создадим для этого функцию SetTextToDoc.

Function SetTextToDoc(text_: string;InsertAfter_: boolean): boolean;
var Rng_:variant;
begin
 SetTextToDoc:=true;
 try
 Rng_:=W.ActiveDocument.Range;
 if InsertAfter_
  then Rng_.InsertAfter(text_)
  else Rng_.InsertBefore(text_);
 except
 SetTextToDoc:=false;
 end;
End;

В этой функции используем объект Range и его методы InsertAfter и InsertBefore для того, чтобы вставить текст в документ с позиции курсора или до позиции курсора. Наша функция будет вставлять текст в активный документ в область курсора или выделенного текста.

Фрагмент кода:

Rng_:=W.ActiveDocument.Range;
if InsertAfter_
 then Rng_.InsertAfter(text_)
else Rng_.InsertBefore(text_);

можно заменить следующим фрагментом:

if InsertAfter_
 then W.ActiveDocument.Range. InsertAfter(text_)
else W.ActiveDocument.Range. InsertBefore(text_);

После того, как документ создан и в него записан текст, его необходимо сохранить. Для этого используем метод SaveAs объекта ActiveDocument. Функция SaveDocAs использует этот метод и сохраняет документ в заданный файл.

Function SaveDocAs(file_:string):boolean;
begin
 SaveDocAs:=true;
 try
 W.ActiveDocument.SaveAs(file_);
 except
 SaveDocAs:=false;
 end;
End;

Закрыть сохраненный документ можно, используя метод Close объекта ActiveDocument.

Function CloseDoc:boolean;
begin
 CloseDoc:=true;
 try
 W.ActiveDocument.Close;
 except
 CloseDoc:=false;
 end;
End;

Закрыть Word можно, используя метод Quit объекта Application(W).

Function CloseWord:boolean;
begin
 CloseWord:=true;
 try
 W.Quit;
 except
 CloseWord:=false;
 end;
End;

Таким образом, мы уже имеем несколько функций, которыми можно создать документ, записать в него текст, сохранить документ и отобразить его на экране монитора. Используя несколько строк, состоящих из функций нашей библиотеки, мы создаем документ, записываем в него текст, сохраняем и закрываем. Для демонстрации этого на новой форме разместим на кнопку и скопируем исходные тексты функций в модуль формы. В процедуру обработки нажатия кнопки разместим следующий программный текст.

procedure TForm1.Button1Click(Sender: TObject);
begin
 if CreateWord
  then begin
   Messagebox(0,'Word запущен.','',0);
   VisibleWord(true);
   Messagebox(0,'Word видим.','',0);
   VisibleWord(false);
   Messagebox(0,'Word невидим.','',0);
   VisibleWord(true);
   Messagebox(0,'Word видим.','',0);
   If AddDoc then begin
    Messagebox(0,'Документ создан.','',0);
    SetTextToDoc('Мой первый текст',true);
    Messagebox(0,'Добавлен текст','',0);
    SaveDocAs('c:\Мой первый текст');
    Messagebox(0,'Текст сохранен','',0);
    CloseDoc;
   end;
   Messagebox(0,' Текст закрыт','',0);
   CloseWord;
  end;
end;

Конечно, набора данных функций недостаточно для создания полноценного отчета. Было бы эффективным создать шаблон некоего документа и затем заполнять его реальными значениями из базы данных, но для этого, как минимум, потребуется еще ряд функций. Такими функциями могут быть открытие ранее созданного документа, поиск текста, замена, копирование. Далее будут рассмотрены реализации этих функций и создание на их базе простого документа, например, платежного поручения. По всем вопросам, касающимся материала этой статьи, вы можете обратиться к автору по адресу _kvn@mail.ru.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А.Тенцер "Delphi 6 и технология COM" "Питер" 2002.

К списку статей


Суперфункции

(Начало в №20)

Часть 2

Труд программиста оценивается только пользователями и почти всегда по конечному результату. Используя материалы первой и второй частей статьи "Суперфункции", мы уже имеем возможность предоставить пользователю свою программу формирования простого документа в редакторе Word в законченном виде.

В первой части мы разработали и использовали функции создания и сохранения документа, а также функции записи текста, но этого недостаточно для подготовки даже простого документа. Каким набором функций нужно пользоваться, чтобы подготовить, например, документ типа "Платежное поручение"?

Поставим задачу: создание документа "Платежное поручение", - и определим, какие функции для этого необходимы. Сам по себе документ "Платежное поручение" является табличным, т.е. в определенную таблицу вписаны значения некоторых текстовых и числовых переменных. К тому же этот документ не является многострочным. Можно найти еще массу примеров таких документов, поэтому технология подготовки "Платежного поручения" подойдет к большому количеству аналогичных документов.

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

Определим функцию открытия ранее созданного документа OpenDoc. Для этого используем метод Open коллекции Documents, которая нами уже использовалась в функции создания нового документа. Функция Open, кроме обязательного аргумента (имени файла), может иметь ряд дополнительных аргументов, которые определяют режим открытия. Она возвращает ссылку на объект типа Document, но в нашем случае будем использовать только обязательный аргумент.

Function OpenDoc (file_:string):boolean;
 Var Doc_:variant;
begin
 OpenDoc:=true;
 try
  Doc_:=W.Documents;
  Doc_.Open(file_);
 except
  OpenDoc:=false;
 end;
End;

Фрагмент из двух операторов

Doc_:=W.Documents;
Doc_.Open(file_);

можно заменить одним

W.Documents.Open(file_);

Для перевода курсора в начало документа используем свойства End и Start объекта W.Selection. Эту функцию необходимо использовать каждый раз перед началом поиска текста, чтобы поиск осуществлялся с начала документа. Свойства End и Start объекта Selection можно использовать и для выделения диапазона текста, при этом в Start записывается номер начального символа фрагмента в тексте, а в End - номер конечного. В данном случае необходимо в оба поля записать нули.

Function StartOfDoc:boolean;
begin
 StartOfDoc:=true;
 try
  W.Selection.End:=0;
  W.Selection.Start:=0;
 except
  StartOfDoc:=false;
 end;
End;

Функция поиска (FindTextDoc) фрагмента текста состоит из трех операторов. Первый и второй задают направление поиска (от начала к концу) и фрагмент для поиска, соответственно. Третий оператор выполняет поиск и возвращает результат. Функция возвращает True, если поиск удачный, и False - если нет. Во всех трех операторах используем поля и методы объекта Selection.

Function FindTextDoc (text_:string):boolean;
begin
 FindTextDoc:=true;
 Try
  W.Selection.Find.Forward:=true;
  W.Selection.Find.Text:=text_;
  FindTextDoc := W.Selection.Find.Execute;
 except
  FindTextDoc:=false;
 end;
End;

Функция FindTextDoc находит и выделяет фрагмент текста в документе. Для того, чтобы вставить новый текст вместо выделенного, создадим еще одну функцию. PasteTextDoc состоит из двух операторов, удаления выделенного фрагмента и вставки нового текста с положения курсора. Оба эти оператора используют объект Selection объекта W. Действие этой функции отличается от SetTextToDoc тем, что она вставляет изменения вместо выделенного фрагмента текста.

Function PasteTextDoc (text_:string):boolean;
begin
 PasteTextDoc:=true;
 Try
  W.Selection.Delete;
  W.Selection.InsertAfter (text_);
 except
  PasteTextDoc:=false;
 end;
End;

Но более удобной была бы функция, которая одновременно подставляла бы новый текст на место найденного фрагмента. Создадим такую функцию.

Function FindAndPasteTextDoc
 (findtext_,pastetext_:string): boolean;
begin
 FindAndPasteTextDoc:=true;
 try
  W.Selection.Find.Forward:=true;
  W.Selection.Find.Text:= findtext_;
  if W.Selection.Find.Execute then begin
   W.Selection.Delete;
   W.Selection.InsertAfter (pastetext_);
  end else FindAndPasteTextDoc:=false;
 except
  FindAndPasteTextDoc:=false;
 end;
End;

И последнее, печать документа. В данной части рассмотрим только процедуру активизации диалогового окна печати. Этот диалог активизируется через метод Show объекта Dialogs(wdDialogFilePrint).Show. С помощью объекта Dialogs можно вызвать практически любое диалоговое окно Word'а, но об этих возможностях поговорим позже.

Функция будет выглядеть следующим образом:

Function PrintDialogWord:boolean;
 Const wdDialogFilePrint=88;
begin
 PrintDialogWord:=true;
 try
  W.Dialogs.Item(wdDialogFilePrint).Show;
 except
  PrintDialogWord:=false;
 end;
End;

Имея необходимый набор функций, можно приступать к написанию программы (процедуры) создания простого документа Word средствами Delphi. Как говорилось ранее, для формирования документа нам необходим шаблон - текст в формате Word (файл с расширением doc, rtf). Создадим вручную этот файл и разместим его, например, на диске C: "C:\Шаблон платежного поручения.doc". Полный пример с исходными текстами можно взять на моей домашней странице (www.kornjakov.ru/st1_2.zip), а здесь, с целью экономии объема, представлен только фрагмент документа (см.рис.).

Общий алгоритм формирования документа таков:

  1. Открываем шаблон, используя функцию открытия ранее созданного документа.
  2. Ищем слова-переменные и подставляем вместо них реальные значения, например, из базы данных.
  3. Сохраняем документ под новым именем.
  4. Печатаем документ, если это необходимо.
  5. Закрываем документ.

Документ готов, и с ним можно работать как обычно, копировать, переименовывать и др.

Описанный выше алгоритм реализуем в виде небольшой программы. Для этого создаем новый проект и переписываем все функции (также и ранее созданные в первой части статьи) в модуль формы. Создаем на форме кнопку и в процедуру обработки ее нажатия пишем следующий программный код.

procedure TForm1.Button2Click(Sender: TObject);
begin
 if CreateWord then begin
  VisibleWord(true);
  If OpenDoc('c:\Шаблон платежного поручения.rtf') then begin
   messagebox(0,'Переходим к заполнению шаблона','Шаблон открыт',0);
   StartOfDoc; while not
    FindAndPasteTextDoc('###№ П.П.&','21') do;
   StartOfDoc; while not
    FindAndPasteTextDoc('###Дата&','21.05.2003') do;
   StartOfDoc; while not
    FindAndPasteTextDoc('###Вид платежа&','обычный') do;
   StartOfDoc; while not
    FindAndPasteTextDoc('###Сумма прописью&','Сто пятьдесят рублей 40 коп.') do;
   SaveDocAs('c:\Платежное поручение.rtf');
   messagebox(0,'Переходим к печати документа',
    'Документ сформирован и сохранен',0);
   PrintDialogWord;
   CloseDoc;
  end;
  CloseWord;
 end;
end;

Данная процедура сформирует документ и откроет окно диалога печати.

Мы сформировали простой документ, но обычно сложные документы содержат таблицы, графики, рисунки и другие компоненты. Все эти компоненты также можно создавать и настраивать из внешних программ, используя объекты и коллекции объекта Application. Все эти вопросы будут рассмотрены в следующей части статьи, там же в качестве примера рассмотрим создание документа, содержащего таблицу. По всем вопросам, касающимся материала этой статьи, вы можете обратиться к автору по адресу www.kornjakov.ru или _kvn@mail.ru.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А. Тенцер "Delphi 6 и технология COM" "Питер" 2002.

К списку статей


Суперфункции

(Начало в №20)

Часть 3

Темой этой части статьи будет создание таблиц в редакторе Word из приложений, написанных на Delphi. В прошлый раз мы рассмотрели создание простых документов, которые не содержат таблиц переменной длины, но большинство отчетов так или иначе содержит табличное представление информации. Уверен, что хоть один отчет в вашей программе содержит хоть одну таблицу. Поэтому информации двух предыдущих частей статьи было бы недостаточно для создания отчета, содержащего табличное представление информации.

Как создать таблицу в Word'е? Так же просто, как это делается в обычном объектно-ориентированном языке. В объекте Document мы имеем коллекцию Tables, с помощью методов и объектов которой можем создать таблицу и получить доступ к ее свойствам, ячейкам и тексту в ячейках. Если в нашем отчете несколько таблиц, то к любой из них мы имеем доступ с помощью коллекции Tables и индекса таблицы.

Чтобы более ясно представить процесс создания таблицы, используя объектные модели MS Office, создадим документ, аналог которого после простой доработки можно будет использовать в своих программах для вывода информации. Одним из самых распространенных отчетов, содержащих таблицу, является документ типа "Прайс-лист". Его мы и будем создавать. Попробуем создать его без шаблона, т.е. с чистого листа. Определимся, каким набором функций нужно владеть для создания этого документа. Во-первых, нам нужна будет функция создания таблицы, затем потребуется задать(изменить) размеры этой таблицы, вписать данные в ячейки, объединить ячейки. Возможно, потребуется еще несколько вспомогательных функций. Творчески используя материал статьи, вы сможете сами определить и создать для себя еще несколько функций для работы с таблицами.

Определим функцию создания таблицы CreateTable. Так как количество таблиц в документе может быть больше одной, то для идентификации каждой таблицы используем ее номер. Для создания применим метод ADD коллекции Tables. Метод ADD имеет аргументы: область, где создается таблица, количество строк и количество столбцов. Наша функция будет создавать таблицу там, где расположен курсор, и иметь еще один аргумент: числовую переменную, через которую будет возвращаться порядковое значение(индекс) таблицы в документе. Функция выглядит следующим образом:

Function CreateTable(NumRows, NumColumns:integer;
  var index:integer):boolean;
 var sel_:variant;
begin
 CreateTable:=true;
 try
  sel_:=W.selection;
  W.ActiveDocument.Tables.Add (Range:=sel_.Range,NumRows: =NumRows,
   NumColumns:=NumColumns);
  index:=W.ActiveDocument. Tables.Count;
 except
  CreateTable:=false;
 end;
End;

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

Наша функция создаст таблицу произвольного размера, но для корректного представления данных необходимо задать определенные размеры строк и столбцов. Чтобы задать размер таблицы или строки(столбца), нужно получить доступ к таким свойствам таблицы, как коллекции Columns и Rows (список столбцов и строк), через которые сможем получить доступ к конкретной строке или(и) столбцу, к ячейкам и к параметрам ячейки(строки, столбца). Для этого используем объект ActiveDocument.Tables.Item(table), где table - номер таблицы в документе. Создадим функцию, которая будет задавать ширину и высоту всех ячеек таблицы.

Function SetSizeTable(Table:integer; RowsHeight,
  ColumnsWidth:real):boolean;
begin
 SetSizeTable:=true;
 try
  W.ActiveDocument.Tables.Item (Table).Columns.Width:=ColumnsWidth;
  W.ActiveDocument.Tables.Item(Table). Rows.Height:=RowsHeight;
 except
  SetSizeTable:=false;
 end;
End;

Аналогично мы можем задавать высоту любой строки или(и) ширину любого столбца на выбор. Для доступа к размерам ячейки используем также коллекции Rows, Columns объекта Table. Чтобы воспользоваться этими возможностями из нашего приложения, создадим следующие функции.

Function SetHeightRowTable(Table,Row:integer;
  RowHeight:real):boolean;
begin
 SetHeightRowTable:=true;
 try
  W.ActiveDocument.Tables.Item(Table).Rows.item(Row).Height:=RowHeight;
 except
  SetHeightRowTable:=false;
 end;
End;
Function SetWidthColumnTable(Table,Column: integer;
  ColumnWidth:real):boolean;
begin
 SetWidthColumnTable:=true;
 try
  W.ActiveDocument.Tables.Item(Table).Columns.
   Item(Column).Width:=ColumnWidth;
 except
  SetWidthColumnTable:=false;
 end;
End;

Возможно, нам придется не только задавать размеры таблицы, но и определять(считывать) размеры ячеек таблицы. Для этого используем те же коллекции, объекты и свойства таблицы, что и в функции SetSizeTable, но немного изменим внутренние операторы таким образом, что в возвращаемые переменные RowsHeight и ColumnsWidth будут записываться значения размеров строк и столбцов таблицы.

Function GetSizeTable(Table:integer;var RowsHeight,
  ColumnsWidth: real):boolean;
begin
 GetSizeTable:=true;
 try
  ColumnsWidth:=W.ActiveDocument. Tables.Item(Table).Columns.Width;
  RowsHeight:=W.ActiveDocument. Tables.Item(Table).Rows.Height;
 except
  GetSizeTable:=false;
 end;
End;

Также можно считать и размеры строки или столбца на выбор, для этого достаточно использовать коллекции Rows, Columns объекта Table (Tables.Item(Table)).

Следующим этапом формирования табличного документа определим запись текстовой информации в выбранную ячейку таблицы. Одним из способов такой записи является доступ к полю Text ячейки, но и в этом случае текст записывается не напрямую, а в объект Range ячейки таблицы. Функция SetTextToTable выполняет такую запись.

Function SetTextToTable(Table:integer;Row, Column:integer;
  text:string):boolean;
begin
 SetTextToTable:=true;
 try
  W.ActiveDocument.Tables.Item(Table).Columns.Item(Column).
   Cells.Item(Row).Range.Text:=text;
 except
  SetTextToTable:=false;
 end;
End;

И последнее действие, которое необходимо произвести над таблицей для создания простого табличного документа, это объединение ячеек. Для этого воспользуемся методом Merge объекта Cell (ячейка). Первый оператор функции объединения ячеек возвращает указатель на объект - конечную ячейку (Cel). Второй оператор объединяет начальную ячейку Row1,Column1 с конечной ячейкой, табличные координаты которой уже заданы и равны Row2,Column2.

Function SetMergeCellsTable(Table:integer;Row1,
  Column1,Row2,Column2:integer):boolean;
 var Cel:variant;
begin
 SetMergeCellsTable:=true;
 try
  Cel:=W.ActiveDocument.Tables.I tem(Table).Cell(Row2,Column2);
  W.ActiveDocument.Tables.Item(Table). Cell(Row1,Column1).Merge(Cel);
 except
  SetMergeCellsTable:=false;
 end;
End;

Переходим к заключительной стадии - созданию документа.

Для этого все определенные в этой части статьи функции объединим с ранее созданными и перенесем во вновь созданную библиотеку процедур и функций. Например, это будет файл MyWord.pas, в разделе interface которого будут описаны заголовки всех наших функций, а в разделе implementation - сами функции (в дальнейшем будем пользоваться этой библиотекой). Не забудьте после implementation вставить строки uses ComObj; var W:variant;.

Создадим новый проект, в программном модуле которого сделаем ссылку на нашу библиотеку uses MyWord;. На форме разместим кнопку и в процедуру обработки нажатия ее впишем следующий программный код.

procedure TForm1.Button1Click(Sender: TObject);
 var tablica_:integer;
begin
 if CreateWord then begin
  VisibleWord(true);
  If AddDoc then begin
// cсоздаем таблицу
   If CreateTable(5,3,tablica_) then begin
    Messagebox(0,pchar('Таблица создана='+inttostr(tablica_)),'',0);
// изменяем размеры таблицы
    SetSizeTable(tablica_,25,37);
    SetWidthColumnTable(tablica_,1,300);
    SetWidthColumnTable(tablica_,2,80);
    SetWidthColumnTable(tablica_,3,80);
    Messagebox(0,'Размер таблицы изменен','',0);
// записывает информацию в ячейки таблицы
    SetTextToTable(tablica_,1,1,
     'ПРОЦЕССОРЫ (данные от 27.05.2003) ');
    SetTextToTable(tablica_,2,1,'Наименование');
    SetTextToTable(tablica_,2,2,'Стоимость');
    SetTextToTable(tablica_,2,3,'Гарантия');
    SetTextToTable(tablica_,3,1,
     'ПРОЦЕССОР AMD K7- 1333 ATHLON 266MHz (Socket-A)');
    SetTextToTable(tablica_,3,2,'47.52 $');
    SetTextToTable(tablica_,3,3,'12 мес.');
    SetTextToTable(tablica_,4,1,
     'ПРОЦЕССОР AMD K7- 800 DURON (Socket-A)');
    SetTextToTable(tablica_,4,2,'23.54 $');
    SetTextToTable(tablica_,4,3,'12 мес.');
// объединяем необходимые ячейки таблицы
    SetMergeCellsTable(tablica_,1,1,1,3);
   end;
   SaveDocAs('c:\Прайс лист');
   Messagebox(0,'Текст сохранен','',0);
   CloseDoc;
  end;
  Messagebox(0,' Текст закрыт','',0);
  CloseWord;
 end;
end;

В результате выполнения приведенной выше процедуры получим результат, который выглядит, как показано на рисунке.

Полный исходный текст смотрите по адресу www.kornjakov.ru/st1_3.zip.

Мы сформировали достаточно простую таблицу, но редактор Word позволяет создавать очень сложные документы (см. как пример бланки налоговых деклараций). Практика показывает, что для таких документов лучше использовать шаблоны, которые можно заполнять информацией из программы. Причем такие шаблоны не обязательно создавать самому, они есть в любых правовых справочных системах. В следующей части статьи будет рассмотрен пример создания сложного документа, который сочетает заполнение шаблона и заполнение таблицы переменной длины, для этого понадобится ряд дополнительных функций, которыми будет дополнена наша библиотека.

По всем вопросам, касающимся материала этой статьи, вы можете обратиться к автору по адресу www.kornjakov.ru или _kvn@mail.ru.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А.Тенцер "Delphi 6 и технология COM" "Питер" 2002.

К списку статей


Суперфункции

(Продолжение. Начало в №20)

Часть 4

Многие популярные информационно-правовые системы содержат шаблоны различных документов в формате Word. Используя их и информацию данной статьи, вы можете легко и быстро создавать отчеты, если пишете свои программы на Delphi. Если пишете на другом языке, это не помеха, описанный подход справедлив к различным языкам.

Когда мы формируем сложный документ по шаблону, и когда в этом шаблоне есть таблицы, количество строк которых в выходном документе может быть произвольным и зависеть от объема информации, то нам недостаточно просто функций создания таблиц и записи в ячейки определенной информации. Для создания такого документа необходимо, как минимум, еще несколько функций работы с таблицами, в перечень которых входит перемещение по таблицам, добавление строк (столбцов) в конец или в середину таблицы. Также необходимо определять размер (количество строк, столбцов) и номер текущего столбца и строки. Чтобы понимать, о чем речь, необходимо просмотреть части 1-3 данной статьи, опубликованных в предыдущих номерах.

Для того, чтобы применить свои знания к конкретной задаче, сделаем ее постановку. Например, в нашем документе есть таблица, которая представляет собой шаблон и заполняется из массива информации, который имеет произвольную длину. Таким документом может быть счет-фактура, заголовок которой представляет собой сложную таблицу, средняя часть представляет таблицу переменной длины, а нижняя также представляет сложную таблицу. Для заполнения такого шаблона можно использовать способ, описанный во второй части данной статьи. Этот способ основан на поиске в шаблоне переменных (неповторяющиеся строковые значения длиной 3-5 символов) и подстановке вместо них реальных значений на этапе формирования документа. Поэтому для добавления информации в такую таблицу придется осуществить поиск и позиционирование в строку (по переменной), в которую и перед которой необходимо вставлять строки, и запомнить, в какие колонки какую записывать информацию, но для начала необходимо определить, находится курсор в таблице или нет.

Для этого используем свойство Information объекта Selection, в качестве параметра которого будет константа wdWithInTable. В этом случае этот метод возвращает TRUE, если курсор в таблице, или FALSE, если нет. Для использования в нашем приложении создадим функцию GetSelectionTable.

Function GetSelectionTable:boolean;
 const wdWithInTable=12;
begin
 GetSelectionTable:=true;
 try
  GetSelectionTable:=W.Selection.Information(wdWithInTable);
 except
  GetSelectionTable:=false;
 end;
End;

Если в нашем документе может быть более одной таблицы, то, скорее всего, необходима возможность перехода и позиционирование курсора на следующей или предыдущей таблице. Объект Selection дает нам эту возможность через методы GoToNext и GoToPrevious, в этом случае в качестве их параметров должна использоваться константа wdGoToTable.

Function GoToNextTable (table_:integer):boolean;
 const wdGoToTable=2;
begin
 GoToNextTable:=true;
 try
  W.Selection.GoToNext (wdGoToTable);
 except
  GoToNextTable:=false;
 end;
End;
Function GoToPreviousTable (table_:integer):boolean;
 const wdGoToTable=2;
begin
 GoToPreviousTable:=true;
 try
  W.Selection.GoToPrevious(wdGoToTable);
 except
  GoToPreviousTable:=false;
 end;
End;

Когда мы позиционируемся на таблице, можем определить количество столбцов и строк в ней. Для этого также используем свойство Information объекта Selection, но в качестве аргументов используем константы wdMaximum Number Of Columns и wdMaximum NumberOfRows.

Function GetColumnsRowsTable(table_:integer;
  var Columns,Rows:integer):boolean;
 const
  wdMaximumNumberOfColumns=18;
  wdMaximumNumberOfRows=15;
begin
 GetColumnsRowsTable:=true;
 try
  Columns:=W.Selection.Information (wdMaximumNumberOfColumns);
  Rows:=W.Selection.Information (wdMaximumNumberOfRows);
 except
  GetColumnsRowsTable:=false;
 end;
End;

Кроме размера таблицы, нам может быть необходим номер колонки и строки, на которой позиционирован курсор. Для этого так же используем свойство Information объекта Selection, но в качестве аргументов используем константы wdStartOfRangeColumnNumber, wdStartOfRangeRowNumber. Для реализации этого в Delphi создадим функцию GetColumnRowTable.

Function GetColumnRowTable(table_:integer;
  var Column,Row:integer):boolean;
 const
  wdStartOfRangeColumnNumber=16;
  wdStartOfRangeRowNumber=13;
begin
 GetColumnRowTable:=true;
 try
  Column:=W.Selection.Information (wdStartOfRangeColumnNumber);
  Row:=W.Selection.Information (wdStartOfRangeRowNumber);
 except
  GetColumnRowTable:=false;
 end;
End;

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

Обычно во время формирования таблицы мы не знаем, сколько будет строк. Они могут добавляться в конец или вставляться в середину таблицы. Если для формирования документа мы используем шаблон таблицы и в нем уже есть, например, заголовок, то нам не обойтись без процедур добавления или вставления строк. Добавить строку в конец таблицы можно, используя метод Add коллекции Rows. Чтобы это сделать из приложения на Delphi, достаточно создать и использовать функцию. Определим ее как AddRowTableDoc.

Function AddRowTableDoc (table_:integer):boolean;
begin
 AddRowTableDoc:=true;
 try
  W.ActiveDocument.Tables.Item(table_).Rows.Add;
 except
  AddRowTableDoc:=false;
 end;
End;

Для того, чтобы вставлять строки в середину таблицы, удобно использовать пару операторов. Первый выделяет строку, перед которой необходимо вставить новую, второй вставляет строку (строки). Смотрите функцию InsertRowsTableDoc.

Function InsertRowsTableDoc(table_,position_,
  count_:integer): boolean;
begin
 InsertRowsTableDoc:=true;
 try
  W.ActiveDocument.Tables.Item(table_).Rows.Item(position_).Select;
  W.Selection.InsertRows (count_);
 except
  InsertRowsTableDoc:=false;
 end;
End;

Для добавления одной строки можно использовать также и метод Add коллекции Rows, но с параметром, в качестве которого выступает ссылка на строку, перед которой необходимо вставить новую. Первый оператор получает ссылку на строку, второй вставляет новую. Смотрите реализацию на Delphi (InsertRowTableDoc).

Function InsertRowTableDoc(table_,position_: integer):boolean;
 var row_:variant;
begin
 InsertRowTableDoc:=true;
 try
  row_:=W.ActiveDocument.Tables.Item(table_).Rows.Item(position_);
  W.ActiveDocument.Tables.Item(table_).Rows.Add(row_);
 except
  InsertRowTableDoc:=false;
 end;
End;

Когда мы в своем распоряжении имеем набор функций для изменения таблицы, можно приступать к решению задачи - созданию документа типа счета-фактуры на базе шаблона. Полный исходный текст и полную версию шаблона счета-фактуры можно скачать по адресу www.kornjakov.ru/st1_4.zip. Здесь мы рассмотрим фрагмент данного документа. Создадим шаблон - документ формата DOC - и разместим его на диске в каталоге нашего проекта. Внешний вид шаблона смотрите на рисунке.

Здесь будем заполнять только табличную часть. О том, как заполнять остальное, читайте вторую часть данной статьи. Для начала наши новые функции скопируем в библиотеку MyWord, которую мы создавали, начиная с первой части статьи. Затем создадим новый проект, на форме которого разместим кнопку, а в процедуре обработки ее нажатия напишем следующий программный текст.

procedure TForm1.Button1Click(Sender: TObject);
 var tablica_:integer;
     col_,row_:integer;
     a_:integer;
     metki_:array[1..12] of record
      col:integer;
      row:integer;
      metka:string;
     end;
    tovar:array[1..2,1..12] of variant;
begin

// Заполняем массив данными. Массив используется
для простоты демонстрации, в реальной программе
данные берутся из базы данных.

tovar[1,1]:='Стул офисный'; tovar[1,2]:='шт.';
tovar[1,3]:=2; tovar[1,4]:=520.00; tovar[1,5]:=1040.00;
tovar[1,6]:='-'; tovar[1,7]:=20; tovar[1,8]:=208.0;
tovar[1,9]:=1248.00; tovar[1,10]:=62.40;
tovar[1,11]:='Россия'; tovar[1,12]:='-';
tovar[2,1]:='Телефон'; tovar[2,2]:='шт.';
tovar[2,3]:=3; tovar[2,4]:=315.25; tovar[2,5]:=945.75;
tovar[2,6]:='-'; tovar[2,7]:=20; tovar[2,8]:=189.15;
tovar[2,9]:=1134.90; tovar[2,10]:=56.70;
tovar[2,11]:='Беларусь'; tovar[2,12]:='-';
if CreateWord then begin
 VisibleWord(true);
 If OpenDoc(ExtractFileDir (application.ExeName) +'\sf.doc')
  then begin
  tablica_:=1;
  for a_:=1 to 12 do begin
   StartOfDoc;
   if FindTextDoc('###M'+inttostr(a_)+'&') then
    if GetSelectionTable then begin
     messagebox(handle,'Находимся в таблице, запоминаем
      метку(переменную), номер колонки и строки!',
      pchar('Номер колонки/строки = '+inttostr(col_)+'/'+inttostr(row_)),0);
     metki_[a_].col:=col_;
     metki_[a_].row:=row_;
     metki_[a_].metka:='###M'+inttostr(a_)+'&';
    end;
   end;
   Messagebox(handle,'Заполняем первую строку','',0);
   for a_:=1 to 12 do begin
    SetTextToTable(tablica_,metki_[a_].row,metki_[a_].col,tovar[1,a_]);
   end;
   a_:=1;
   Messagebox(handle,'Добавляем строку','',0);
   InsertRowTableDoc(tablica_, metki_[a_].row);
   Messagebox(handle,'Заполняем вторую строку','',0);
   for a_:=1 to 12 do begin
    SetTextToTable(tablica_,metki_[a_].row,metki_[a_].col,tovar[2,a_]);
   end;
   SaveDocAs(ExtractFileDir(application.ExeName)+'\Счет - фактура.doc');
   Messagebox(handle,'Текст сохранен','',0);
   CloseDoc;
  end;
  Messagebox(handle,' Текст закрыт','',0);
  CloseWord;
 end;
end;

Мы сформировали фрагмент сложного документа, но вы, возможно, захотите в дальнейшем сами развивать эту тему и использовать все возможности Word.Application. В следующей части я постараюсь на примерах объяснить, каким образом это сделать. По всем вопросам вы можете обратиться к автору по адресу www.kornjakov.ru или _kvn@mail.ru.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А. Тенцер "Delphi 6 и технология COM" "Питер" 2002.

К списку статей


Суперфункции

(Начало в №20)

Часть 5

Используя доступ к Word.Application из приложений Delphi, можно вставлять в текст документа записи, рисунки и другие объекты. Сложные документы в формате Word обычно могут содержать не только таблицы или текст, но также записи, линии и фигуры, объекты WordArt, рисунки, графику и многое другое.

Все эти объекты можно разделить на две группы: те, которые являются внутренними объектами Word, и внешние объекты, создаваемые внешними по отношению к самому Word серверами OLE. Все объекты, рассмотренные в 1-4 части статьи, - это внутренние объекты.

Кто программирует в Visual Basic в среде Word и в Delphi, тот может дальше сам развивать тему "Суперфункций". Все просто. Объекты, коллекции и методы, которые работают в среде Word, переносятся почти без изменений в среду Delphi. Главное здесь - применить немного изобретательности и находчивости. Можно использовать палитру компонентов Servers, которая есть в Delphi, начиная с 5-й версии. Выбор между готовыми компонентами и работой "напрямую" с Word.Application зависит от профессионализма, сложности поставленных задач, отпущенного времени и главное - от вкусов и стиля программирования. Это индивидуально для каждого, кто занимается разработкой сложных и не очень сложных приложений на Delphi и других языках программирования. Я свой выбор остановил на работе с Word.Application, так как это дает больше гибкости и возможностей при решении сложных и нестандартных задач

Рассмотрим еще несколько необходимых внутренних и использование некоторых внешних объектов, их создание и управление из приложений на Delphi.

Одним из часто используемых объектов является Textbox. Для его создания используем коллекцию Shapes(формы) и ее метод AddTextbox. Объект коллекции Shapes имеет атрибут - имя, его можно считать, можно изменить и обращаться к объекту не только через индекс, но и через имя. В функцию создания объекта Textbox передаем в качестве аргументов координаты и размеры области, а возвращаем имя объекта. Она выглядит следующим образом.

Function CreateTextBox (Left,Top,Width,Height:real;
  var name:string):boolean;
 const msoTextOrientationHorizontal=1;
begin
 CreateTextBox:=true;
 try
  name:=W.ActiveDocument.Shapes.AddTextbox
  (msoTextOrientationHorizontal,Left,Top,Width,Height).Name;
 except
  CreateTextBox:=false;
 end;
End;

Следующей естественной задачей является запись текста в TextBox. Используем доступ к созданному объекту (Shapes.Item) через индекс(число) или имя(строка). Текст можно записать в свойство Text объекта TextRange. Перед записью текста проверяем тип формы (Shape). Если форма имеет тип TextRange, тогда записываем текст. Смотрите реализацию в виде функции TextToTextBox на Delphi.

Function TextToTextBox (TextBox:variant;text: string):boolean;
 const msoTextBox=17;
begin
 TextToTextBox:=true;
 try
  if w.ActiveDocument.Shapes.Item(TextBox).Type = msoTextBox then
   W.ActiveDocument.Shapes.Item(TextBox).TextFrame.TextRange.Text:=Text
  else TextToTextBox:=false;
 except
  TextToTextBox:=false;
 end;
End;

Объект - форма (Shape) - может иметь тип не только как запись, он может содержать картинку, звук, линию и др. В зависимости от типа формы, процедура ее создания различна, но некоторые поля не зависят от типа. Одним из таких полей является имя формы, которое можно получить или изменить. Создадим две функции для определения имени (индекса) формы и для его изменения.

Function GetNameIndexShape (NameShape:variant): variant;
begin
 try
  GetNameIndexShape:=W.ActiveDocument.Shapes.Item(NameShape).Name;
 except
  GetNameIndexShape:=false;
 end;
End;

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

Function SetNewNameShape (NameShape:variant;
  NewNameShape:string):string;
begin
 try
  W.ActiveDocument.Shapes.Item(NameShape).Name:=NewNameShape;
  SetNewNameShape:=NewNameShape;
 except
  SetNewNameShape:='';
 end;
End;

Здесь можно было бы рассмотреть реализацию функций перемещения, изменения размеров, а также определение положения и размеров формы в документе. Можете сделать это самостоятельно. В Visual Basic для этого используются следующие операторы:

ActiveDocument.Shapes.Item (NameShape).Left = Left
ActiveDocument.Shapes.Item (NameShape).Top = Top
ActiveDocument.Shapes.Item (NameShape).Width = Width
ActiveDocument.Shapes.Item (NameShape).Height = Height

Или наоборот

Left = ActiveDocument.Shapes.Item (NameShape).Left
Top = ActiveDocument.Shapes.Item (NameShape).Top
Width = ActiveDocument.Shapes.Item (NameShape).Width
Height = ActiveDocument.Shapes. Item(NameShape).Height

В документах часто могут использоваться рисованные объекты, например, линии. Для их создания также используем коллекцию Shapes (формы) и ее метод AddTextbox. В функцию создания объекта Line передаем в качестве аргументов начальные и конечные координаты линии, а возвращаем имя объекта. Эта функция выглядит следующим образом:

Function CreateLine (BeginX,BeginY,EndX,EndY: real;
  var name:string):boolean;
begin
 CreateLine:=true;
 try
  name:=W.ActiveDocument.Shapes.AddLine(BeginX,BeginY,EndX,EndY).Name;
 except
  CreateLine:=false;
 end;
End;

Для прорисовки сложной фигуры необходимо использовать метод AddPolyline коллекции Shapes. Аргументом этой функции должен быть массив точек (massiv). Реализация на Visual Basic имеет следующий вид:

ActiveDocument.Shapes.AddPolyline (massiv)

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

Function CreatePicture(FileName:string;Left,Top: real;
  var name:string):boolean;
begin
 CreatePicture:=true;
 try
  name:=W.ActiveDocument.Shapes.AddPicture(FileName).Name;
  W.ActiveDocument.Shapes.Item (name).Left:=Left;
  W.ActiveDocument.Shapes.Item(name). Top:=Top;
 except
  CreatePicture:=false;
 end;
End;

Мы должны иметь возможность не только создать новый объект, но и удалить ранее созданный, например, рисунок или запись. Для этого используется метод Delete коллекции Shapes. Для использования этого в своих приложениях создадим функцию DeleteShape, в качестве аргумента которой будет имя или индекс объекта Shape.

Function DeleteShape (NameShape:variant): variant;
Begin
 DeleteShape:=true;
 try
  W.ActiveDocument.Shapes.Item (NameShape).Delete;
 except
  DeleteShape:=false;
 end;
End;

Внешний объект в документе представляет собой Ole-объект, отображаемый внешней программой, которая является Ole-сервером по отношению к редактору Word. Такими объектами могут быть рисунки (BMP), созданные программой Paint или лист Excel. Внешний объект может отображаться в документе только тогда, когда установлена поддерживающая его программа. Для внедрения внешних объектов в документ используется метод AddOLEObject коллекции Shapes. Например, чтобы получить доступ к объекту в Visual Basic, используется следующий оператор:

Set obb = ActiveDocument.Shapes.AddOLEObject("MSGraph.Chart.8")

В Delphi он выглядит следующим образом:

Var Obb:variant;
Obb:=W.ActiveDocument.Shapes.AddOLEObject("MSGraph.Chart.8");

Где W - Word.Application.

Но чтобы программировать Ole-объект, необходимо знать его поля и методы. Эта информация индивидуальна для каждого объекта и ее рассмотрение - отдельная тема.

На основе созданных нами функций создадим небольшую демонстрационную программу, которая будет создавать объект-запись и объект-линию, а затем удалит их из документа. Как всегда, используем ранее созданные функции, разместим на форме кнопку и процедуре обработки ее нажатия напишем следующий программный текст:

procedure TForm1.Button1Click (Sender: TObject);
 var BoxName_,LineName_:string;
begin
 if CreateWord then begin
  Messagebox(0,'Word запущен.','',0);
  VisibleWord(true);
  Messagebox(0,'Word видим.','',0);
  If AddDoc then begin
   Messagebox(0,'Документ создан.','',0);
   CreateTextBox(1,1,100,50,BoxName_);
   Messagebox(0,'Создали форму - надпись.','',0);
   Messagebox(0,pchar(GetNameIndexShape(1)) ,
    'Считали имя формы',0);
   BoxName_:=SetNewNameShape(BoxName_,'Новое имя');
   Messagebox(0,pchar(GetNameIndexShape (1)),
    'Изменили имя формы и считываем его снова',0);
   TextToTextBox(BoxName_,'Добавляем текст в TextBox');
   Messagebox(0,'Рисуем линию','',0);
   CreateLine(1,15,300,200,LineName_);
   Messagebox(0,'Удаляем линию','',0);
   DeleteShape(LineName_);
   Messagebox(0,'Удаляем надпись','',0);
   DeleteShape(BoxName_);
   SaveDocAs('c:\Документ, содержащий объекты');
   Messagebox(0,'Текст сохранен','',0);
   CloseDoc;
  end;
  Messagebox(0,' Текст закрыт','',0);
  CloseWord;
 end;
end;

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

По всем вопросам вы можете обратиться к автору по адресу www.kornjakov.ru или _kvn@mail.ru. Исходный текст www.kornjakov.ru/st1_5.zip.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А.Тенцер "Delphi 6 и технология COM" "Питер" 2002.

К списку статей


Суперфункции EXCEL. Часть 1.

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

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

Обратимся к постановке задачи. Нам необходимо сформировать документ из прикладной программы на языке Delphi. Как это сделать? Табличный редактор Excel представляет собой COM-сервер и может получать и обрабатывать запросы от внешних программ. Все это позволяет организовать процесс управления и создания документа из внешних программ. Используя этот механизм, можно создать документ программно - так же, как это делается вручную (посредством меню, кнопок и клавиатуры), но гораздо быстрей и эффектней.

Основными объектами, к которым можно обращаться из внешних программ, являются Excel.Application и Excel.Sheet.8. Используя их, можно получить доступ к объектам документа, например, к ячейкам, рисункам, автофигурам и к свойствам самого Excel. Используя основные объекты, можно создать и обращаться к объектам, созданными внешними серверами OLE. Общая объектная модель Excel представляет древовидную структуру и имеет следующий общий вид:

Корневым объектом является Excel.Application. Коллекция Workbooks обеспечивает создание и доступ к любой книге, которая открыта в приложении. Объект Workbook, в свою очередь, содержит коллекцию Sheets, посредством которой можно создавать, удалять и получить доступ к листам документа. И конечный объект Range обеспечивает запись информации в ячейку. Кроме перечисленных, есть и другие объекты, которые будут рассмотрены в следующих частях статьи.

С чего можно начать программирование? Для начала создадим библиотеку, файл с расширением MyExcel.pas, и все функции для удобства будем размещать в ней. Определимся с набором необходимых функций. Самыми простыми и необходимыми являются следующие: активизация Excel, создание новой книги, открытие ранее созданной книги, отображение книги (книг) и приложения Excel, запись информации в ячейку, запись книги на диск и выход (закрытие книги и приложения). Для создания объекта Excel.Application используем переменную E типа variant и библиотеку ComObj.

Рассмотрим следующий фрагмент кода:

uses ComObj, Classes;
var E:variant;
Function CreateExcel:boolean;
begin
 CreateExcel:=true;
 try
  E:=CreateOleObject('Excel.Application');
 except
  CreateExcel:=false;
 end;
end;
End;

Доступ к объекту Excel.Application в нашей функции CreateExcel получаем, используя процедуру CreateOleObject ('Excel.Application') стандартной библиотеки ComObj. Если редактор Excel не установлен в системе, то будет сгенерирована ошибка, и мы получим значение функции = false; если Excel установлен и объект будет создан, то получим значение функции = true. Эта функция создает объект E, свойства и методы которого мы будем использовать в дальнейшем. Если выполнить нашу функцию CreateExcel, то Excel будет запущен, но не будет отображен, потому что по умолчанию он запускается в фоновом режиме. Чтобы его активизировать (сделать видимым) или деактивировать (сделать невидимым), используем свойство visible объекта E. Оформим это в виде функции VisibleExcel. Скобки try except везде используются для обработки исключительных ситуаций.

Function VisibleExcel(visible:boolean): boolean;
begin
 VisibleExcel:=true;
 try
  E.visible:=visible;
 except
  VisibleExcel:=false;
 end;
End;

Используя эту функцию, мы можем показывать или скрывать Excel с документами.

Следующим шагом будет создание рабочей книги. Для этого используем метод Add, коллекции Workbooks объекта E. См. нижеописанный оператор, с помощью которого мы не только создаем новую книгу, но и получаем на нее ссылку: book_:=E. Workbooks.Add.

Function AddWorkBook:boolean;
begin
 AddWorkBook:=true;
 try
  E.Workbooks.Add;
 except
  AddWorkBook:=false;
 end;
End;

Чтобы открыть ранее созданную рабочую книгу, используем ту же коллекцию Workbooks объекта E и метод Open. Смотрите нижеописанный оператор, с помощью которого мы открываем рабочую книгу и получаем на нее ссылку: book_:= Workbooks. Open(file_). Функция OpenWorkBook открывает книгу и возвращает True в случае успешного выполнения.

Function OpenWorkBook(file_: string):boolean;
begin
 OpenWorkBook:=true;
 try
  E.Workbooks.Open(file_);
 except
  OpenWorkBook:=false;
 end;
End;

Работая с книгой, мы должны иметь возможность добавлять или удалять в ней листы и присваивать им имена. Для работы с листами книги используется коллекция Sheets. Добавить новый лист можно, используя метод Add этой коллекции. Функция AddSheet реализует эту возможность и присваивает новому листу выбранное пользователем имя.

Function AddSheet(newsheet:string):boolean;
begin
 AddSheet:=true;
 try
  E.Sheets.Add;
  E.ActiveSheet.Name:=newsheet;
 except
  AddSheet:=false;
 end;
End;

Создавая новые листы, мы должны иметь возможность и удалять их. Метод Delete, коллекции Sheets дает такую возможность. При удалении возможно появление диалогового окна Excel, которое потребует подтверждения операции. Чтобы отключить диалоговое окно Excel, необходимо использовать оператор E.DisplayAlerts:=False.

Function DeleteSheet(sheet:variant):boolean;
begin
 DeleteSheet:=true;
 try
  E.DisplayAlerts:=False;
  E.Sheets[sheet].Delete;
  E.DisplayAlerts:=True;
 except
  DeleteSheet:=false;
 end;
End;

Обычно книга Excel содержит более одного листа. Их количество содержится в свойстве Count коллекции Sheets. Для того, чтобы в Visual Basic получить имена листов текущей книги, используйте следующий оператор:

For a_ = 1 To Sheets.Count
 MsgBox (Sheets.Item(a_).Name)
Next a_

Для активации любого листа книги необходимо использовать процедуру Select. Смотрите пример:

Sheets.Item(a_).Select

Все описанные выше возможности можно легко реализовать в Delphi как набор отдельных функций. Смотрите примеры:

Function CountSheets:integer; // получаем количество листов книги
begin
try
CountSheets:=E.ActiveWorkbook.Sheets.Count;
except
CountSheets:=-1;
end;
End;
Function GetSheets(value:TStrings):boolean;
// записываем листы книги в value
var a_:integer;
begin
GetSheets:=true;
value.Clear;
try
for a_:=1 to E.ActiveWorkbook.Sheets.Count do
value.Add(E.ActiveWorkbook.Sheets.Item[a_].Name);
except
GetSheets:=false;
value.Clear;
end;
End;
Function SelectSheet (sheet:variant):boolean;
// выбираем лист
begin
SelectSheet:=true;
try
E.ActiveWorkbook.Sheets.Item[sheet].Select;
except
SelectSheet:=false;
end;
End;

После внесения изменений необходимо сохранить рабочую книгу. Для этого используем метод SaveAs коллекции Workbooks или объекта ActiveWorkbook. Функция SaveWorkBookAs реализует эту возможность на Delphi. Используем E.DisplayAlerts:=False(True) для отключения (включения) диалогового окна подтверждения записи.

Function SaveWorkBookAs(file_:string): boolean;
begin
SaveWorkBookAs:=true;
try
E.DisplayAlerts:=False;
E.ActiveWorkbook.SaveAs(file_);
E.DisplayAlerts:=True;
except
SaveWorkBookAs:=false;
end;
End;

Одновременно может быть открыто несколько книг, в которые вносится или из которых получается информация. Их количество содержится в свойстве Count коллекции WorkBooks. Используя следующий оператор на Visual Basic, можем получить их имена.

For a_ = 1 To Application.Workbooks.Count
MsgBox (Application.Workbooks.Item(a_).Name)
Next a_

Для активации любой книги из списка используем процедуру Activate. Смотрите пример:

Windows("Книга1").Activate

Эти возможности можно реализовать в Delphi как набор отдельных функций.

Для закрытия книги используется метод Close коллекции Workbooks или объекта ActiveWorkbook. Функция CloseWorkBook закрывает активный документ.

Function CloseWorkBook:boolean;
begin
 CloseWorkBook:=true;
 try
  E.ActiveWorkbook.Close;
 except
  CloseWorkBook:=false;
 end;
End;

Excel закрывается методом Quit объекта Application.

Function CloseExcel:boolean;
begin
 CloseExcel:=true;
 try
  E.Quit;
 except
  CloseExcel:=false;
 end;
End;

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

procedure TForm1.Button1Click (Sender: TObject);
 var a_:integer;
begin
 if not CreateExcel then exit;
 messagebox(handle,'','Запускаем Excel.',0);
 VisibleExcel(true);
 messagebox(handle,'','Отобразили Excel на экране.',0);
 if AddWorkBook then begin
  messagebox(handle,'','Создали новую книгу.',0);
  AddSheet('Новый лист');
  messagebox(handle,'','Добавили новый лист.',0);
  DeleteSheet(2);
  messagebox(handle,'','Удалили лист №2.',0);
  GetSheets(ListBox1.Items);
  messagebox(handle,'','Получили список листов!',0);
  for a_:=1 to CountSheets do begin
   ListBox1.ItemIndex:=a_-1;
   SelectSheet(ListBox1. Items.Strings[a_-1]);
   messagebox(handle,'',
    pchar('Выбираем лист '+ListBox1.Items.Strings[a_-1]+'!'),0);
  end;
  SaveWorkBookAs('c:\1.xls');
  messagebox(handle,'','Сохранили книгу как "c:\1.xls".',0);
  CloseWorkBook;
  messagebox(handle,'','Закрыли книгу "c:\1.xls".',0);
 end;
 CloseExcel;
end;

Мы рассмотрели общий вид объектной модели Excel и примеры нескольких функций работы с книгами и листами. Далее изучим вопросы записи (чтения) информации в ячейки и программирование их свойств. По всем вопросам Вы можете обратиться к автору по адресу _kvn@mail.ru или www.kornjakov.ru.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А.Тенцер, "Delphi 6 и технология COM", "Питер", 2002.

К списку статей


Суперфункции EXCEL. Часть 2.

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

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

Доступ к ячейке или ячейкам в Excel предоставляет объект Range. Этот объект обладает всеми необходимыми свойствами и методами, чтобы писать, читать из ячейки и изменять все ее свойства. Для того, чтобы просто записать информацию в ячейку, необходимо присвоить объекту Range значение, записанное в переменной типа variant. Например: Range['A1']:=123.25; или Range['A1']:='ячейка';. Для записи (чтения) в ячейку из приложений на Delphi разработаем несколько функций. Аргумент (range:string) этих функций может принимать значения, которые соответствуют одной ячейке (например 'A1') или группе ячеек (например 'A1:D5').

Function SetRange (sheet:variant;range:string;
  value_:variant):boolean;
begin
 SetRange:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range[range]:=value_;
 except
  SetRange:=false;
 end;
End;

Читать информацию одновременно можно только из одной ячейки. Если попытаться читать из группы ячеек, то можно получить ошибку. Поэтому аргумент range:string в функции GetRange принимает только такие значения, как, например 'A1'. В этих функциях чтения и записи, а также и во всех последующих аргумент sheet может принимать как числовые значения (номер листа), так и строковые (имя листа).

Function GetRange (sheet:variant;range:string):variant;
begin
 try
  GetRange:=E.ActiveWorkbook.Sheets.Item[sheet].Range[range];
 except
  GetRange:=null;
 end;
End;


Высота и ширина ячейки

Чтобы формировать вид документа в процессе его создания, недостаточно только функций записи информации в ячейки, необходимо также изменять ее визуальные параметры. Самое простое, с чего можно начать, - изменение ширины столбцов и высоты строк. Доступ к ширине столбцов можно получить, используя коллекцию Columns. Используя номер колонки в буквенном или числовом формате и свойство коллекции ColumnWidth, можно изменить ширину столбца или назначить ее. Определенная ниже функция, реализованная на Delphi, устанавливает ширину столбца.

Function SetColumnWidth (sheet:variant;
  column:variant;width:real):boolean;
begin
 SetColumnWidth:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Columns
   [column].ColumnWidth:=width;
 except
  SetColumnWidth:=false;
 end;
End;

Для определения ширины столбца используйте следующий оператор: width:=E.ActiveWorkbook .Sheets.Item[sheet].Columns[column].ColumnWidth;

Доступ к высоте строк можно получить, используя коллекцию Rows. Назначая номер строки и свойство коллекции RowHeight, можно изменить высоту строки или назначить ее. Определенная ниже функция, реализованная на Delphi, устанавливает высоту строки.

Function SetRowHeight (sheet:variant;row:variant;
  height:real):boolean;
begin
 SetRowHeight:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Rows[row].RowHeight:=height;
 except
  SetRowHeight:=false;
 end;
End;

Для определения высоты строки используйте следующий оператор: height:=E.ActiveWorkbook.Sheets.Item[sheet].Rows[row].RowHeight;


Числовой формат ячейки

Данные в ячейках таблицы могут отображаться различным образом (число, дата, время, строка), способ отображения данных называется числовым форматом. Значение числового формата ячейки хранится в свойстве NumberFormat объекта Range, имеет тип строка и может содержать, например, такие значения: 'General', 'hh:mm:ss', '0,000'. Они соответствуют общему формату, формату времени и формату числа с тремя знаками после запятой. Опытным путем можно получить значения всех форматов, для этого в Delphi используем функцию GetFormatRange.

Function GetFormatRange (sheet:variant;
  range:string):string;
begin
 try
  GetFormatRange:=E.ActiveWorkbook.Sheets.Item
   [sheet].Range[range].NumberFormat;
 except
  GetFormatRange:='';
 end;
End;

Для установки числового формата ячейки можем использовать функцию SetFormatRange, которая записывает значение числового формата в свойстве NumberFormat объекта Range.

Function SetFormatRange(sheet:variant;range:string;
  format:string):boolean;
begin
 SetFormatRange:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range
   [range].NumberFormat:=format;
 except
  SetFormatRange:=false;
 end;
End;

Данная функция изменяет числовой формат не только в одной отдельно взятой ячейке, а также в группе ячеек. Это определяется значением аргумента range:string. Смотрите примеры: 'A:A' - изменение формата во всех ячейках столбца A, '2:5' - изменение формата во всех ячейках столбцов со второй по пятую включительно, 'A:C' - изменение формата во всех ячейках столбцов с A по C включительно; 'A1:C5' - изменение формата во всех ячейках области, ограниченной колонками A...C и строками 1...5 включительно.


Выравнивание текста в ячейке

Следующим шагом изменения режима отображения данных в ячейках книги Excel рассмотрим выравнивание текста по горизонтали и вертикали. Для выравнивания по горизонтали используется свойство HorizontalAlignment объекта Range, которое применяем в функции SetHorizontalAlignment. Если записывать в аргумент alignment:integer этой функции определенные числовые константы, то получим различные варианты выравнивания текста по горизонтали. Смотрите список констант и функцию, реализующую выравнивание текста по горизонтали.

const
 xlHAlignCenter=-4108;
 xlHAlignDistributed=-4117;
 xlHAlignJustify=-4130;
 xlHAlignLeft=-4131;
 xlHAlignRight=-4152;
 xlHAlignCenterAcrossSelection=7;
 xlHAlignFill=5;
 xlHAlignGeneral=1;
Function SetHorizontalAlignment (sheet:variant;range:string;
  alignment:integer):boolean;
begin
 SetHorizontalAlignment:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range
   [range].HorizontalAlignment:=alignment;
 except
  SetHorizontalAlignment:=false;
 end;
End;

Для выравнивания по вертикали используем свойство VerticalAlignment объекта Range. Смотрите набор констант и функцию SetVerticalAlignment.

const
 xlVAlignBottom=-4107;
 xlVAlignCenter=-4108;
 xlVAlignDistributed=-4117;
 xlVAlignJustify=-4130;
 xlVAlignTop=-4160;
Function SetVerticalAlignment (sheet:variant;range:string;
  alignment:integer):boolean;
begin
 SetVerticalAlignment:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range
   [range].VerticalAlignment:=alignment;
 except
  SetVerticalAlignment:=false;
 end;
End;


Другие режимы отображения текста в ячейке

Угол, под которым текст отображается в ячейке, определяется свойством Orientation объекта Range. Значение Orientation может находиться в пределах от -90 до 90. Функция SetOrientation реализует эту возможность в приложениях Delphi.

Function SetOrientation (sheet:variant;range:string;
  orientation:integer):boolean;
begin
 SetOrientation:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range
   [range].Orientation:=orientation;
 except
  SetOrientation:=false;
 end;
End;

Текст, ширина которого больше ширины ячейки, может отображаться несколькими строками (переносом по словам) или одной строкой. Это свойство ячейки содержится в поле WrapText объекта Range. Функция SetWrapText изменяет это поле и режим отображения текста большой длины.

Function SetWrapText(sheet:variant;range:string;
  WrapText:boolean):boolean;
begin
 SetWrapText:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range
   [range].WrapText:=WrapText;
 except
  SetWrapText:=false;
 end;
End;

Можно использовать и альтернативный способ для размещения текста большой длины в ячейке. Он основан на автоподборе ширины текста под ширину ячейки. Свойство.ShrinkToFit объекта Range определяет этот режим отображения. Смотрите функцию SetShrinkToFit. Если установлен режим "перенос по словам", то действие этой функции отменяется.

Function SetShrinkToFit (sheet:variant;range:string;
  ShrinkToFit:boolean):boolean;
begin
 SetShrinkToFit:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range
   [range].ShrinkToFit:=ShrinkToFit;
 except
  SetShrinkToFit:=false;
 end;
End;

Несколько ячеек можно объединить. Для этой цели используется свойство MergeCells объекта Range[range], где range - область для объединения, например "A1:C2". Если в MergeCells записывает значение True, то это приводит к объединению ячеек. Для реализации в приложениях на Delphi используем функцию SetMergeCells.

Function SetMergeCells (sheet:variant;range:string;
  MergeCells:boolean):boolean;
begin
 SetMergeCells:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range
   [range].MergeCells:=MergeCells;
 except
  SetMergeCells:=false;
 end;
End;

Мы рассмотрели формирование формата данных ячейки листа книги Excel. Далее рассмотрим выбор шрифта и другие свойства ячейки, такие как цвет и стиль фона и границы. Исходные тексты с примерами смотрите по адресу www.kornjakov.ru/st2_2.zip. По всем вопросам вы можете обратиться к автору по адресу _kvn@mail.ru или www.kornjakov.ru.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А.Тенцер, "Delphi 6 и технология COM", "Питер", 2002.

К списку статей


Суперфункции EXCEL. Часть 3

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


Выбор шрифта

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

Рассмотрим в деталях объект Font и его поля. Объект Font является свойством ячейки или области ячеек Range, а доступ к нему получаем, используя следующий оператор: E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Font, где E = Excel.Application. Объект Font имеет несколько полей, которые влияют на режим отображения символов ячейки. Name - наименование шрифта в формате string. В это поле записывается имя одного из шрифтов, установленного в системе. Bold - параметр, который может принимать значение True или False и который влияет на толщину символов. Italic - принимает значение True (наклонный) или False (прямой) и отвечает за наклонное написание символов. Strikethrough - равен True, если символы перечеркнутые, или False, если не перечеркнутые. Underline - свойство, которое определяет стиль подчеркивания, имеет тип Integer. Когда Underline=xlUnderlineStyleNone, символы отображаются без подчеркивания, если Underline=xlUnderlineStyleSingle, то используется обычное подчеркивание. Когда необходимо использовать дополнительные виды подчеркивания, то применяем определенные константы (смотрите приложение на домашней странице). Color - цвет символов, тип longint.

Нетрудно провести соответствие между описанием полей объекта Font ячеек Excel и объектом Tfont Delphi. Ниже описанная функция использует это соответствие для задания шрифта ячеек таблиц Excel из приложений Delphi. Последним аргументом этой функции является ссылка на объект Font:Tfont, который является стандартным типом объекта Delphi. Этот аргумент мы используем для передачи параметров шрифта в Excel.

Function SetFontRange(sheet:variant;range:string;
 font:Tfont):boolean;
begin
 SetFontRange:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Font.Name:=font.Name;
  if fsBold in font.Style then E.ActiveWorkbook.Sheets.Item
    [sheet].Range[range].Font.Bold:=True
   else E.ActiveWorkbook.Sheets.Item[sheet].Range
    [range].Font.Bold:=False;
  if fsItalic in font.Style then E.ActiveWorkbook.Sheets.Item
    [sheet].Range[range].Font.Italic:=True
   else E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Font.Italic:=False;
  E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Font.Size:=font.Size;
  if fsStrikeOut in font.Style
   then E.ActiveWorkbook.Sheets.Item[sheet].Range
    [range].Font.Strikethrough:=True
   else E.ActiveWorkbook.Sheets.Item[sheet].Range
    [range].Font.Strikethrough:=False;
  if fsUnderline in font.Style then
   E.ActiveWorkbook.Sheets.Item[sheet].Range
    [range].Font.Underline:=xlUnderlineStyleSingle
   else E.ActiveWorkbook.Sheets.Item[sheet].Range
    [range].Font.Underline:=xlUnderlineStyleNone;
  E.ActiveWorkbook.Sheets.Item [sheet].Range
    [range].Font.Color:=font.Color;
 except
  SetFontRange:=false;
 end;
End;

Так как Excel имеет больше возможностей для отображения шрифта, то для реализации их можно использовать дополнительную функцию SetFontRangeEx. Аргумент Superscript=True определяет написание символов как верхний индекс. Subscript=True отображает символы как нижний индекс. Цвет символов может определяться не только полем Color объекта Font, но и полем ColorIndex того же объекта. ColorIndex может принимать следующие значения: -4105 - соответствует автоматическому выбору цвета; от 1 до 56 - одному из заданных значений палитры цветов. Underline определяет стиль подчеркивания (integer) и может принимать одно из пяти значений (смотрите исходный текст на домашней странице).

Function SetFontRangeEx(sheet:variant;range:string;
  underlinestyle,colorindex:integer;superscript,subscript:boolean):boolean;
begin
 SetFontRangeEx:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Font.Superscript:=superscript;
  E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Font.Subscript:=subscript;
  E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Font.ColorIndex:=colorindex;
  E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Font.Underline:=underlinestyle;
 except
  SetFontRangeEx:=false;
 end;
End;


Формат границ ячейки

Границы ячейки имеют следующие свойства: цвет, стиль и толщина. Чтобы получить доступ к границе, используем коллекцию Borders объекта Range, которая через индекс (Edge) предоставляет доступ к той или иной стороне границы ячейки (левая, правая и т.д. сторона). Edge может принимать одно из 8 определенных значений. Объекты коллекции Borders определяют цвет границы, который может задаваться выбором из определенной в Excel палитры или как комбинация из трех цветов RGB. Свойство ColorIndex содержит индекс цвета: когда нас не устраивает цвет из заранее определенной палитры, тогда используем свойство Color, в которое запишем значение из комбинации трех основных цветов, например: Color= RGB(200,100,125). Стиль границы (LineStyle) имеет тип integer и одно из 8 предопределенных значений (смотрите приложение). Толщина границы (Weight) имеет тип integer и одно из 4 значений. Исходный текст функции для установки параметров границы ячейки смотрите ниже.

Function SetBorderRange(sheet:variant;range:string;
  Edge,LineStyle,Weight,ColorIndex,Color:integer):boolean;
begin
 SetBorderRange:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Borders.item
   [Edge].Weight:=Weight;
  E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Borders.item
   [Edge].LineStyle:=LineStyle;
  if ColorIndex>0 then
   E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Borders.item
   [Edge].ColorIndex:=ColorIndex
  else
   E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Borders.item
   [Edge].Color:=color;
 except
  SetBorderRange:=false;
 end;
End;


Формат заливки ячейки

Заливка ячейки определяется цветом, фоновым рисунком и цветом фонового рисунка. Доступ к этим полям осуществляется через объект Interior, который является свойством объекта Range. Цвет заливки может выбираться из определенной палитры цветов, в этом случае индекс цвета записывается в поле ColorIndex. Если необходимо задать цвет, отличный от цветов палитры, используется поле Color, в которое записывается значение комбинации трех основных цветов RGB. Фоновый рисунок заливки выбирается путем записи в поле Pattern константы из списка (смотрите исходный текст на домашней странице). Цвет фонового рисунка выбирается из цветовой палитры с записью в переменную PatternColorIndex цветового индекса или записью непосредственно значения RGB в поле PatternColor. Функция SetPatternRange реализует в среде Delphi управление форматом заливки ячеек. В этой функции, как и во всех предыдущих, действия могут выполняться как над одной ячейкой так и над множеством, все определяется форматом аргумента функции range:string.

Function SetPatternRange(sheet:variant;range:string;
  Pattern,ColorIndex,PatternColorIndex,Color,PatternColor:integer):boolean;
begin
 SetPatternRange:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].Range[range].Interior.Pattern:=Pattern;
  if ColorIndex>0
   then E.ActiveWorkbook.Sheets.Item[sheet].Range
    [range].Interior.ColorIndex:=ColorIndex
   else E.ActiveWorkbook.Sheets.Item[sheet].Range
    [range].Interior.Color:=color;
  if PatternColorIndex>0
   then E.ActiveWorkbook.Sheets.Item[sheet].Range
    [range].Interior.PatternColorIndex:=PatternColorIndex
   else E.ActiveWorkbook.Sheets.Item[sheet].Range
    [range].Interior.PatternColor:=PatternColor;
 except
  SetPatternRange:=false;
 end;
End;


Некоторые дополнительные возможности

Мы рассмотрели основные функции работы с ячейками: запись/чтение и установка формата. К этому можно добавить еще те, которые пригодятся на практике. Если мы работаем с областью, то внутри этой области можно обращаться к ячейкам по номеру колонки и столбца относительно начала этой области. Смотрите пример: E.ActiveWorkbook.Sheets.Item[sheet].Range['A5:B10'].Cells.Item[1,1]:=2343. Значение будет записано в ячейку A5.

Для записи формул можно использовать следующий оператор E.ActiveWorkbook.Sheets.Item[sheet].Range['A1'].Formula: ='=$A$4+$A$10'.

Для выделения области листа, заполненного информацией, используйте оператор E.ActiveWorkbook.Sheets.Item[sheet].UsedRange.Select;

Вычислить количество ячеек, столбцов и строк области листа, заполненного информацией, можно, используя следующие операторы:

E.ActiveWorkbook.Sheets.Item[sheet].UsedRange.Count - количество ячеек.

E.ActiveWorkbook.Sheets.Item[sheet].UsedRange.Columns.Count - количество столбцов.

E.ActiveWorkbook.Sheets.Item[sheet].UsedRange.Rows.Count - количество строк.

Для вычисления адреса заполненной области (левая верхняя ячейка - правая нижняя ячейка) можно использовать оператор E.ActiveWorkbook.Sheets.Item[sheet].UsedRange.Address, который возвращает строку, содержащую область адресов.

Мы, в целом, закончили формирование формата данных ячеек таблицы Excel. Далее рассмотрим настройки листа, просмотр печати, печать. Полные исходные тексты с примерами смотрите по адресу www.kornjakov.ru/st2_3.zip. По всем вопросам можете обратиться к автору по адресу _kvn@mail.ru или www.kornjakov.ru.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А. Тенцер "Delphi 6 и технология COM" "Питер" 2002.

К списку статей


Суперфункции EXCEL. Часть 4

После окончательного формирования информации на листе рабочей книги необходимо задать настройки листа и переходить к печати. Эта часть будет посвящена функциям настройки общих параметров листа, выбора и настройки принтера, подготовки листа и функциям печати. Excel.Application имеет большие возможности для выбора и настройки принтера и параметров печати. Здесь представлен только минимальный их набор. Если в вашей операционной системе не установлен принтер, то большинство описанных ниже функций завершится ошибкой. Для использования информации в своих приложениях начните изучение статьи с первой части.


Некоторые общие параметры для листа

Фоновый рисунок листа устанавливается процедурой SetBackgroundPicture, коллекции Sheets или объекта ActiveSheet. Если аргумент FileName этой функции равен пустой строке, то это отменяет установленный ранее фоновый рисунок. Реализация этой возможности на Delphi представлена в виде функции SetBackgroundPicture.

Function SetBackgroundPicture(sheet:variant;
  file_:string):boolean;
begin
 SetBackgroundPicture:=true;
 try
  E.ActiveWorkbook.Sheets.Item
   [sheet].SetBackgroundPicture(FileName:=file_);
 except
  SetBackgroundPicture:=false;
 end;
End;

Сетку активной страницы можно сделать видимой или невидимой, используя свойство DisplayGridlines объекта ActiveWindow. Если перед этим необходимо выбрать определенный лист, то используйте метод Select, например, Sheets("Лист1").Select.

Function DisplayGridlines(display:boolean):boolean;
begin
 DisplayGridlines:=true;
 try
  E.ActiveWindow.DisplayGridlines:=display;
 except
  DisplayGridlines:=false;
 end;
End;


Выбор и настройка принтера

Если принтеры не установлены, то функции выбора и настройки принтера и задания параметров страницы для печати не могут быть выполнены. Выбор принтера можно осуществить разными способами. Один из них - активизация диалогового окна "Выбор принтера". В Visual Basic это осуществляется оператором Application.Dialogs.Item (xlDialogPrinterSetup).Show, где Dialogs - коллекция диалогов, а xlDialogPrinterSetup - константа, определяющая выбор диалога. В Delphi это можно реализовать в виде функции ShowDialogPrinterSetup, которая возвращает True или False, в зависимости от результата.

Function ShowDialogPrinterSetup:boolean;
 const xlDialogPrinterSetup = 9;
begin
 ShowDialogPrinterSetup:=true;
 try
  ShowDialogPrinterSetup:=E.Dialogs.Item
   [xlDialogPrinterSetup].Show;
 except
  ShowDialogPrinterSetup:=false;
 end;
End;

Для того, чтобы выбрать принтер и отправить задание на печать, необходимо вызвать диалог с использованием следующего оператора Application.Dialogs.Item (xlDialogPrint).Show. Константа xlDialogPrint определяет вызов стандартного диалога печати. Функция ShowPrintDialog реализует эти возможности.

Function ShowPrintDialog:boolean;
begin
 ShowPrintDialog:=true;
 try
  ShowPrintDialog:=E.Dialogs.Item[xlDialogPrint].Show;
 except
  ShowPrintDialog:=false;
 end;
End;

Можно расширить возможности этого диалога, предварительно задав некоторые параметры, например, диапазон страниц и количество копий: result=Application.Dialogs.Item(xlDialogPrint).Show(arg2:=1, arg3:=2, arg4:=3). В Delphi это выглядит так: ShowPrintDialog:=E.Dialogs.Item[xlDialogPrint].Show(arg2:=1, arg3:=2, arg4:=3).


Вид листа, область и параметры страницы для печати

Вид рабочего листа может быть представлен в режиме "Разметка страницы", если установлен и выбран принтер, или в режиме "Обычный". В режиме разметки страницы есть возможность изменять область печати. Вид рабочего листа определяется константой, которая содержится в поле View объекта ActiveWindow. Она может иметь значения xlNormalView=1 или xlPageBreakPreview=2. Функция WindowView для приложений Delphi реализует изменение вида рабочего листа.

Function WindowView (view:integer):boolean;
begin
 WindowView:=true;
 try
  E.ActiveWindow.View:=view;
 except
  WindowView:=false;
 end;
End;

Когда принтер выбран, можно приступать к настройке параметров страницы печати, которые зависят от параметров выбранного принтера. Параметры настройки печати листа содержатся в полях объекта PageSetup, который является свойством листа. Поля объекта PageSetup содержат и определяют ориентацию и пропорции для печати страницы, размеры полей, колонтитулы, порядок и диапазон печати, качество печати. Из всего этого набора остановимся на тех, которые используются наиболее часто. Это задание ориентации страницы, размер бумаги и область печати. Ориентация бумаги определяется константой, которая записывается в поле Orientation объекта PageSetup. Она может иметь два значения: xlLandscape - альбомная и xlPortrait - книжная. Функция PageOrientation реализует это в приложениях Delphi.

Function PageOrientation (sheet:variant;
  orientation:integer):boolean;
begin
 PageOrientation:=true;
 try
  E.ActiveWorkbook.Sheets.Item
   [sheet].PageSetup.Orientation:=orientation;
 except
  PageOrientation:=false;
 end;
End;

Размер бумаги определяется константой, записанной в поле PaperSize, которая может иметь более 40 значений, каждое из которых соответствует различным типовым размерам бумаги (см. приложение www.kornjakov.ru/st2_4.zip). Наиболее часто используются размеры бумаги формата A3 (xlPaperA3=8) и A4 (xlPaperA4=9).

Function PagePaperSize (sheet:variant;
  papersize:integer):boolean;
begin
 PagePaperSize:=true;
 try
  E.ActiveWorkbook.Sheets.Item
   [sheet].PageSetup.PaperSize:=papersize;
 except
  PagePaperSize:=false;
 end;
End;

Область границ страницы - прямоугольная область ячеек, которая будет выведена на печать. Для задания области границ необходимо в поле PrintArea объекта PageSetup записать строку, которая определит верхнюю левую, правую нижнюю ячейку области, например: PrintArea="$A$1:$I$26". Ячейки, которые не входят в эту область, не будут выведены на печать.

Function PagePrintArea (sheet:variant;
  printarea:string):boolean;
begin
 PagePrintArea:=true;
 try
  E.ActiveWorkbook.Sheets.Item
   [sheet].PageSetup.PrintArea:=printarea;
 except
  PagePrintArea:=false;
 end;
End;

Для того, чтобы линии сетки отображались на печатной форме или были спрятаны, используется свойство PrintGridlines объекта PageSetup.

Function PrintGridlines (sheet:variant;
  gridline:boolean):boolean;
begin
 PrintGridlines:=true;
 try
  E.ActiveWorkbook.Sheets.Item
   [sheet].PageSetup.PrintGridlines:=gridline;
 except
  PrintGridlines:=false;
 end;
End;

Важным свойством объекта PageSetup являются размеры полей слева, справа, сверху и снизу (LeftMargin, RightMargin, TopMargin, BottomMargin). В эти поля записывается количество точек. Если исходные величины полей заданы в дюймах, то преобразование осуществляем, используя функцию Point=Application.InchesToPoints(Inche), где Point - количество точек, Inche - величина в дюймах.


Просмотр печати

Когда документ сформирован и выполнены настройки печати, можно переходить к просмотру информации, выводимой на печать. Для этого используем метод PrintPreview объекта "лист". Для применения его в приложениях Delphi можно воспользоваться следующей функцией PrintPreview, где в качестве аргумента применяется номер или имя страницы.

Function PrintPreview (sheet:variant):boolean;
begin
 PrintPreview:=true;
 try
  E.ActiveWorkbook.Sheets.Item[sheet].PrintPreview;
 except
  PrintPreview:=false;
 end;
End;

Можно воспользоваться альтернативным способом для просмотра печати. Он заключается в вызове обычного диалога. Используйте для этого Dialogs.Item(xlDialogPrintPreview).Show, где константа xlDialogPrintPreview=222.

Function PrintPreviewEx:boolean;
begin
 PrintPreviewEx:=true;
 try
  E.Dialogs.Item[xlDialogPrintPreview].Show;
 except
  PrintPreviewEx:=false;
 end;
End;


Печать

После всех настроек и просмотра печати можно переходить непосредственно к печати документа. Для этого будем использовать метод PrintOut объекта "Лист" коллекции Sheets. В функции Print в качестве аргументов передаем номер или имя листа и количество копий для печати.

Function Print (sheet:variant;copies:integer):boolean;
begin
 Print:=true;
 try
  E.ActiveWorkbook.Sheets.Item
   [sheet].PrintOut(Copies:=copies);
 except
  Print:=false;
 end;
End;

Для расширения возможностей печати можем использовать весь набор аргументов метода PrintOut. Например, для задания печати 2-х копий со 2-й по 3-ю страницу используем метод и набор следующих аргументов: PrintOut(from:=2, To:=3, Copies:=2);

Мы рассмотрели все основные вопросы по печати в Excel. Чтобы дополнить описанные функции, используйте свойства объекта PageSetup, которые не рассмотрены в статье, а также другие возможности Excel.Application. В следующей части рассмотрим создание визуальных объектов на листе Excel. Полные исходные тексты с примерами смотрите на www.kornjakov.ru/st2_4.zip. По всем вопросам можете обратиться к автору по адресу _kvn@mail.ru или www.kornjakov.ru.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А.Тенцер "Delphi 6 и технология COM" "Питер" 2002.

К списку статей


Суперфункции EXCEL. Часть 4

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

Для создания и работы с диаграммами в Excel используется коллекция Charts объекта Application. Через эту коллекцию мы можем получить полный доступ ко всем диаграммам и их свойствам. Перед тем, как создавать диаграмму, рассмотрим ее внешний вид и свойства (см. рис.).

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


Создание диаграммы

Для создания диаграммы используем метод Add коллекции Charts. Процедура AddChart (для Delphi) создает диаграмму, устанавливает ее вид и возвращает ее имя для доступа к этой диаграмме в дальнейшем. В качестве второго аргумента функции можно использовать константу xl3Darea(-4098), которая позволяет создать объемную диаграмму. Значения других констант, которые соответствуют другим видам диаграмм, и исходный текст смотрите на www.kornjakov.ru/st2_5.zip.

Function AddChart(var name:string;
  ChartType:integer):boolean;
begin
 AddChart:=true;
 try
  name:=E.Charts.Add.Name;
  E.Charts.Item[name].ChartType:=ChartType;
 except
  AddChart:=false;
 end;
End;


Область данных диаграммы

Данные для построения диаграммы должны быть расположены на любом листе рабочей книги и представлять собой прямоугольную область. Для определения рабочей области данных используется метод SetSourceData, первый аргумент которого - ссылка на лист и область ячеек, второй - определяет способ использования данных (по строкам/столбцам).

Function SetSourceData(Name,Sheet:variant;
  Range:string;XlRowCol:integer):boolean;
begin
 SetSourceData:=true;
 try
  E.ActiveWorkbook.Charts.Item[name].SetSourceData
   (Source:=E.ActiveWorkbook.Sheets.Item [Sheet].Range[Range],PlotBy:=XlRowCol);
 except
  SetSourceData:=false;
 end;
End;


Область диаграммы

Если диаграмма расположена на одном листе с данными, то можно изменять координаты и размеры области диаграммы. Диаграмма может быть размещена также на отдельном листе, тогда ее размеры совпадают с размером листа. Для доступа к координатам и размерам этой области используем объект ChartArea (область диаграммы). Функция PositionChart изменяет ее координаты и размеры. Аналогично мы можем получить координаты и размеры диаграммы. Для этого достаточно считать значения Left, Top, Width и Height объекта ChartArea.

Function PositionChart(Name:variant;
  Left,Top,Width,Height:real):boolean;
begin
 PositionChart:=true;
 try
  E.Charts.Item[name].ChartArea.Left:=Left;
  E.Charts.Item[name].ChartArea.Top:=Top;
  E.Charts.Item[name].ChartArea.Width:=Width;
  E.Charts.Item[name].ChartArea.Height:=Height;
 except
  PositionChart:=false;
 end;
End;

Кроме размеров и координат, область диаграммы имеет свойства, которые определяют стиль, цвет, толщину рамки окаймления, а также рисунок и цвет самой области. Свойства рамки содержатся в объекте Border области ChartArea. Цвет рамки может быть представлен как комбинация из трех цветов RGB или выбран из палитры. Толщина и стиль выбираются из конечного, определенного списка значений (смотрите исходный текст). Используем функцию BorderChartArea для установки типа и цвета рамки из приложений Delphi.

Function BorderChartArea(Name:variant;
  Color,LineStyle,Weight:integer):boolean;
begin
 BorderChartArea:=true;
 try
  E.Charts.Item[name].ChartArea.Border.Color:=Color;
  E.Charts.Item[name].ChartArea.Border.Weight:=Weight;
  E.Charts.Item[name].ChartArea.Border.LineStyle:=LineStyle;
 except
  BorderChartArea:=false;
 end;
End;

Свойства области диаграммы содержатся в объекте Interior. Цвет области и рисунка заполнения может быть представлен как комбинация из трех цветов RGB или выбран из палитры. Вид рисунка заполнения выбирается из конечного, определенного списка значений (смотрите исходный текст). Функция BrushChartArea устанавливает цветовые параметры области диаграммы.

Function BrushChartArea(Name:variant;
  Color,Pattern,PatternColor:integer):boolean;
begin
 BrushChartArea:=true;
 try
  E.Charts.Item[name].ChartArea.Interior.Color:=Color;
  E.Charts.Item[name].ChartArea.Interior.Pattern:=Pattern;
  E.Charts.Item[name].ChartArea.Interior.PatternColor:=PatternColor;
 except
  BrushChartArea:=false;
 end;
End;

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

Function BrushChartAreaFromFile(Name:variant;File_:string):boolean;
begin
 BrushChartAreaFromFile:=true;
 try
  E.Charts.Item[name].ChartArea.Fill.UserPicture(PictureFile:=File_);
  E.Charts.Item[name].ChartArea.Fill.Visible:=True;
 except
  BrushChartAreaFromFile:=false;
 end;
End;

Область диаграммы - это область, которая содержит все остальные объекты диаграммы. Рассмотрим остальные компоненты, расположенные на этой области.


Область построения диаграммы

Область построения диаграммы служит для размещения графического изображения. Она имеет координаты относительно области диаграммы и другие свойства, присущие области: цвет и стиль рамки, цвет заливки и фоновый рисунок. Для доступа к ее координатам и размерам используем объект PlotArea (область построения диаграммы), который содержит все свойства области. Функция PositionPlotArea изменяет ее координаты и размеры.

Function PositionPlotArea(Name:variant;
  Left,Top,Width,Height:real):boolean;
begin
 PositionPlotArea:=true;
 try
  E.Charts.Item[name].PlotArea.Left:=Left;
  E.Charts.Item[name].PlotArea.Top:=Top;
  E.Charts.Item[name].PlotArea.Width:=Width;
  E.Charts.Item[name].PlotArea.Height:=Height;
 except
  PositionPlotArea:=false;
 end;
End;

Другими важными свойствами области диаграммы являются свойства, определяющие стиль, цвет, толщину рамки окаймления и рисунок, цвет самой области. Свойства рамки содержатся в объекте Border области PlotArea. Цвет рамки может быть представлен как комбинация из трех цветов RGB или выбран из палитры. Толщина и стиль выбираются из конечного, определенного списка значений (смотрите исходный текст).

Function BorderPlotArea(Name:variant;
  Color,LineStyle,Weight:integer):boolean;
begin
 BorderPlotArea:=true;
 try
  E.Charts.Item[name].PlotArea.Border.Color:=Color;
  E.Charts.Item[name].PlotArea.Border.Weight:=Weight;
  E.Charts.Item[name].PlotArea.Border.LineStyle:=LineStyle;
 except
  BorderPlotArea:=false;
 end;
End;

Цветовая характеристика области построения диаграммы содержится в объекте Interior. Цвет области и рисунка заполнения может быть представлен как комбинация из трех цветов RGB или выбран из палитры. Вид рисунка заполнения выбирается из конечного, определенного списка значений (смотрите исходный текст). Функция BrushPlotArea устанавливает цветовые параметры области диаграммы.

Function BrushPlotArea(Name:variant;
  Color,Pattern,PatternColor:integer):boolean;
begin
 BrushPlotArea:=true;
 try
  E.Charts.Item[name].PlotArea.Interior.Color:=Color;
  E.Charts.Item[name].PlotArea.Interior.Pattern:=Pattern;
  E.Charts.Item[name].PlotArea.Interior.PatternColor:=PatternColor;
 except
  BrushPlotArea:=false;
 end;
End;

Фон области построения диаграммы может быть представлен не только в виде определенного узора и цветовой комбинации, но и в виде рисунка, загруженного из графического файла. Для этого используется метод UserPicture объекта Fill области PlotArea.

Function BrushPlotAreaFromFile(Name:variant;File_:string):boolean;
begin
 BrushPlotAreaFromFile:=true;
 try
  E.Charts.Item[name].PlotArea.Fill.UserPicture(PictureFile:= File_);
  E.Charts.Item[name].PlotArea.Fill.Visible:=True;
 except
  BrushPlotAreaFromFile:=false;
 end;
End;


Заголовок диаграммы

Заголовок диаграммы имеет такие же параметры, как и любая область, но есть некоторые отличия. Ширина и высота заголовка определяется размером шрифта, и, в отличие от области диаграммы, важным параметром является текст надписи заголовка и сам шрифт как объект, входящий в ChartTitle. Полные версии функций для использования в приложениях Delphi смотрите на www.kornjakov.ru/st2_5.zip, здесь представлены только их фрагменты. Рассмотрим основные свойства объекта ChartTitle. Заголовок и текст заголовка выводится при условии, что в поле HasTitle объекта Chart записано значение True, а поле Text объекта ChartTitle записан сам текст. Смотрите пример:

E.Charts.Item[name].HasTitle:=True;
E.Charts.Item[name].ChartTitle.Text:='Заголовок диаграммы';

Координаты заголовка содержатся в полях Left и Top объекта ChartTitle. Для перемещения заголовка запишите в эти поля новые значения координат. Для определения координат считайте значения из этих полей.

E.Charts.Item[name].ChartTitle.Left:=Left;
E.Charts.Item[name].ChartTitle.Top:=Top;

Чтобы изменить визуальные параметры рамки, используйте объект Border и его поля Color (цвет), Weight (толщина) и LineStyle (стиль линии)

E.Charts.Item[name].ChartTitle.Border.Color:=Color;
E.Charts.Item[name].ChartTitle.Border.Weight:=Weight;
E.Charts.Item[name].ChartTitle.Border.LineStyle:=LineStyle;

Для заполнения цветом и узором области заголовка используйте объект Interior и его поля Color (цвет), Pattern (узор) и PatternColor (цвет узора).

E.Charts.Item[name].ChartTitle.Interior.Color:=Color;
E.Charts.Item[name].ChartTitle.Interior.Pattern:=Pattern;
E.Charts.Item[name].ChartTitle.Interior.PatternColor:=PatternColor;

Чтобы заполнить область заголовка рисунком из графического файла, используйте метод UserPicture объекта Fill. Чтобы этот рисунок стал видимым, запишите в поле Visible объекта Fill значение True.

E.Charts.Item[name].ChartTitle.Fill.UserPicture(PictureFile:= File_);
E.Charts.Item[name].ChartTitle.Fill.Visible:=True;

Мы рассмотрели не все свойства диаграммы, в следующей части рассмотрим остальные свойства, а также программирование графической части диаграммы. Полные исходные тексты с примерами смотрите по адресу www.kornjakov.ru/st2_5.zip. По всем вопросам вы можете обратиться к автору по адресу _kvn@mail.ru или www.kornjakov.ru.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А. Тенцер "Delphi 6 и технология COM" "Питер" 2002.

К списку статей


Суперфункции EXCEL. Часть 6

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


Тип диаграммы

Тип диаграммы определяет, каким образом отображается информация: в виде плоских или объемных фигур или графиков, а также сам вид этих фигур. Существует около 70 типов диаграмм, и чтобы выбрать один из них, используется метод ApplyCustomType. В качестве аргумента этого метода используется константа из списка (см. приложение www.kornjakov.ru/st2_6.zip). В Delphi выбор типа диаграммы можно реализовать, используя функцию SetChartType.

Function SetChartType (Name:variant;ChartType:integer):boolean;
begin
 SetChartType:=true;
 try
  E.Charts.Item[name].ApplyCustomType(ChartType:=ChartType);
 except
  SetChartType:=false;
 end;
End;


Размещение диаграммы

Диаграмма может размещаться совместно с данными или на отдельном листе. Размещение диаграммы лучше совмещать с процессом ее создания, но можно выполнить эту процедуру и самостоятельно. При этом необходимо учитывать, что при изменении размещения меняется и имя диаграммы (не путать с названием). Для размещения диаграммы используйте функцию SetChartLocation, аргумент xlLocation которой может иметь одно из двух значений (xlLocationAsNewSheet или xlLocationAsObject).

Function SetChartLocation (var name:variant;sheet:variant;
  xlLocation:integer):boolean;
begin
 SetChartLocation:=true;
 try
  name:=E.Charts.Item[name].Location(Where:=
   xlLocationAsObject,Name:=sheet).name;
 except
 SetChartLocation:=false;
 end;
End;


Наклон и поворот

Наклон диаграммы можно выполнить на угол от -90° до +90°. Значения, выходящие за эти пределы, вызывают ошибку. Выбор угла поворота осуществляется записью значения угла в свойство Elevation объекта Chart. Поворот диаграммы осуществляется записью в поле Rotation объекта Chart значения угла поворота. Этот угол может иметь значения от 0° до 360°. Для задания углов наклона и поворота в приложениях на Delphi можно использовать функции ElevationChart и RotationChart.

Function ElevationChart (Name:variant;Elevation:real):boolean;
begin
 ElevationChart:=true;
 try
  E.Charts.Item[name].Elevation:=Elevation;
 except
  ElevationChart:=false;
 end;
End;
Function RotationChart(Name:variant;Rotation:real):boolean;
begin
 RotationChart:=true;
 try
  E.Charts.Item[name].Rotation:=Rotation;
 except
  RotationChart:=false;
 end;
End;


Легенда

Легенда диаграммы представляет собой подписи к той части, которая передает информацию в графическом виде. Как и любая область, она обладает типичными свойствами, присущими им. Есть одно отличие - шрифт элемента легенды. Чтобы легенда была видима на диаграмме, установите поле HasLegend объекта Chart в True.E.Charts.Item[name].HasLegend:=True. Затем можно установить координаты и размеры легенды, параметры границы (рамки) и области. Для этого используем следующие функции:

Установка размеров и координат.

Function PositionSizeLegend (Name:variant;
  Left,Top,Width,Height:real):boolean;
begin
 PositionSizeLegend:=true;
 try
  E.Charts.Item[name].Legend.Left:=Left;
  E.Charts.Item[name].Legend.Top:=Top;
  E.Charts.Item[name].Legend.Width:=Width;
  E.Charts.Item[name].Legend.Height:=Height;
 except
  PositionSizeLegend:=false;
 end;
End;

Установка типа и цвета рамки.

Function BorderLegend (Name:variant;
  Color,LineStyle,Weight:integer):boolean;
begin
 BorderLegend:=true;
 try
  E.Charts.Item[name].Legend.Border.Color:=Color;
  E.Charts.Item[name].Legend.Border.Weight:=Weight;
  E.Charts.Item[name].Legend.Border.LineStyle:=LineStyle;
 except
  BorderLegend:=false;
 end;
End;

Установка цвета и типа узора области.

Function BrushLegend (Name:variant;
  Color,Pattern,PatternColor:integer):boolean;
begin
 BrushLegend:=true;
 try
  E.Charts.Item[name].Legend.Interior.Color:=Color;
  E.Charts.Item[name].Legend.Interior.Pattern:=Pattern;
  E.Charts.Item[name].Legend.Interior.PatternColor:=PatternColor;
 except
  BrushLegend:=false;
 end;
End;

Заливка области из файла.

Function BrushLegendFromFile (Name:variant;File_: string):boolean;
begin
 BrushLegendFromFile:=true;
 try
  E.Charts.Item[name].Legend.Fill.UserPicture(PictureFile:=File_);
  E.Charts.Item[name].Legend.Fill.Visible:=True;
 except
  BrushLegendFromFile:=false;
 end;
End;

Шрифт элемента легенды.

Объект Legend имеет доступ к коллекции LegendEntries, посредством которой можно получить доступ к шрифту элемента легенды. Например: E.Charts.Item[name].Legend.LegendEntries.Item[LegendEntries].Font, где LegendEntries - индекс элемента. Чтобы согласовать поля объектов "Шрифт" в Excel и Delphi, напишем функцию FontToEFont, которая преобразует шрифт объекта Delphi в шрифт объекта Excel. Эту функцию можно будет использовать везде, где необходимо установить шрифт.

Function FontToEFont (font:Tfont;EFont:variant):boolean;
Begin
 FontToEFont:=true;
 try
  EFont.Name:=font.Name;
  if fsBold in font.Style
   then EFont.Bold:=True // Жирный
   else EFont.Bold:=False; // Тонкий
  if fsItalic in font.Style
   then EFont.Italic:=True // Наклонный
   else EFont.Italic:=False; // Наклонный
  EFont.Size:=font.Size; // Размер
  if fsStrikeOut in font.Style
   then EFont.Strikethrough:=True // Перечеркнутый
   else EFont.Strikethrough:=False; // Перечеркнутый
  if fsUnderline in font.Style
   then EFont.Underline:=xlUnderlineStyleSingle // Подчеркивание
   else EFont.Underline:=xlUnderlineStyleNone; // Подчеркивание
  EFont.Color:=font.Color; // Цвет
 except
  FontToEFont:=false;
 end;
End;

Функция FontLegendEntries устанавливает шрифт элемента(LegendEntries) легенды(Name).

Function FontLegendEntries(Name,LegendEntries:variant;
  Font:TFont):boolean;
begin
 FontLegendEntries:=true;
 try
  FontLegendEntries:=
   FontToEFont(Font,E.Charts.Item[name].Legend.LegendEntries.Item[LegendEntries].Font);
 except
  FontLegendEntries:=false;
 end;
End;


Подписи осей

Оси диаграммы могут иметь подписи, представляющие собой области и описываемые свойствами, присущими любым прямоугольным областям на диаграмме. Рассмотрим только запись текста и включение, выключение отображения объекта "подпись оси". Доступ ко всем полям и методам подписи осуществляется через коллекцию Axes, члены которой и есть ссылки на подписи. В приложениях Delphi запись текста в объект "подпись оси" можно реализовать с помощью функции AxisChart.

Function AxisChart (Name:variant;Category,Series,Value:string):boolean;
begin
 AxisChart:=true;
 try
  if Category<>'' then E.Charts.Item[name].Axes[xlCategory].HasTitle:=True
   else E.Charts.Item[name].Axes[xlCategory].HasTitle:=False;
  if Series<>'' then E.Charts.Item[name].Axes[xlSeries].HasTitle:=True
   else E.Charts.Item[name].Axes[xlSeries].HasTitle:=False;
  if Value<>'' then E.Charts.Item[name].Axes[xlValue].HasTitle:=True
   else E.Charts.Item[name].Axes[xlValue].HasTitle:=False;
  E.Charts.Item[name].Axes[xlCategory].AxisTitle.Text:=Category;
  E.Charts.Item[name].Axes[xlSeries].AxisTitle.Text:=Series;
  E.Charts.Item[name].Axes[xlValue].AxisTitle.Text:=Value;
 except
  AxisChart:=false;
 end;
End;


Стены и основание диаграммы

Стены представляют собой вертикальные области, ограничивающие графическую часть диаграммы, и описываются через свойства и методы объекта Walls. Этот объект имеет такие свойства, как цвет и стиль окаймления, стиль и цвет (заливка) области стен. Функции управления этими свойствами смотрите в приложении (www.kornjakov.ru/st2_6.zip), а здесь рассмотрим их фрагменты.

Цвет, толщина и стиль рамки окаймления:

E.Charts.Item[name].Walls.Border.Color:=Color;
E.Charts.Item[name].Walls.Border.Weight:=Weight;
E.Charts.Item[name].Walls.Border.LineStyle:=LineStyle;

Цвет, рисунок и цвет рисунка заполнения стен:

E.Charts.Item[name].Walls.Interior.Color:=Color;
E.Charts.Item[name].Walls.Interior.Pattern:=Pattern;
E.Charts.Item[name].Walls.Interior.PatternColor:=PatternColor;

Заливка области стен из файла:

E.Charts.Item[name].Walls.Fill.UserPicture(PictureFile:=File_);
E.Charts.Item[name].Walls.Fill.Visible:=True;

Основание графической части диаграммы - область, ограничивающая диаграмму внизу. Она описывается через свойства и методы объекта Floor. Этот объект обладает аналогичными свойствами, как и область стен. Вот несколько примеров их настройки из приложений Delphi.

Цвет, толщина и стиль линий - границы основания:

E.Charts.Item[name].Floor.Border.Color:=Color;
E.Charts.Item[name].Floor.Border.Weight:=Weight;
E.Charts.Item[name].Floor.Border.LineStyle:=LineStyle;

Цвет, рисунок и цвет рисунка области основания:

E.Charts.Item[name].Floor.Interior.Color:=Color;
E.Charts.Item[name].Floor.Interior.Pattern:=Pattern;
E.Charts.Item[name].Floor.Interior.PatternColor:=PatternColor;

Заливка области основания из файла:

E.Charts.Item[name].Floor.Fill.UserPicture(PictureFile:=File_);
E.Charts.Item[name].Floor.Fill.Visible:=True;


Серии коллекции

Рассмотрим серии коллекции - графики, набор фигур на диаграмме. Доступ к коллекциям получаем через объект SeriesCollection. Количество их зависит от размеров области данных диаграммы на рабочем листе. Чтобы получить его значение, считаем поле Count объекта SeriesCollection. Функция SeriesCount (для работы в среде Delphi) возвращает количество серий.

Function SeriesCount (Name:variant):integer;
begin
 SeriesCount:=-1;
 try
  SeriesCount:=E.Charts.Item[name].SeriesCollection.Count;
 except
  SeriesCount:=-1;
 end;
End;

Рассмотрим вид коллекции - вид фигур в коллекции (куб, пирамида и др.). Я насчитал шесть видов. Для своих приложений можем использовать функцию BarShapeSeries для выбора любого из шести видов.

Function BarShapeSeries (Name:variant;series,BarShape:integer):boolean;
begin
 BarShapeSeries:=true;
 try
  E.Charts.Item[name].SeriesCollection.Item[series].BarShape:=BarShape;
 except
  BarShapeSeries:=false;
 end;
End;

Остальные параметры: параметры границы и областей коллекции аналогичны параметрам любых областей диаграммы. Привожу их краткий список в виде операторов для Delphi:

E.Charts.Item[name].SeriesCollection.Item[series].Border.Color:=Color;
E.Charts.Item[name].SeriesCollection.Item[series].Border.Weight:=Weight;
E.Charts.Item[name].SeriesCollection.Item[series].Border.LineStyle:=LineStyle;
E.Charts.Item[name].SeriesCollection.Item[series].Interior.Color:=Color;
E.Charts.Item[name].SeriesCollection.Item[series].Interior.Pattern:=Pattern;
E.Charts.Item[name].SeriesCollection.Item[series].Interior.PatternColor:=PatternColor;
E.Charts.Item[name].SeriesCollection.Item[series].Fill.UserPicture(PictureFile:=File_);
E.Charts.Item[name].SeriesCollection.Item[series].Fill.Visible:=True;

Мы рассмотрели только малую часть из того, что позволяет программировать процесс создания документа в Excel из приложений на Delphi. Ответы на остальные вопросы вы можете получить сами, например, методом изучения дополнительной литературы или методом проб и ошибок. В дальнейшем рассмотрим создание и варианты использования динамической библиотеки на базе наработанного материала. Полные исходные тексты с примерами смотрите по адресу www.kornjakov.ru/st2_6.zip. По всем вопросам можете обратиться к автору по адресу _kvn@mail.ru или www.kornjakov.ru.

Василий КОРНЯКОВ

Литература: Н. Елманова, С. Трепалин, А. Тенцер "Delphi 6 и технология COM" "Питер" 2002.

К списку статей


Суперфункции Создание DLL-библиотеки для работы с Word/Excel из приложений на Delphi

Если вы хотите и готовы предложить своим коллегам свои собственные API-функции для работы с документами Word и Excel, то эта статья вам очень пригодится.

Весь набор функций, который рассмотрен в статьях №1 и №2, можно реализовать в виде DLL-библиотеки. Реализация в виде DLL дает большие преимущества программисту в гибкости, надежности использования своих программных продуктов и сокращает время на разработку программного обеспечения. В своих библиотеках вы можете заложить базовые функции, которые не будут изменяться довольно часто, при этом основное приложение, которое использует библиотеки, может меняться достаточно часто и совершенствоваться от версии к версии. Функции, оформленные в виде DLL, называются иначе - API-функциями. Система Windows использует как системные, так и пользовательские функции API.

Если вы решите создавать библиотеку для работы с Word.Application (Excel.Application), то столкнетесь с некоторыми особенностями, которые укладываются в общее представление о создании динамических библиотек. Эти особенности связаны с преобразованием формата данных, передаваемых через механизм DDE.

Приступим к созданию нашей библиотеки (назовем ее MyLWord). Выполним команду меню "File" -> "New..." . В открывшемся окне выберите закладку "New" и далее пиктограмму "DLL", нажмите кнопку "OK". Получим новый проект. Его название изменим на MyLWord и сохраним под тем же именем. Используем нашу библиотеку MyWord, которая была создана ранее (см. "Суперфункции 1.5"). Изменим эту библиотеку, дописав в конец объявления каждой процедуры в секции interface ключевое слово StdCall, которое определяет соглашение о передаче параметров через стек. В файле проекта MyLWord.dpr в секцию подключения внешних модулей uses допишем ссылку на библиотеку MyWord. После секции uses создадим секцию экспортируемых процедур и функций, напишем ключевое слово exports, после которого через запятую перечислим список всех экспортируемых процедур и функций. Если откомпилировать этот проект, то получим файл динамической библиотеки MyLWord.dll. Ниже представлены фрагменты перечисленных выше файлов.

Файл - MyLWord.dpr

library MyLWord;
uses
 SysUtils,
 Classes,
 MyWord;
{$R *.RES}
exports
 CreateWord,
 VisibleWord,
 ................,
 GetNameIndexShape;
Begin
// Секция инициализации модуля, можно вставлять функции,
 которые должны выполняться при загрузке модуля,например
 начальная загрузка данных, которые будут использоваться
 всеми функциями и процедурами модуля.
end.

Файл - MyWord.pas

unit MyWord;
interface
 const
  wdBorderTop=-1;
  ......................
  wdLineStyleEngrave3D=22;
Function CreateWord:boolean; StdCall
Function VisibleWord(visible:boolean):boolean; StdCall
.........................................
Function SetNewNameShape(NameShape:variant;
  NewNameShape:string):string; StdCall
Function GetNameIndexShape(NameIndex:variant):string; StdCall
 var W:variant;
implementation
uses ComObj;
Function CreateWord: boolean;
 begin
  CreateWord:=true;
 try
  W:=CreateOleObject ('Word.Application');
  .........................................
Function DeleteShape (NameShape:variant): variant;
Begin
 DeleteShape:=true;
 try
  W.ActiveDocument.Shapes.Item(NameShape).Delete;
 except
  DeleteShape:=false;
 end;
end;
end.

После создания динамической библиотеки процедур и функций рассмотрим ее использование. Для этого возьмем пример, описанный в предыдущих статьях "Суперфункции". Любую динамическую библиотеку можно использовать двумя основными способами: загрузка библиотеки при старте EXE-модуля и динамическая загрузка, которая выполняется в местах программы, там, где это необходимо. Преимущество первого метода заключается в простоте написания кода, второго - в гибкости, например, в зависимости от каких-либо условий программы можно загружать различные модули, содержащие одинаковые функции. Если используется первый вариант, то при отсутствии модуля DLL программа просто не загрузится, при втором варианте программа загрузится, но в местах вызова модуля будет сгенерирована ошибка, которую можно обработать.

Рассмотрим подробнее вариант загрузки модуля DLL при старте программы, которая его использует. Если вы хотите использовать какую-либо функцию динамической библиотеки, то достаточно в модуле, где будет использоваться функция, добавить строку объявления такого типа:

Function (Procedure) <Имя функции (процедуры)>(<список переменных и типов>): <возвращаемое значение>; external '<Имя файла библиотеки с расширением>' name ' Имя функции или процедуры ';

Конкретные примеры:

Function CreateWord:boolean;
  external 'MyLWord.dll' name 'CreateWord';
Function VisibleWord(visible:boolean):boolean;
  external 'MyLWord.dll' name 'VisibleWord';
.........................
Begin
 .....................
 if CreateWord then VisibleWord(true);
 .....................
End.

Для объявления функций и процедур динамической библиотеки удобно использовать отдельный модуль Unit. В таком модуле в секции interface перечисляются функции и процедуры с указанием имен, параметров и типов возвращаемых значений как в обычном модуле, в секции implementation они описываются с указанием на модули (имена файлов) DLL и оригинальные имена. Например:

unit MyDWord;
interface
Function CreateWord: boolean; StdCall
Function VisibleWord (visible:boolean):boolean; StdCall
.........................................
Implementation
Function CreateWord:boolean;
  external 'MyLWord.dll' name 'CreateWord';
Function VisibleWord (visible:boolean):boolean;
  external 'MyLWord.dll' name 'VisibleWord';
.........................................
End.

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

Uses MyDWord;
.........................................
Begin
// Выполним загрузку Word'а, вызвав необходимые функции.
if CreateWord then VisibleWord(true);
end;

Рассмотрим динамическое выполнение процедур и функций модуля DLL. Для динамической загрузки и выполнения необходимо определить типы вызываемых процедур (функций), загрузить библиотеку DLL, получить адреса входа в процедуру (функцию), выполнить процедуру (функцию) и выгрузить библиотеку.

Для этого рассмотрим следующий пример:

//Выполним загрузку и отображение Word'а, используя
 функции CreateWord и VisibleWord. В секции type
 определим их типы, они должны совпадать с оригиналом
 в модуле DLL.
type
TCreateWord=function: boolean;
TVisibleWord=function (visible:boolean):boolean;
//В разделе описания переменных определим переменную
 hdll:thandle, через которую будем обращаться к функциям
 работы с библиотекой, и переменные - ссылки на процедуры
 динамической библиотеки.
var hdll:thandle;
 CreateWord:TCreateWord;
 VisibleWord:TvisibleWord;
Begin
//В секции кода выполним загрузку модуля (библиотеки)
 и получим ее handle.
 hdll:=LoadLibrary ('MyLWord.dll');
//Получим точки входа в функции.
 CreateWord:=GetProcAddress (hdll,'CreateWord');
 VisibleWord:=GetProcAddress (hdll,'VisibleWord');
// Выполним загрузку Word'а, вызвав необходимые функции.
 if CreateWord then VisibleWord(true);
// Выгрузим библиотеку (очистим память от библиотеки).
 FreeLibrary(hdll);
end;

Как видно, динамическая загрузка библиотеки немного сложнее, но, несмотря на это, она оправдывает себя. Используя данный материал, вы сможете создать и использовать свою персональную динамическую библиотеку для работы с редакторами Word и Excel. Полные исходные тексты с примерами смотрите по адресу www.kornjakov.ru/st3_1.zip. По всем вопросам можете обратиться к автору по адресу _kvn@mail.ru или www.kornjakov.ru.

Василий КОРНЯКОВ

Литература: Марко Кенту "Delphi 6 " "Питер" 2002.

К списку статей


Суперфункции Создание средствами Delphi DLL библиотек для использования в макросах Excel

Рассмотрим, как создать (средствами Delphi) и использовать динамическую библиотеку в макросах книги Excel. Что это дает? Это дает возможность независимо от разработки основной задачи создавать гибкие отчетные формы, которые можно быстро перестраивать по желанию ваших пользователей. Это особенно удобно, когда имеем дело с теми базами данных, которые плохо согласуются с Excel.

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

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


Вызов стандартных процедур Windows из макроса Excel

Для начала рассмотрим, как мы можем использовать какую-либо функцию или процедуру из любой динамической библиотеки и какие ограничения накладываются на них и на их входные/выходные параметры (переменные). Во-первых, не все типы переменных можно использовать в таких функциях, только небольшое количество типов данных в Excel и Delphi могут иметь общую структуру. Я использую следующие типы данных: String - строка длиной до 64 Кб или до нескольких ГГб, ограниченная символом CHR(0); Integer - число в пределах -32768 до 32767; Byte - число от 0 до 255; Boolean - логическая переменная (True|False); Variant - тип данных, к которому относятся все переменные, не описанные явно. Чтобы подробнее познакомиться с данным вопросом и узнать о всех возможных типах данных, используйте Help по Excel, раздел "Справочник по Visual Basic". Когда мы уяснили, какими типами данных мы можем оперировать, попробуем подключить и вызвать какую-либо функцию или процедуру из стандартной библиотеки. В качестве примера можем поработать с функцией Messagebox из состава стандартных динамических библиотек Windows. Функция Messagebox использует в качестве входных и возвращаемых значений типы Integer и Pchar. В макросе Excel тип Pchar можно заменить типом String. Прежде чем обращаться к внешней процедуре в макросе, необходимо ее описать. Приведу общую структуру описания:

Синтаксис для процедуры:

Declare Sub имя Lib "Имя Библиотеки" [Alias "псевдоним"] [([списокАргументов])]

Синтаксис для функции:

Declare Function имя Lib "Имя Библиотеки" [Alias "псевдоним"] [([списокАргументов])] [As тип]

Sub - указывает, что процедура не возвращает значение;

Function - указывает, что процедура возвращает значение, которое может быть использовано в выражении;

Lib - указывает, что описываемая процедура содержится в динамической библиотеке;

" Имя библиотеки " - имя динамической библиотеки;

Alias -указывает, что вызываемая процедура имеет другое имя в библиотеке;

"псевдоним" - имя процедуры в библиотеке;

списокАргументов - список переменных, представляющий аргументы, которые передаются в процедуру при ее вызове;

тип - тип данных значения, возвращаемого процедурой Function.

В нашем примере мы из Excel вызываем функцию Messagebox. Если просмотреть входящий в состав Delphi файл Windows.pas, то найдем там указатель на эту функцию. Используем эту информацию. Итак, мы узнали, что эта функция входит в состав библиотеки user32.dll, а ее описание выглядит следующим образом:

Interface
............
function MessageBoxA(hWnd:HWND;lpText,lpCaption:PAnsiChar;
  uType:UINT):Integer; stdcall;
............
implementation
............
function MessageBoxA; external user32 name 'MessageBoxA';

Следовательно, в макросе в объявлении функции мы напишем следующую строку:

Declare Function MessageBoxA Lib "user32.dll" (ByVal hwnd
  As Integer, ByVal lpText As String, ByVal lpCaption As
String, ByVal uType As Integer) As Integer

В теле процедуры макроса напишем следующее:

Public Sub Message()
Call MessageBoxA(0, "Тип объекта = " + TypeName(Selection),
  "Вызов функции MessageBox из библиотеки user32.dll", 0)
Call MessageBoxA(0, "Значение ячейки = " + Range("A1").Text,
  "Вызов функции MessageBox из библиотеки user32.dll", 0)
End Sub

Если выполнить этот макрос, то мы получим результат в виде следующего окна диалога:

Разработка в среде Delphi диалогов в динамических процедурах и функциях и их вызов из макроса Excel

Создадим функцию в составе динамической библиотеки (ее будем использовать в макросах), содержащую диалог выбора даты, она будет возвращать дату. Эту функцию будем использовать для записи даты в ячейку таблицы. Первым шагом будет создание нового проекта LibForOf. Файл LibForOf.dpr имеет следующий вид:

library LibForOf;
uses
 SysUtils,
 Classes,
 st3_2;
{$R *.RES}
exports
 GetDateDialog,
 GetSumInWords;
begin
end.

Подключаемая библиотека st3_2.pas содержит тексты экспортируемых процедур. Наша функция выбора даты имеет следующий вид:

interface
Function GetDateDialog:variant; Stdcall;
...............
implementation
..............
Function GetDateDialog:variant;
begin
 Application.CreateForm(TDateDlg_,DateDlg_);
 if DateDlg_.ShowModal=mrOk
  then GetDateDialog:=DateDlg_.MonthCalendar1.Date
  else GetDateDialog:=null;
 DateDlg_.Free;
End;

Где:

Stdcall - директива, определяющая способ передачи данных через стек;

DateDlg_ - форма - диалог (подробности и исходные тексты - в файле www.kornjakov.ru/st3_2.zip).

Для того, чтобы использовать нашу функцию, скопируйте полученный в результате компиляции файл LibForOf.dll в каталог windows\system32. После этого можно приступить к написанию макроса, который будет использовать данную функцию динамической библиотеки. Вначале опишем функцию, используя ключевое слово Declare. Описание выглядит следующим образом:

Declare Function GetDateDialog Lib "LibForOf.dll" () As Variant

В функцию не передаются параметры, но она возвращает данные - дату. Так как переменная типа даты может не использоваться для динамических процедур в ранних версиях Excel, то определим ее тип как variant. После того, как функция декларирована, приступим к написанию самого макроса. Он выглядит следующим образом:

Public Sub DateDialog()
Selection = GetDateDialog
End Sub

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

Разработка динамических функций в среде Delphi для использования в формулах, применяемых к ячейкам таблиц Excel

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

unit st3_2;
interface
..............
Function GetSumInWords(cur_:currency;
  var stroka_:string):boolean; Stdcall;
..............
implementation
..............
Function GetSumInWords(cur_:currency;
  var stroka_:string):boolean;
label 1;
var ss_r,ss_k,rub_,ckop_,kop_:shortstring;
.................
begin
 1:
 str_:=currtostr(cur_);
 if str_<>'' then
...............................
End;

Полный исходный текст и макросы смотрите на www.kornjakov.ru/st3_2.zip.

Опишем функцию, используя ключевое слово Declare. Описание выглядит следующим образом:

Declare Function GetSumInWords Lib "LibForOf.dll" (ByVal cur As Currency, stroka_ As String) As Boolean

В переменной stroka_ функция возвращает текстовый эквивалент передаваемой в первом аргументе суммы. Сам макрос выглядит следующим образом:

Public Function SumInWords(cur_ As Currency) As String
Dim str_ As String
Call GetSumInWords(cur_, str_)
SumInWords = str_
End Function

Для того, чтобы наша функция начала работать, в любой ячейке (например, в F1) вставим формулу вида: =SumInWords(A1) и получим следующий результат:

Как видно из статьи, стандартные средства Excel можно дополнить своими нестандартными функциями и процедурами, перенести и использовать собственный опыт по разработке приложений в среде Delphi для создания отчетов в виде макросов. Используя данный материал, вы сможете создать и использовать свою персональную динамическую библиотеку для работы не только с редактором Excel, но и с редактором Word. Полные исходные тексты с примерами смотрите по адресу www.kornjakov.ru/st3_2.zip. По всем вопросам обращайтесь к автору по адресу _kvn@mail.ru или www.kornjakov.ru.

Василий КОРНЯКОВ

Литература: Смотрите Help для Excel.

К списку статей

 


Суперфункции Ответы на вопросы

Как и в любом деле, так и в процессе работы с созданной библиотекой функций формирования документов в Word, появились вопросы, на которые нужно найти ответы. Данная статья посвящена анализу поступившей информации и поиску ответов на вопросы читателей. Вопросы читателей показали, что материал по "Суперфункциям" интересен в практическом применении и нуждается в расширении и уточнении, что я пытаюсь сделать. Перехожу к вопросам и ответам.


Как переместить курсор в конец только что открытого файла, т.е. дописать текст в конец?

Используем объект Selection. Объект Selection имеет поля Start и End. Эти поля имеют тип Integer и содержат номера символов начальной и конечной позиции выделенного текста. Если выделить весь документ, а затем считать значения этих полей, то сможем определить объем документа как количество символов. Если в поле Start объекта Selection записать значение из поля End этого же объекта, то курсор будет перемещен в конец документа. Используем это обстоятельство для перемещения курсора в конец документа. В Delphi это выглядит следующим образом:

Function EndOfDoc:boolean;
begin
 EndOfDoc:=true;
 try
  W.ActiveDocument.Range.Select;
  W.Selection.Start:=W.Selection.End;
 except
  EndOfDoc:=false;
 end;
End;


Как изменить шрифт в таблице?

Попробуем изменить шрифт только в ячейке таблицы. Для этого можно использовать объект Font как свойство ячейки, например: ActiveDocument.Tables.Item(Table).Columns.Item(Column).Cells.Item(Row).Range.font.

Есть и другой способ: можно выделить ячейку и работать с объектом Selection.Font. Второй способ выгоден тем, что его можно использовать для изменения шрифта не только в таблице, но и во всех выделенных объектах. Рассмотрим его подробнее. Выделим ячейку таблицы, используя метод Select объекта Cell. В Delphi эта функция будет выглядеть следующим образом:

Function SelectCell(Table:integer;
  Row,Column:integer):boolean;
begin
 SelectCell:=true;
 try
  W.ActiveDocument.Tables.Item(Table).Columns.Item
   (Column).Cells.Item(Row).Select;
 except
  SelectCell:=false;
 end;
End;

Используем эту функцию для выделения определенной ячейки таблицы. После этого можно приступать к работе со свойством Font объекта Selection. Объект Font аналогичен одноименному объекту в Delphi, но имеет некоторые отличия: цвет шрифта определяется индексом, который может иметь небольшое количество возможных значений, но количество режимов подчеркивания и перечеркивания текста больше, чем для шрифта в Delphi. Так как предполагается, что мы разрабатываем приложения на Delphi для разработки документов в Word, то было бы удобно применить функцию преобразования полей шрифта. Приведу пример такой функции:

Function FontToEFont(font:Tfont;EFont:variant;
  ColorIndex:integer):boolean;
begin
 FontToEFont:=true;
 try
  EFont.Name:=font.Name;
  if fsBold in font.Style
   then EFont.Bold:=True // Жирный
   else EFont.Bold:=False; // Тонкий
  if fsItalic in font.Style
   then EFont.Italic:=True // Наклонный
   else EFont.Italic:=False; //
  EFont.Size:=font.Size; // Размер
  if fsStrikeOut in font.Style
   then EFont.Strikethrough:=True // Перечеркнутый
   else EFont.Strikethrough:=False; //
  if fsUnderline in font.Style
   then EFont.Underline:=wdUnderlineSingle // Подчеркивание
   else EFont.Underline:=wdUnderlineNone; //
  EFont.ColorIndex:=ColorIndex; // Цвет
 except
  FontToEFont:=false;
 end;
End;

Когда объект выделен, можем изменить его шрифт, для этого используем приведенную ниже функцию для объекта Selection:

Function SetFontSelection(font:Tfont;
  ColorIndex:integer):boolean;
begin
 SetFontSelection:=true;
 try
  SetFontSelection:=FontToEFont(font,W.Selection.font,ColorIndex);
 except
  SetFontSelection:=false;
 end;
End;

В теле вашей программы замена шрифта будет выглядеть, например, следующим образом:

SelectCell(tab_,2,3); SetFontSelection(Button2.font,5);

Где tab_ - номер таблицы, Button2.font - шрифт кнопки, 5 - индекс цвета.


Как изменить положение таблицы на листе (подвинуть влево, вправо, вверх, вниз)?

Координаты таблицы можно изменить, но эти изменения ограничены по своим возможностям:

  1. две таблицы нельзя выстроить на странице в одну линию, их можно разместить как строки: вторая таблица идет на следующей строке после первой;
  2. есть возможность менять только левый отступ таблицы от края листа. Вертикальное положение определяется строкой, на которой создается таблица. Поэтому чтобы изменить вертикальное положение таблицы, необходимо добавить или удалить строки, расположенные выше таблицы. Левый отступ определяется значением, записанным в поле LeftIndent коллекции Rows таблицы:
    W.ActiveDocument.Tables.Item (tab_).Rows.LeftIndent=Left;
    где Tab_ - номер таблицы, Left - левый отступ таблицы.


Как изменить цвет сетки таблицы?

Информация о стиле, цвете и других параметрах ячейки таблицы содержится в элементах коллекции Borders, которые, по сути, представляют собой линии, ограничивающие и пересекающие ячейку. Выбор элемента коллекции производится через константы WdBorderBottom, WdBorderHorizontal, WdBorderLeft, WdBorderRight, WdBorderTop, wdBorderVertical. Цвет сетки определяется индексом, который записывается в поле ColorIndex элемента коллекции. Оператор установки цвета для Delphi выглядит следующим образом, смотрите пример:

W.ActiveDocument.Tables.Item(tab_).Columns.Item(col_).Cells.Item(row_).Borders.Item(wdBorderTop).ColorIndex:

=wdDarkRed;

где tab_ - номер таблицы, col_ - номер колонки, row_ - номер строки, wdBorderTop - верхняя граница ячейки, wdDarkRed - цветовой индекс. Значения цветовых индексов и констант, определяющих выбор элемента коллекции Borders, можно определить опытным путем, запустив макрос Word. Например:

Sub Макрос16()
'
' Макрос16 Макрос
' Макрос записан 29.07.03 Корняков Василий Николаевич
'
 MsgBox (wdBorderTop)
End Sub


Как напечатать документ без предварительной настройки принтера (что печатать, какое качество печати и т.д.)?

Для печати без отображения диалога я использую метод PrintOut. В качестве аргумента этого метода можно указать количество копий, но можно использовать и другие параметры, которые устанавливаются в диалоге печати (см. Help по VB). Приведу только простой пример функции для печати нескольких копий.

Function PrintOutDoc(NumCopies:integer):boolean;
begin
 PrintOutDoc:=true;
 try
  W.ActiveDocument.PrintOut(NumCopies);
 except
  PrintOutDoc:=false;
end;


Как напечатать документ с предварительной настройкой принтера?

Для печати документа через диалог можно использовать элемент wdDialogFilePrint коллекции Dialogs, метод Show.W.Dialogs.Item(wdDialogFilePrint).Show; где wdDialogFilePrint=88; Если в этом диалоге использовать метод Execute, то будет запущена печать без диалога.


Как выравнивать текст в документе (по ширине, по центру и т.д.)?

Если выделить объект (часть объекта), то к нему можно применять операции выравнивания текста, используя методы и свойства объекта Selection. Используйте поле Alignment объекта Selection.ParagraphFormat. Например:

W.Selection.ParagraphFormat.Alignment:=wdAlignParagraphCenter;

W.Selection.ParagraphFormat.Alignment:=wdAlignParagraphRight;

W.Selection.ParagraphFormat.Alignment:=wdAlignParagraphJustify;

где:

WdAlignParagraphCenter=1;

WdAlignParagraphRight=2;

WdAlignParagraphJustify=3;


Внести текст в ячейку можно, только если все ячейки одинаковой ширины и высоты. Иначе попросту OLE выдаст ошибку. Как быть, если таблица содержит столбцы, количество строк в которых разное?

Я использую перемещение от одной ячейки к следующей или поиск по шаблону. Затем заполняю выделенную ячейку информацией.


Можно ли работать и создавать, редактировать документы, используя объект Word.Basic?

Можно работать с документами Word, используя Word.Basic. Для этого вначале создаем объект W:=CreateOleObject('Word.Basic'). Чтобы открыть файл, используем W.FileOpen('Путь и имя файла'). Для сохранения файла используем W.FileSave. Для поиска строки используем W.EditFind ('текст'), после чего оцениваем результат поиска W.EditFindFound и т.д. Объект Word.Application имеет больше возможностей, поэтому лучше использовать его.


Уточнение по работе с "Офисом XP" (замечание автора)

Для работы в "Офисе XP" пришлось аргументы типа real заменить аргументами типа extended. Это пришлось сделать во всех функциях, особенно там, где необходимо установить координаты расположения объектов. Смотрите пример изменения координат и размеров объекта TextBox:

Function SetPosZizeTextBox(TextBox:variant;
  Left,Top,Width,Height:real):boolean;
 const msoTextBox=17;
 var l_,t_,w_,h_:Extended;
begin
 SetPosZizeTextBox:=true;
 try
  l_:=Left; t_:=Top; w_:=Width; h_:=Height;
  if w.ActiveDocument.Shapes.Item(TextBox).Type=msoTextBox
   then begin
    W.ActiveDocument.Shapes.Item(TextBox).Left:=l_;
    W.ActiveDocument.Shapes.Item(TextBox).Top:=t_;
    W.ActiveDocument.Shapes.Item(TextBox).Width:=w_;
    W.ActiveDocument.Shapes.Item(TextBox).Height:=h_;
   end
   else SetPosZizeTextBox:=false;
 except
  SetPosZizeTextBox:=false;
 end;
End;

MS Word и Excel предоставляют мощное средство для разработки выходных документов. А раз это есть, то этим нужно пользоваться и создавать конкурентно-способные приложения. Мы рассмотрели только малую часть, но вы можете сами развивать эту тему и применить свой опыт в практической деятельности. Для тех, кто желает дальше и глубже копнуть, могу сказать, что Word и Excel предоставляют возможность не только создавать и модифицировать документы из внешних программ, но и модифицировать свой вид, работать с меню, панелями и кнопками, но это тема для отдельной статьи. Кто желает посмотреть практический результат от применения данных библиотек, прошу скачать и установить программу www.kornjakov.ru/minimax.exe, которая демонстрирует возможности использования Word.Application.

Василий КОРНЯКОВ,
www.kornjakov.ru,
_kvn@mail.ru

Литература: Н. Елманова, С. Трепалин, А. Тенцер "Delphi 6 и технология COM" "Питер" 2002.

К списку статей