уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

pinguin LinuxКак я уже отмечал в блоге, есть планы прейти на программирование в Lazarus. Учитывая, что уже сейчас решается вопрос о том, чтобы перевести все машины на работе под управление Linux с нового года, можно начинать чесать репу и думать каким макаром перегнать большой программный комплекс для экологов поту же Ubuntu. Самая острая проблема — документы. Как ни крути, а отчёт созданный в том же Excel или Word, выглядит намного более привлекательно, чем простой текстовик. Посмотрим, что можно предпринять в случае работы под Linux не потерять презентабельность документов.

В принципе вариантов не так уж и много.

Первый вариант — генерировать простой html-файл. Достоинство этого подхода очевидно — простота при разработке программ. Если учесть, что Lazarus вполне хорошо справляется с DOM, то есть возможность не только выдавать документ на печать, но и, в случае необходимости, проводить его анализ.

Недостаток подобного подхода — достаточно трудно сформировать удобочитаемый документ, если в нем встречается большое количество формул, диаграмм и т.д.

Второй вариант — использовать возможности OpenOffice. На данный момент этот вариант мне больше всего нравится. Что сразу бросилось в глаза при изучении документации по OO — это то, что в документе математические формулы хранятся точно также как и простой текст. То есть сразу появляется куча возможностей по формированию сложных по составу и содержанию отчётов и документов.

Помниться, когда только начинал разрабатывать первую версию программы, не мог понять как работать из Delphi с MathType (надстройка в office для рисования формул). В итоге, так и не поняв как это делается писал все формулы в строку простым текстом — корявенько и топорно, но читаемо. С OpenOffice + Lazarus все по другому — можно расписывать хоть 10-ти этажные дроби.

Дополнительным стимулом к использованию форматов OpenOffice послужило также то, что в этом случае можно создать 100% кросплатформенный проект и уже не заморачиваться над тем, какую ОС задумают поставить админы на машинах в следующем году — OpenOffice без проблем работает везде.

Посмотрим, что из себя в принципе представляет документ OpenOffice, например, возьмем файл Writer’а *.odt (аналог Word).

1. Формат Open Document

Собственно, для тех, кто имеет хотя бы общие представления об устройстве XML-файла, не составит особого труда разобраться и с форматом Open Document.

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

Более того, само содержание и расположение файлов в архиве чертовски напоминает мне сайты на narod.ru :). Вот, например, содержимое файа *.odt в котором содержится всего одна строка по центру страницы — «hello world»

odt файл

Тут, наверное, разберется даже ребенок, что основное содержимое документа располагается в файле content.xml. Посмотрим, как выглядит наша строка Hello world». Открываем файл в браузере и видим:

xml odt

Всё те же знакомые узлы XML и не менее знакомые атрибуты типа center и пр.
Получается следующее. Если необходимо создавать документы по какому-либо шаблону (что мне наиболее часто и приходится делать), то достаточно накидать шаблон документа и распакавать его в какую-либо папку, затем уже в своей программе открыть нужный xml-файл, изменить и запокавать обратно в zip-архив, но с расширением файла Open Document. И никаких тебе OLE и т.д. и т.п. Организуется всё элементарно и без каких-либо сторонних компонентов.
Если же Вам требуется разрабатывать документы какого-нибудь уникального содержания, то тут Вам, как ни крути, придётся с головой окунуться в документацию по Open Document Format.

Итак, первый шаг к разработке кроссплатформенного проекта сделан — определились с форматами документов и в общих чертах представляем себе алгоритм работы.
Остается решить вопрос с тем, как паковать документ? Использоать dll, какой-либо компонент или обойтись тем, что есть в Lazarus?

2. Работа с архивами в Lazarus

Лично я сторонник того подхода к разработке любых программ, при котором по возможности не используются какие-либо сторонние компоненты — только «родные» компоненты и модули.
Это обстоятельство избавляет как минимум от одного геморроя — не надо за собой везде тягать тучу сторонних компонентов, чтобы проект без проблем открывался на любом компьютере.
Так и в случае работы с архивами в Lazarus — никто нам не запрещает воспользоваться компонентами, например с этой страницы Wiki Lazarus. Но зачем накручивать лишние компоненты, когда для работы с zip-архивами в составе Lazarus есть вполне понятная и простая в использовании утилита ZIP?
Воспользуемся ей, а заодно посмотрим, как можно обойтись в работе со сторонними приложениями без всяких ShellExecute, ShellAPI и пр.

