скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

Работа с MsWord из Delphi - Нестандартные отчёты



Автор: Шлеенкин Александр

Содержание:

Введение

Данная статья написана на базе реальной программы "Автоматизация производства" — автоматической генерации сопровождающей документации при разработке печатных плат на программных продуктах "P-CAD 2000/2001".
  • Перечень элементов
  • Спецификация
  • Ведомость комплектации

На каждом предприятии, будь то малый бизнес и огромный завод, немалую роль играет составление документации и отчётов. Почти всегда этим занимается специально выделенный человек. Так заведено уже давно, но теперь всё чаще появляются инициативные руководители, стремящиеся свести эти горы однотипной рутинной работы с человека на машину. Для этого и используют программы автоматизации производства. Эти программы автоматически генерируют требуемую документацию. Зачастую это сводится к работе с базами данных и библиотеками. Есть много программ делающих это. Но типов таковой документации столь много, что современные программные монстры, такие как пользовательская программа (MS ACCESS) или программируемый монстр (ORACLE) не в состоянии обеспечить даже половины нужд. Ведь у каждого предприятия своя с годами сложившаяся традиция заполнения документации или свой "Норма контроль" с заданными обязательными параметрами. Универсальной программы такого сорта нет и быть не может. Поскольку специфика работы предприятия может быть как гибкой в области документации (коммерческий ларёк), так и строго установленной на мировом уровне (банк или производственная сфера). Для решения этих проблем используют нестандартные отчёты. Отчёты сделанные специально под требования, наложенные на их оформления. Вы только представьте, ту работу, которую сотрудник выполнял несколько месяцев, программа сделает за пару минут!!! И это вполне реально. Данная статья представляет собой набор советов и примеров, которые помогут разработчику разобраться в столь оставленной без внимания теме, как автоматизация производства. Поскольку документации по этой теме практически нет, то данная статья поможет резко уменьшить время разработки таких программ с месяцев до недель. Но хотя по предлагаемой информации уже были созданы описанные выше программы, этой информации может всё равно оказаться недостаточно. В конце статьи вы найдёте координаты связи для пополнения содержательной части статьи и вопросов. Иллюстрирующие примеры мы приводим на языке Delphi 32 (версии 5 и выше). Выбор был остановлен на Делфи в виду её простоты и наглядности, но все идеи и реализации, изложенные в статье, легко переносятся на любой другой обьектно ориентированный язык программирования высокого уровня.

Нестандартные отчёты - кто и зачем этим занимается

На вопрос "зачем" мы, думаю, дали уже достаточно аргументации. Но всё-таки это не всё, остановимся на ещё неописанных проблемах.

Первый вопрос, который нам обычно задают - это где я смогу это использовать кроме как на предприятии, сфера применимости данной тематики довольно широка, рассмотрим некоторые вопросы и варианты их решения по средствам работы с Ворд и созданием отчётов:

  1. Удобство интерфейса. Вы можете предоставлять пользователю информацию прямо через WORD, где он сможет либо распечатать её, либо внести необходимые корректировки или сохранить себе копию. Согласитесь, чтобы реализовать это как-либо иначе уйдёт слишком много времени, а интерфейс WORD интуитивен, знаком и понятен, так что ряд проблем просто отпадает.
  2. Вы можете пользоваться любыми средствами, какими располагает Ворд. В том числе проигрывать видео и аудио записи, выдавать изображения, кроме того, становятся доступны любые возможности конвертации файлов (Например, можно не используя тегов через Ворд создать документ HTML)
  3. Реальностью становится программа, анализирующая документы формата WORD на диске и создание библиотеки вида название документа = имя файла, причём всю информацию можно напрямую собирать из WORD документов.
  4. Можно реализовывать локальные операции, допустим, все файлы WORD перевести в DOSовские TXT файлы. И многое, многое другое.

А на счёт кто же этим занимается? Эта информация может быть полезна руководителям. Любой WINDOWS программист с высшим или средне специальным образованием, знакомый с ЯВУ и ООП. Такого вида программистов часто называют прикладными. Срок изготовления в среднем 2-3 месяца с учётом бета тестирования.

Основы работы с OLE

На программном уровне работа с WORD заключается в использовании OLE. Основная структура взаимодействия такова: Существует программа СЕРВЕР, которая считается главной и именно она выполняет все операции, в нашем случае сервером является программа WORD. Из этих слов уже ясно, что если WORD не установлен на компьютере, то есть сервер отсутствует, то ничего выполнено быть не может. Просто некому будет выполнять. Это, по сути, наиболее распространенный вопрос среди программистов среднего класса. Вторая взаимодействующая программа - это программа КЛИЕНТ, все, что она делает - это связывается с сервером и просит его выполнить необходимые операции, сама по себе она ничего не может. В результате такого взаимодействия и решается поставленная задача. Теперь рассмотрим реализацию:

procedure Word.Run;
var
  verr, verr1: string;
  i, verrI: integer;
const
  DigiChar = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
