Пятница, 17.05.2024
Королевство Delphi
Главное меню
Статьи
Наш опрос
Как часто ви на этот сайт заходите?
Всего ответов: 159
Статистика
Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа
Главная » Статьи » Разные » Примеры Delphi

Документация на основе RTF-шаблона

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

До последнего времени самым простым и широко применяемым решением представлялось применение механизма ole. Например, для комбинации word и visualbasic возможна такая схема:

  • Создаем некий файл - шаблон документа. Там, где должна быть "шапка" (дата, номер документа и др.), используем закладки, а для основной части отчета создаем таблицу-заготовку соответствующей структуры. Пример такого шаблона приведен на рис. 1.
  • Пишем программу с использованием объектной модели word:
// numstr - кол-во строк в отчете
// newdata (5,numstr) - массив с данными для заполнения таблицы,
// заранее приведенными к символьному виду
// itog - сумма, приведенная к символьному виду
// pth - путь к исходному файлу
// str_ndoc = "bs190"
// str_name = "Петров И.И."
//.................

dim objword as word.application
dim objdoc as word.document
dim objtable as word.table

// создаем объект word
set objword = new word.application
// делаем его видимым - это не обязательно, но очень интересно :)
objword.visible = true

// открываем файл шаблона
set objdoc = objword.documents.open (pth)
// делаем его активным
objdoc.activate

// заполняем "шапку документа" - номер и получатель
// - закладки 'ndoc' и 'name' соответственно
objdoc.bookmarks ("ndoc").range.text = str_ndoc
objdoc.bookmarks ("name").range.text = str_name

// связывам объект с таблицей
set objtable = objword.activedocument.tables (1)

// выделяем 2-ю строку таблицы в шаблоне
objtable.cell (2, 1).range.select

// вставляем нужное кол-во строк-1 (т.к. одна уже есть в шаблоне)
if numstr > 0 then objword.selection.insertrows (numstr - 1)

// для каждой строки в каждую ячейку вставляем нужные данные из массива
for i = 1 to numstr
for j = 1 to 5
objtable.cell (i + 1, j).range.text = newdata (j, i)
next j
next i

// проставляем сумму "Всего"
objtable.cell (numstr + 2, 5).range.text = itog
  • Запускаем ее в составе всего приложения и получаем результат (см. рис. 2).
  • Пользователь, получив отчет в виде doc-файла, может легко внести в документ любые изменения, отправить его по электронной почте, распечатать - одним словом, распорядиться по своему усмотрению в привычной ему среде. Так же легко он может изменить и шаблон документа - для этого достаточно уметь работать в текстовом редакторе.

Но эту идиллическую картину омрачает несколько неприятных моментов. Во-первых, недостаточная гибкость приложения - если вы захотите перейти на другой редактор, то придется писать код заново. Во-вторых, приложение работает только в среде пакета ms office, а он стоит немалых денег. Если приложение должно работать на 30-ти компьютерах предприятия, то установка на них ms office обойдется примерно в 40 тыс. гривен - не каждый бюджет выдержит.

В то же время существует целый ряд достаточно полнофункциональных и бесплатных офисных пакетов: openoffice, staroffice, easyoffice и др. Для большинства операций, выполняемых обычно с документами, их возможностей вполне достаточно. Но возможна ли их простая и эффективная интеграция в прикладное программное обеспечение?

Решением этой проблемы может быть использование rtf-файлов. Этот формат, предложенный microsoft как стандарт для обмена данными между текстовыми редакторами, поддерживается абсолютным большинством офисных пакетов. Сама microsoft использует его в качестве формата, в котором данные передаются через буфер обмена между различными приложениями windows.

Кратко об rtf

В формате rtf используются только коды, представляемые символами из наборов ascii, mac и pc. Помимо текста, rtf-файл содержит команды управления в читаемой форме. Документ состоит преимущественно из команд управления настройкой программы чтения. Эти команды можно разделить на управляющие слова и управляющие символы.

Управляющее слово представляет собой последовательность символов с разделителем в конце. Например, фрагмент:

 …bkmkstart ndoc…
 
соответствует началу закладки ndoc.