Итак, пишем свой первый кроссплатформенный архиватор, который потом будем использовать для сборки документов OpenOffice.
Открываем Lazarus, создаем новые проект и, для наглядности работы программы, укладываем на форму две кнопки и Memo.
Самый простой вариант работы с утилитами наподобие zip и unzip — это использовать в Win32 пакетные файлы DOS (*.bat), а в Linuх — bash-скрипты. Смысл работы прост как три копейки:
1. В зависимости от того в какой ОС запущена программа, создаем либо файл скрипта с расширением sh, либо bat-файл
2. Выполняем скрипт, который пакует необходимые файлы в документ.

Разрабатываем скрипт.

Думаю, что тем, кто знаком с Linux, написать скрипт для упаковки папки в архив потребуется на всё пара минут, а то и меньше. Текст скрипта выглядит следующим образом:

#!/bin/bash
cd /путь/до/папки/с_файлами
zip -r Документ.расширение *

Обращу Ваше внимание, что переход в папку с докуменами необходим, т.к. если просто указать утилите zip расположение файлов, то в итоге в архив будет записан весь путь до файлов и документ просто не распознается как Open Document.
В случае с bat-файлов всё также просто и понятно:

CD Полныйпутьдопапки
Полныйпутьк_утилитеzip -r Document.расширение Полныйпутьдопапки

Оба файла работают абсолютно идентично — пакуют всю папку, содержащую xml-файлы документа в один архив.
Со вспомогательной частью покончено. Переходим в Lazarus.

Первое, что необходимо — это написать обработчик одной из кнопок для создания необходимого нам файла в зависимости от ОСи. У меня получился следующий код:

procedure TForm1.Button2Click(Sender: TObject);
var F: TextFile;
begin
  AssignFile(F, ExtractFilePath(Application.ExeName)+'mybash.sh');
  Rewrite(F);
  {$IFDEF LINUX}
  WriteLn(F, '#!/bin/bash');
  WriteLn(F, 'cd '+ExtractFilePath(Application.ExeName)+'document');
  WriteLn(F, 'zip -r doc.odt *');
  CloseFile(F);
Memo1.Lines.LoadFromFile(ExtractFilePath(Application.ExeName)+'mybash.sh');
  {$ENDIF}
  {$IFDEF WIN32}
    WriteLn(F, 'CD '+ExtractFilePath(Application.ExeName)+'document');
    WriteLn(F, ExtractFilePath(Application.ExeName)+'zip -r doc.odt '+
      ExtractFilePath(Application.ExeName)+'document');
    CloseFile(F);
Memo1.Lines.LoadFromFile(ExtractFilePath(Application.ExeName)+'mybash.bat');
  {$ENDIF}
end;

Обратите внимание, что для того, чтобы узнать под какой ОС мы запустили программу, нам не требуется изгаляться и писать лишние процедуры и функции — достаточно использовать простенькие директивы «{$IFDEF}» и «{$ENDIF}».
В представленном обработчике в зависимости от операционной системы в которой запущено приложение создается свой файл для упаковки папки с xml-файлами документа и содержимое файла выводится в Memo.
Теперь посмотрим, как под Lazarus’ом можно запускать сторонние приложения.

Запуск скриптов и bat-файлов из своей программы.

Для того, чтобы запустить любую программу или выполнить скрипт в своем приложении и при этом не нарушить кроссплатформенность, в Lazarus предусмотрено использование класса TProcess или, кому удобнее использовать компоненты, сразу три невизуальных компонента TProcess* cо вкладки System:

компоненты process

Укладываем на форму самы простой из трех компонентов — TProcess и в обработчике второй кнопки пишем:

procedure TForm1.Button1Click(Sender: TObject);
begin
  {$IFDEF LINUX}
    Process1.CommandLine:='/bin/bash '+ExtractFilePath(Application.ExeName)+'mybash.sh';
  {$ENDIF}
  {$IFDEF WIN32}
    Process1.CommandLine:='cmd '+ExtractFilePath(Application.ExeName)+'mybash.bat';
  {$ENDIF}
  Process1.Options:=[poWaitOnExit];
  Process1.Execute;
end;