begin
  try
    MsWord := CreateOleObject('Word.Application');
    MsWord.Visible := False;
  except
    error(1, 'Microsoft Word не установлен');
  end;
  verr := Trim(Version);
  verr1 := '';
  for i := 1 to Length(verr) do
    if not (verr[i] in DigiChar) then
      break
    else
      verr1 := verr1 + verr[i];
  verrI := StrToInt(verr1);
  if verrI<
  9 then
    error(1, 'Требуется WORD 2000/XP или выше');
end;

Эта процедура связывает переменную MsWord с Ole, в результате чего подгружается сам WORD, далее мы делаем его пока невидимым и проверяем версию, пояснения процедуры проверки версии будут позже.

type
  Word = class
  public
    function Version: string; //shadow
    procedure Error(i: integer; str: string); //intro
    MsWord: Variant; // Main
  end;

Главный класс, в котором описаны основные переменные и процедуры необходимые для корректной работы с WORD.

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

Ошибки при вызове WORD

Для начала опишем процедуру загрузки в WORD DOC файла, делается это так:
procedure Word.Open(fileName: string);
begin
  try
    MsWord.Documents.Add(fileName, EmptyParam);
  except
    Error(2, 'файл не найден');
  end;
end;
Можно к уже открытому добавить ещё один, так чтобы в итоге из двух получить один.
procedure Word.Open_Next(fileName: string);
begin
  try
    MsWord.Selection.InsertFile(FileName := filename, ConfirmConversions :=
      false, Link := false);
  except
    Error(2, 'файл не найден');
  end;
end;
A вот и процедура, которая наиболее часто используется в приложениях такого типа!
procedure Word.Error(i: integer; str: string);
begin
  case i of
    1:
      begin
        showmessage(str);
        showmessage('Продолжение работы невозможно');
        Application.Terminate;
      end;
    2:
      begin
        showmessage(str);
        showmessage('Продолжение работы невозможно');
        Application.Terminate;
      end;
  end;
  showmessage(str);
  Exit;
end;
А теперь рассмотрим проблемы, которые встречаются при работе с WORD, о которых говорилось ранее.
  1. Если установить Ворд и попытаться сразу связаться с ним через Ole, то ничего не получится, дело в том, что при первом запуске WORD программа предлагает напечатать тестовую страницу, при этом, никак не сообщив об этом Ole клиенту. Из-за чего в работе вашей программы может происходить сбой. И исправлению эта ошибка не подлежит, данная неприятность - дело рук компании MICROSOFT создавшей WORD и пока она эту проблему решать не собирается, как видно из WORD XP.
  2. Ещё может быть ситуация, когда открываемый WORD файл уже занят другим приложением, или копией вашего, тогда ворд предлагает использовать режим только для чтения, а по освобождению ресурса предлагает переход в возможность редактирования. Это тоже влияет на работу клиентской программы, поскольку требует от пользователя согласия на изменение режимов.
  3. Файл, который вы открываете, просто не существует. Эту проблему вам придётся решать средствами языка разработки. WORD подобные сервисы не предоставляет.
  4. На используемой машине не хватает памяти. Ответ на этот вопрос смотрите в пункте 3.

Создание отчётов в WORD (различные подходы)

Существует несколько подходов создания нестандартных отчётов в WORD, используя OLE технологии, рассмотрим их по порядку:
  1. Это стандартный подход. Клиент делает запрос, сервер выполняет, клиент делает следующий запрос и так далее, пока задача не будет решена.
  2. Можно использовать встроенный в WORD язык VBA, написать необходимые макросы на Visual Basic Script и внедрить их в текущий документ, тогда останется только вызывать их и всё. За счёт этого можно реально выиграть во времени, но волею случая этот метод в основном используется в компьютерных вирусах, за счёт чего относится к вирусным технологиям и из-за этого некоторые антивирусы могут определять вашу программу как инфицированную WORD вирусом. Поэтому данный метод так и не получил распространения среди Ole программ.
  3. Третий метод - самый важный, а заключается он в сочетании первых двух, таким образом, демонстрируя взаимное дополнение подходов.

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

procedure Word.search(data: string);
var
  What, Which, Count, Name: OLEVariant;
begin
  What := -1;
  Which := unAssigned;
  Count := unAssigned;
  Name := data;
  MsWord.Selection.goto(What, Which, Count, Name);
end;
Теперь закладку мы нашли запишем в то место что-нибудь
procedure Word.insert(info: string; _bold, _italic, _StrikeThrough, _Underline:
  boolean; _Size: integer; _center: boolean);
begin
  MsWord.Selection.Font.Bold := _bold;
  MsWord.Selection.Font.italic := _italic;
  MsWord.Selection.Font.StrikeThrough := _StrikeThrough;
  MsWord.Selection.Font.Underline := _Underline;
  MsWord.Selection.Font.Size := _Size;
  if _center = true then
    MsWord.Selection.ParagraphFormat.Alignment := 1;
  MsWord.selection.TypeText(info);
end;

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

Теперь напишем процедуру перехода к следующей ячейке таблицы, считаем, что на первую мы перешли по закладке!
procedure Word.NextCell;
begin
  MsWord.Run('NextCell');
end;