Перед управляющим словом вводится обратная косая черта (). В качестве разделителей могут использоваться следующие символы:

  • пробел, причем этот символ относится к управляющему слову;
  • цифра или дефис (<->). После этих символов должен следовать параметр с разделителем. В качестве разделителя может быть использован пробел или другие символы (кроме цифр и букв);
  • все символы, кроме цифр и букв. Эти символы не относятся к управляющему слову.

Для задания управляющей последовательности в rtf-формате используются буквы от А до z и от а до z, а также цифры от 0 до 9. Национальные символы к управляющей информации не относятся.

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

…f1fs20…

устанавливает шрифт № 1 размером в 20 единиц.

Фрагмент rtf-файла приведен ниже. Структура его, как можно видеть, напоминает структуру html-документа:

intblphmrgposy371dxfrtext180dfrmtxtx180dfrmtxty0nowrapaspalphaaspnum
faautoadjustrightrin0lin0f1fs20lang1049langfe1049cgridlangnp1049langfenp1049
{lang1033langfe1049langnp1033 11cell 12cell 13cell} pard ql li0ri0widctlpar
intbl aspalphaaspnumfaautoadjustrightrin0lin0

В rtf-формате существует возможность объединять отдельные последовательности в группы при помощи скобок:

 {группа}

Такие группы создаются, например, при описании сносок, колонтитулов, закладок и т.п.

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

  • раr - конец абзаца;
  • сеll - конец столбца;
  • row - конец строки (или таблицы);
  • *bkmkstart <название закладки> *bkmkend - закладка. Пример: {*bkmkstart ndoc} bs190{*bkmkend ndoc};
  • pard - устанавливает стандартную настройку для абзаца;
  • intbl … intbl - выделяет область таблицы;
  • ' - прямой ввод в текст шестнадцатеричных чисел. При сохранении кириллического текста он обычно сохраняется в шестнадцатеричной форме, например:

'd1'f2'f0'ee'ea'e0 ('строка')

Поскольку нас интересуют только определенные задачи, знания приведенных выше управляющих слов и символов вполне достаточно. Условимся для простоты называть управляющие слова и символы тегами.

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

Вставка строки на месте закладки

Пример такой закладки:

 …{*bkmkstart ndoc}<значение закладки>{*bkmkend ndoc}…

Для решения данной задачи можно предложить следующий алгоритм.

  • Читаем последовательно строки входного файла (в большинстве случаев строка больше 255 символов).
  • Ищем в текущей строке тег 'bkmkstart'.
  • Если находим, то выделяем название закладки и сравниваем его с искомой.
  • Если совпадает, то записываем строковую строку данных после закрывающей скобки (}).

Алгоритм реализован в виде функции in_zakl1(pth as string, zakl as string, data as string), где pth - имя rtf-файла, zakl - имя закладки, data - строка для добавления в файл.

Добавление строк в таблицу

Предположим, нам требуется найти m-ю строку в n-той таблице и повторить ее в этой таблице p раз. Для поиска начала строки таблицы мы будем использовать тег intbl, а для поиска конца - тег row. Конец самой таблицы определяется по последовательности тегов row…pard…par.

Алгоритм решения этой задачи следующий.

  • Читаем последовательно строки входного файла.
  • Ищем последовательность …row…pard…par…intbl… (не обязательно в одной строке) (n-1) раз. После этого мы находимся в начале нужной таблицы.
  • Ищем тег row (m-1) раз. После этого находимся перед нужной строкой таблицы.
  • Ищем следующий тег row и копируем содержимое файла от (m-1)-го до m-го тега row (между row и intbl содержатся настройки строки, они нам тоже нужны).
  • Вставляем после m-го тега row скопированную нами подстроку p раз.

Следует отметить, что недостатком предложенного алгоритма является то, что он может копировать любую строку таблицы, кроме первой. Но в большинстве случаев первая строка является "шапкой" документа и копировать ее нет необходимости.

Алгоритм реализован в виде функции in_tstr (pth as string, itbl as integer, irow as integer, kol as integer), где pth - имя rtf-файла, itbl - номер таблицы, irow - номер строки, kol - количество повторов строки.