Здесь опять же, как мне кажется, особых сложностей нету — в зависимости от операционной сисемы запускаем на выполнение нужный файлик и ожидаем окончания выполнения. Аналогичным образом можно запускать абсолютно любые программы и приложения, отслеживать вывод консольных программ и т.д. и т.п. Чтобы лишний раз не повторяться и копипастить чужой текст — я просто скажу, что более подробно с работай компонента TProcess Вы всегда можете ознакомиться в Wiki Lazarus.
Вот теперь у нас в руках есть всё необходимое для работы с документами в любой операционной системе. Главное, не забудтся перенести утилиту zip.exe, входящую в сосав Lazarus к себе в проект.
Какие выводы можно сделать? Во-первых, работа с документами в Lazarus и OpenOffice, лично для меня оказалась намного проще, чем я ожидал. Всё, что требуется — разработать грамотный шаблон и потом немного поработать с XML. Во-вторых, использование утилиты zip избавляет нас от использования сторонних компонентов (не дай бог езё и платных). В-третьих, разработка кроссплатформенного приложения для работы с документами оказалась опять же не сложнее, чем под чисто под Win32 — достаточно не забывать про элементарные директивы компилятора. Так что, если Вас вдруг постинет та же проблема, что и меня — переход под другую ОС, то можете сильно не переживать — организовать документоооборот будет не сложнее, а даже в некотором смысле проще, чем для Win32 с использованием Microsoft Office.

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
5 1 голос
Рейтинг статьи
Подписаться
Уведомить о
13 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Игорь
Игорь
10/12/2009 09:46

Спасибо, в целом интересно, но немного не точен следующий момент. Ваша цитата:
===========
Обратите внимание, что для того, чтобы узнать под какой ОС мы запустили программу, нам не требуется изгаляться и писать лишние процедуры и функции – достаточно использовать простенькие директивы “{$IFDEF}” и “{$ENDIF}”.
===========

Насколько я понимаю, лучше написать «чтобы узнать под какой ОС мы КОМПИЛИРУЕМ программу». Иначе возникнет ощущение, что скомпилированная программа будет работать в обеих операционках

С. Дмитрий
С. Дмитрий
26/02/2010 12:53

Автору большое спасибо за статью! Очень интересная информация а главное полезная ! Интересно было узнать что  *.odt обычный zip архив. Да и Lazarus  с каждым выходом хорошеет

Al
Al
25/05/2010 12:10

docx тоже зип

AndyPanda
AndyPanda
18/09/2010 11:16

Если директория до скрипта содержит пробелы, то необходимо:
Process1.CommandLine:=’/bin/bash «/home/user/Lazarus projects/zumas backuper/zumas scripts/save»‘;
Как видно .sh к скрипту приписывать нет надобности.

Дмитрий
Дмитрий
22/09/2010 10:27

Автору огромная благодарность за проделанную работу и статью.
После изучения все стало просто и понятно, что и как устроено.

AndyPanda
AndyPanda
22/09/2010 20:50

Попробовал скрипт запустить в WIN32. Не пашет, потому как нужно вот так писать:
[code]
Process1.CommandLine := 'cmd /c "' + ExtractFilePath(Application.ExeName) + 'mybatORmycmd.cmd)' + '"';
[/code]
PS: Аффтар, пробуй код перед публикацией.

AndyPanda
AndyPanda
22/09/2010 20:53

прим: скобка лишняя ‘mybatORmycmd.cmd:)’

Konstantin
Konstantin
12/03/2011 21:07

Народ сделал как в примере ничего не понял, прошу не издеваться а более конкретно рассказать

123
123
03/04/2012 20:47

У меня не прокатывает ни: Process1.CommandLine := 'cmd /c "' +......., ни

Process1.CommandLine := 'cmd ".... ни

Process1.CommandLine := 'file.bat'
Lazarus пишет "ошибка 123" или что-то другое. Все, что начинается с CMD запускает пустое окно DOS.
Решил написать на паскале для ДОС программку, которая тупо запускает батник. Теперь из Lazarus запускается эта программка и

file.bat корректно обрабатывается

=))))))

trackback

[…] о том, что и где располагается в документе OpenOffice в этом посте. Теперь разберемся с содержимым документа […]

trackback

[…] необходимо при запуске в определенной ОС, то тут, как я уже упоминал, следует использовать директивы компилятора {$IFDEF …} […]