Он позволяет создавать "богатые" интернет приложения, без использования (и, соответственно, знания) (x)HTML, CSS и JS, используя исключительно средства Object Pascal, действующие по технологии Fast CGI. Так же, есть возможность для использования обычного CGI, а так же - встроенного (embedded) Веб сервера, основанного на базе библиотеки Indy. Я хочу рассмотреть возможность создания простейшего веб-приложения в среде Lazarus.
Для этого потребуется fpс, Lazarus (я использую SVN сборку), ExtJS v. 3.2.1, ExtPascal (тоже SVN) и Indy. Так же возможно потребуется скачать пакет Orpheus, для создания ExtJS таблиц в Design-time. Хотя, можно обойтись и без этого шага. Indy так же можно не ставить, но лично я настоятельно рекомендую, поскольку с ней можно обойтись без установки веб-сервера и настройки в нём FCGI, или сборке и настройке CGI-gateway для нашего приложения. Здесь я буду рассматривать именно вариант с Indy.
Не буду рассматривать установку FPC, Lazarus и Indy. Надеюсь, это не вызовет трудностей. Архив с ExtJS содержит папку "ext-3.2.1", которую потребуется переименовать в "ext" и поместить в корень с нашим будущим проектом. ExtPascal в своём текущем виде содержит следующие интересующие нас папки -
- Blaise - IDE, в начальной стадии;
- ExtJSWrapper - собственно, обёртка для фреймворка ExtJS;
- ExtP_Toolkit - набор пакетов для Lazarus/Delphi;
- ExtPascalSamples - рабочие примеры;
Создадим наше первое приложение на ExtPascal, для чего выберем ExtPascal Application. Первым делом, потребуется сохранить наше приложение. Назовём папку %folder%, проект - project1.lpr и форму - unit1.pas. После чего в ней окажутся следующие файлы -
- AppThread - файл потока, созданный ExtP_Toolkit. Собственно, то, ради чего и ставился весь пакет ExtP_Toolkit. Обновляется каждый раз при компиляции, если была добавлена новая форма, что создаёт некоторые неудобства. Так же потребуется привести функцию CurrentThread к виду:
- Код: Выделить всё
function CurrentThread : TAppThread;
begin
{$IFDEF WebServer}
Result := TAppThread(CurrentWebSession);
{$ELSE}
Result := TAppThread(CurrentFCGISession);
{$ENDIF}
end;
- project1.lpr - файл проекта. Здесь так же потребуется внести небольшую корректировку -
- Код: Выделить всё
{$IFNDEF WebServer}
Application := TFCGIApplication.Create('MyApp', TAppThread, Port, MaxIdleMinutes);
{$ELSE}
Application := TIdWebApplication.Create('MyApp, TAppThread, 80, MaxIdleMinutes);
{$ENDIF}
- unit1.pas, unit1.lfm,unit1.inc - файлы формы. Первый содержит собственно исходный код, второй использует средой, третий - хранит ExtPascal'евские свойства для формы. unit1.inc появится только при первой компиляции и будет обновляться при каждом изменении формы.
Для использования библиотеки Indy для создания веб-приложения со встроенным веб-сервером потребуется добавить флаг компиляции WebServer к проекту. Для этого нужно зайти в свойства проекта-> Свойства компиляции -> Другие и записать там -dWebServer -
Так же, если на машине уже занят 80 порт, то потребуется в файле project1.lpr заменить число 80 на другое, соответствующее свободному порту. Предположим, что у нас уже стоит другой веб-сервер и заменим порт 80 например на 81.
При первой же компиляции приложение должно ругнуться на отсутсвие некоторых модулей. Это произошло из-за той самой заброшенности ExtP_Toolkit'a. Решается простым добавлением ExtJSWrapper к пути -
Если всё шло правильно, и не забыли скопировать папку ext в %folder%, то на этом этапе приложение уже должно собираться. И зайдя в браузере на http://localhost:81/ вы должны увидеть примерно следующее:
Теперь попробуем его слегка изменить. Я не рекомендую пользоваться компонентами с вкладки ExtPascal. Дело в том, что ExtP_Toolkit не позволяет пользоваться большей частью свойств и методов классов ExtPascal. Для доступа к ним требуется указывать директиву -dUseRuntime. Но компоненты со вкладки ExtPascal, при этой директиве, ведут себя не вполне корректно. В частности, каждый раз при добавлении нового контрола на форму в список uses добавляется модуль, делающий невозможной сборку проекта. Убрать его не представляет никакой сложности, но все же раздражает. Плюс, возможности Lazarus в design-time не обеспечивают всех возможностей ExtJS по проектированию интерфейса. В общем, я рекомендую создавать интерфейс динамически. Но для нашего примера всё-таки воспользуемся теми вкладками.
Итак, бросим на форму кнопку(TExtButton) и "Мемо" (TExtFormTextArea) и присваиваем кнопке событие. На этом пользование ExtP_Tookit'ом завершается ^_^ В начале файла unit1.pas добавляем определение {$DEFINE UseRuntime}, заключаем описание класса формы в {$M+} и {$M-}, добавляем секцию Published и преносим туда созданное событие ExtButton1Click.
- Код: Выделить всё
{$M+}
Type
{ TExtWindow1 }
TExtWindow1 = Class(TExtWindow)
ExtButton1: TExtButton;
ExtFormTextArea1: TExtFormTextArea;
Private
Public
Constructor Create;
Procedure Show;
Published
Procedure ExtButton1Click;
End;
{$M-}
Теперь, доделаем то, что не сделал ExtP_Toolkit в нынешнем своём состоянии - обозначим включаемый файл unit1.inc и назначим кнопке ExtButton1 событие - в конструкторе Create добавим строчку -
- Код: Выделить всё
Constructor TExtWindow1.Create;
Begin
Inherited;
{$IFDEF UseRuntime}
{$I unit1.inc}
{$ENDIF}
ExtButton1.On('click', Ajax(ExtButton1Click));
End;
Ну, и определим действие -
- Код: Выделить всё
Procedure TExtWindow1.ExtButton1Click;
Begin
ExtFormTextArea1.Text := 'Привет, мир!';
end;
В итоге у нас должно получиться следующее -
- Код: Выделить всё
Unit Unit1;
Interface
Uses
SysUtils, Classes,
{$DEFINE UseRuntime}
{$IFDEF UseRuntime}
Ext, ExtPascal, ExtPascalUtils, ExtForm,
ExtData, ExtGrid, ExtUtil, ExtAir, ExtDd,
ExtLayout, ExtMenu, ExtDirect, ExtState, ExtTree,
ExtUxForm;
Type
{$M+}
TExtPanel_Tab = TExtPanel;
TExtFormTextField_Grid = TExtFormTextField;
TExtFormNumberField_Grid = TExtFormNumberField;
TExtFormDateField_Grid = TExtFormDateField;
TExtFormTimeField_Grid = TExtFormTimeField;
TExtFormCheckbox_Grid = TExtFormCheckbox;
TExtFormComboBox_Grid = TExtFormComboBox;
{$M-}
{$ELSE}
ExtP_Design_Ctrls;
{$ENDIF}
{$M+}
Type
{ TExtWindow1 }
TExtWindow1 = Class(TExtWindow)
ExtButton1: TExtButton;
ExtFormTextArea1: TExtFormTextArea;
Private
Public
Constructor Create;
Procedure Show;
Published
Procedure ExtButton1Click;
End;
{$M-}
Implementation
Uses
AppThread;
Procedure TExtWindow1.ExtButton1Click;
Begin
ExtFormTextArea1.Value := 'Привет, мир!';
end;
Constructor TExtWindow1.Create;
Begin
Inherited;
{$IFDEF UseRuntime}
{$I unit1.inc}
{$ENDIF}
ExtButton1.On('click', Ajax(ExtButton1Click));
End;
Procedure TExtWindow1.Show;
Begin
Inherited Show;
End;
End.
и выглядеть всё должно так -
Ну, и напоследок то, что поначалу меня несколько испугало - отсутствие привычных Align'ов. В ExtJS вместо этого используются различные Layout менеджеры. Несколько перепишем конструктор формы, чтобы увидеть, как это работает один из них, наиболее близкий к Align'у - Layout Border:
- Код: Выделить всё
Constructor TExtWindow1.Create;
Begin
Inherited;
{$IFDEF UseRuntime}
{$I unit1.inc}
{$ENDIF}
Layout := lyBorder;
ExtButton1.Region := rgNorth;
ExtButton1.On('click', Ajax(ExtButton1Click));
ExtFormTextArea1.Region := rgCenter;
End;
Результатом получится следующее -
Надеюсь, эта заметка поможет начать работу с ExtPascal ^_^