Заполнение ячейки таблицы

 Представим, что требуется найти k-ю ячейку в m-й4 строке n-й таблицы и вставить в нее текстовую строку данных. Пример таких ячеек:

 ...{lang1033cgrid0<содержимое 1-й ячейки>cell<содержимое 2-й ячейки>cell}…

Задача может быть решена по следующему алгоритму.

  • Читаем последовательно строки входного файла.
  • Ищем последовательность …row…pard…par…intbl… (не обязательно в одной строке) (n-1) раз. После этого мы находимся перед нужной нам таблицей.
  • Ищем тег row (m-1) раз. После этого мы находимся в начале нужной строки таблицы.
  • Ищем k-e вхождение тега cell.
  • Вставляем перед ним строку данных.

Данный алгоритм реализован в виде функции in_tcell1(pth as string, itbl as integer, irow as integer, icell as integer, ndata as string), где pth - имя rtf-файла, itbl - номер таблицы, irow - номер строки, icell - номер ячейки, data - строка для занесения в ячейку.

Программа на visualbasic, демонстрирующая применение такой технологии и функционально идентичная программе, приведенной в начале этой статьи, выглядит так:

// numstr - кол-во строк в отчете
// newdata (5,numstr) - массив с данными для заполнения таблицы,
// заранее приведенными к символьному виду
// itog - сумма, приведенная к символьному виду
// pth - путь к файлу
// str_ndoc = "bs190"
// str_name = "Петров И.И."

dim res as boolean ' результат выполнения функций

// заполняем "шапку документа" - номер и получатель
// - закладки 'ndoc' и 'name' соответственно

res = in_zakl1(pth, "ndoc", str_ndoc)
res = in_zakl1(pth, "name", str_name)

// вставляем нужное кол-во строк-1 (т.к. одна уже есть в шаблоне)
res = in_tstr (pth, 1, 2, numstr - 1)

// для каждой строки в каждую ячейку вставляем нужные данные из массива

for i = 1 to numstr
for j = 1 to 5
res = in_tcell1(pth, 1, i + 1, j, newdata (j, i))
next j
next i

res = in_tcell1(pth, 1, numstr + 2, 5, itog) ' проставляем сумму "Всего"

Заключение

Каковы преимущества и недостатки предложенной технологии? Начнем с достоинств. Во-первых, это более гибкая технология для формирования отчетов - даже если часть пользователей работает с openoffice, а часть с ms office, программа создания отчетных документов универсальна. Во-вторых, несмотря на многоразовую перезапись файла шаблона во время работы, эта программа работает быстрее, чем связка ole+word. Тем более что приведенные выше алгоритмы могут совершенствоваться. Один из примеров кардинального повышения производительности приведен в листингах варианта для pascaldelphi. В-третьих, пользуясь свободным ПО, вы экономите деньги.

Теперь о проблемах. Основная из них - это недостаточная стандартизация формата rtf. Производители ПО, в целом придерживаясь единого стандарта, допускают несколько свободную трактовку частных моментов. Результат - проблемы с использованием "чужих" rtf-файлов, подготовленных в других редакторах. Например, ms word сохраняет графические изображения внутри rtf-файла в виде последовательности шестнадцатеричных кодов, а oowriter - как внешний файл.

Впрочем, эти проблемы решаются - стоит только приложить некоторые усилия.

Полные листинги подпрограмм, реализующих описанные алгоритмы на visualbasic, pascaldelphi и visualfoxpro, находятся на КП-диске.

Автор: Александр Харьков

Получить ссылку на материал

Категория: Примеры Delphi | Добавил: Барон (12.12.2011)
Просмотров: 1939 | Теги: Шаблон, RTF | Рейтинг: 0.0/0
[ Пожертвования для сайта ] [ Пожаловаться на материал ]

Если вам помог материал сайта кликните по оплаченной рекламе размещенной в центре

Поиск
Категории раздела
Delphi.NET [3]
Kylix Delphi for Linux [9]
Советы Дельферу [6]
Хитрости в Delphi [2]
Обзор Delphi [45]
Инсталлятор [11]
Пользовательский интерфейс [18]
Примеры Delphi [93]
Функции и процедуры [15]
Разные [31]
Королевство Delphi © 2010-2024
Яндекс цитирования