Статьи
Суперфункции (№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)
Труд программиста оценивается только пользователями и почти всегда по конечному результату. Используя материалы первой и второй частей статьи "Суперфункции", мы уже имеем возможность предоставить пользователю свою программу формирования простого документа в редакторе 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), а здесь, с целью экономии объема, представлен только фрагмент документа (см.рис.).

Общий алгоритм формирования документа таков:
- Открываем шаблон, используя функцию открытия ранее созданного документа.
- Ищем слова-переменные и подставляем вместо них реальные значения, например, из базы данных.
- Сохраняем документ под новым именем.
- Печатаем документ, если это необходимо.
- Закрываем документ.
Документ готов, и с ним можно работать как обычно, копировать, переименовывать и др.
Описанный выше алгоритм реализуем в виде небольшой программы. Для этого создаем новый проект и переписываем все функции (также и ранее созданные в первой части статьи) в модуль формы. Создаем на форме кнопку и в процедуру обработки ее нажатия пишем следующий программный код.
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)
Темой этой части статьи будет создание таблиц в редакторе 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)
Многие популярные информационно-правовые системы содержат шаблоны различных документов в формате 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)
Используя доступ к 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.
Многие программисты и пользователи очень часто предпочитают вместо 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, необходимо и достаточно научиться записывать информацию в ячейки таблицы. Шаблоны многих документов уже разработаны и представлены в разнообразных справочных системах, и целесообразно научиться использовать их в своих приложениях.
Лист книги 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. Выбор шрифта, его цвета и стиля, параметров границы и фона ячеек позволит задействовать дополнительные возможности для создания информативно наполненного документа.
Выбор шрифта
Для задания шрифта ячеек электронной таблицы используем свойства и поля объекта 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.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 есть возможность программировать отображение информации в виде диаграмм и графиков, и вы можете воспользоваться этим, чтобы сделать свою программу более информативной и конкурентно-способной.
Для создания и работы с диаграммами в 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. В прошлый раз мы рассмотрели создание, настройку внешнего вида областей, области построения, заголовка и формирование области данных диаграммы. Важными свойствами диаграммы являются ее тип, размещение, параметры легенды и параметры той части, которая несет информационную составляющую. Программирование всего этого и рассмотрим в данной части статьи.
Тип диаграммы
Тип диаграммы определяет, каким образом отображается информация: в виде плоских или объемных фигур или графиков, а также сам вид этих фигур. Существует около 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.
Если вы хотите и готовы предложить своим коллегам свои собственные 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) и использовать динамическую библиотеку в макросах книги 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 - индекс цвета.
Как изменить положение таблицы на листе (подвинуть влево, вправо, вверх, вниз)?
Координаты таблицы можно изменить, но эти изменения ограничены по своим возможностям:
- две таблицы нельзя выстроить на странице в одну линию, их можно разместить как строки: вторая таблица идет на следующей строке после первой;
- есть возможность менять только левый отступ таблицы от края листа. Вертикальное положение определяется строкой, на которой создается таблица. Поэтому чтобы изменить вертикальное положение таблицы, необходимо добавить или удалить строки, расположенные выше таблицы. Левый отступ определяется значением, записанным в поле 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.