Таким же образом запускаются макросы WORD, только вместо NextCell надо вставить имя макроса который хотим запустить. Важно не забывать, что через Ole можно вызывать только "свободные макросы" то есть без параметров!!! (VIRUS TECHNOLOGIES NOT FOR GAME)

А вот ещё процедура. Она позволяет пропускать нужное число ячеек таблицы с учётом, что позиционирования на закладке ещё возможно не было.

procedure Word.SkipCell(n: integer);
var
  i: integer;
begin
  if n<
  1 then
    Exit;
  if not NewList then
  begin
    for i := 1 to n do
      MsWord.Run('NextCell');
  end
  else if n>
  1 then
  begin
    search('a1');
    for i := 1 to n - 1 do
      MsWord.Run('NextCell')
  end
else
  begin
    search('a1');
  end;
end;
  • NewList - переменная булевского типа, отвечающая за начало нового листа и новой таблицы на нём.
  • a1 - закладка на первую ячейку таблицы.
Есть ещё команда по работе с закладками. Это удаление.
MsWord.ActiveDocument.Bookmarks.Item(1).Delete;

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

Полезная процедура для всех типов подходов к ole программированию. Она пересчитывает сантиметры в пиксели.
function Word.CentimetersToPoints(a: Single): Single;
begin

  {Converts a measurement from centimeters to points (1 cm = 28.35 points).
  Returns the converted measurement as a Single.
  Syntax
  expression.CentimetersToPoints(Centimeters)
  expression Optional. An expression that returns an Application object.
  Centimeters Required Single. The centimeter value to be converted to points.}

  Result := 28.35 * a;

end;

Предварительная настройка страницы WORD

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

procedure Word.Normalize;
begin
  //MsWord.ActiveDocument.PageSetup.LineNumbering.Active := False;
  //MsWord.ActiveDocument.PageSetup.Orientation :=0;// wdOrientPortrait;
  MsWord.ActiveDocument.PageSetup.TopMargin := CentimetersToPoints(0.75);
  MsWord.ActiveDocument.PageSetup.BottomMargin := CentimetersToPoints(0.2);
  MsWord.ActiveDocument.PageSetup.LeftMargin := CentimetersToPoints(0.5);
  MsWord.ActiveDocument.PageSetup.RightMargin := CentimetersToPoints(0.5);
  MsWord.ActiveDocument.PageSetup.Gutter := CentimetersToPoints(0);
  MsWord.ActiveDocument.PageSetup.HeaderDistance := CentimetersToPoints(1.27);
  MsWord.ActiveDocument.PageSetup.FooterDistance := CentimetersToPoints(1.27);
  //MsWord.ActiveDocument.PageSetup.PageWidth := CentimetersToPoints(21);
  //MsWord.ActiveDocument.PageSetup.PageHeight := CentimetersToPoints(29.7);
  //MsWord.ActiveDocument.PageSetup.FirstPageTray :=0;// wdPrinterDefaultBin;
  //MsWord.ActiveDocument.PageSetup.OtherPagesTray :=0;// wdPrinterDefaultBin;
  //MsWord.ActiveDocument.PageSetup.SectionStart :=2;// wdSectionNewPage;
  //MsWord.ActiveDocument.PageSetup.OddAndEvenPagesHeaderFooter := False;
  //MsWord.ActiveDocument.PageSetup.DifferentFirstPageHeaderFooter := False;
  //MsWord.ActiveDocument.PageSetup.VerticalAlignment :=0;// wdAlignVerticalTop;
  //MsWord.ActiveDocument.PageSetup.SuppressEndnotes := False;
  //MsWord.ActiveDocument.PageSetup.MirrorMargins := False;
  //MsWord.ActiveDocument.PageSetup.TwoPagesOnOne := False;
  //MsWord.ActiveDocument.PageSetup.GutterPos :=0;// wdGutterPosLeft;
end;

Как вы видите, ряд настроек закомментирован, и это не случайность. Поскольку кождое обращение к серверу занимает время, то слишком объемное конфигурирование системы может привести к тому, что пользователь подумает, что программа, должно быть, зависла и перезагрузится, не дав выполнить всё конфигурирование целиком. Поэтому я советую ввести эту возможность как полезную утилиту программы, типа: Full Correction

Полезные утилиты

Вообще-то всего описанного выше вполне достаточно для работы, но есть такое понятие, как "подвязать бантики и шнурочки" и именно это мы и сделаем...

Получить версию WORD:
function Word.Version: string;
var
  verr: string;
begin
  verr := MsWord.Version;
  Result := verr;
end;
Закрыть WORD:
procedure Word.Quit;
begin
  MsWord.Quit;
end;
Закрыть документ WORD:
procedure Word.Close;
begin
  MsWord.Documents.Close;
end;
Сохранить активный документ:
procedure Word.Save(Name: string);
begin
  MsWord.ActiveDocument.SaveAs(FileName := Name);
end;
Отправка активного документа на печать:
procedure Word.Print;
begin
  MsWord.ActiveDocument.Print;
end;
Разрыв страницы - переход к новой странице. Реализуется так:
MsWord.Selection.InsertBreak;

Напоследок

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






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook