Создание Internet-приложений в среде Delphi. Компоненты TDataSetTableProducer и TDataSetPageProducer

   
На этом шаге мы рассмотрим компоненты TDataSetTableProducer и TDataSetPageProducer палитры Internet.

   
Воспользуемся базой данных DBDemos из поставки Delphi 6.0, а из нее выберем таблицу
events.db. В таблице перечисляются ожидаемые спортивные состязания.

   
В поле Event_Name занесено название соревнования, поля Event_Date и Event_Time -
дата и время соревнования, а в Memo-поле Event_Description приводится описание
соревнования.

   
Event_Photo это BLOB-поле, в котором хранятся фотоснимки с сюжетами соревнований и
последнее поле, Ticket_price, - это цена билета на означенное соревнование.

   
В программе сначала показывается все содержимое таблицы в HTML-документе. Откуда
по щелчку "мыши" на нужной записи будет выводиться подробное описание соревнования с
выводом графического изображения.

   
Создадим новое Web-приложение. Поместим на его форму компонент ТТable, и
подключим его к таблице events.db.

   
Зададим в свойстве DataBaseName имя DBDemos, а свойству TableName присвоим
значение events.db. При Web-запросе без параметров, когда путь не указан,
будем выводить содержимое отобранных столбцов всей таблицы. В другом варианте запроса,
со значением пути равным, например строке "/full", будем выводить подробную информацию о состязании.

   
Добавим на форму компонент TDataSetTableProducer, и создадим объект-действие по имени
initial, с пустым значением PathInfo и свойством Enabled равным True.
Вслед за этим добавим действие по умолчанию: назовем его default, а путь оставим пустым.
Поставим отметку на свойстве Default, a Enabled установим в False. Последняя
установка делается для того, чтобы это действие гарантированно выполнялось только в самую
последнюю очередь. Это действие по умолчанию будет выдавать сообщение об ошибке.

   
Далее необходимо связать объекты DataSetTableProducer1 и Table1. Для
этого указываем имя Table1 в свойстве DataSet поставщика данных.

   
Заголовок всей таблицы находится в свойстве Caption. В свойствах Footer
и Header задаются необходимые заголовочные и заключительные HTML-теги,
которыми поставщик обрамляет данные из таблицы базы данных, чтобы получить корректный HTML-документ,
понятный Web-браузеру.

   
В этой программе для Header используется следующий фрагмент:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> <HTML>
<HEAD>
<TITLE>3аказ билетов на спортивные состязания</TITLE>
</HEAD>
<BODY>

   
В свойстве Footer указывается только две строки

</BODY>
</HTML>

   
В ответ на активизацию свойства Columns загрузится окно Редактора этого свойства,
показанное на рисунке 1. Основное, что можно сделать в этом редакторе, это отобрать нужные поля для вывода в таблицу.


Рис.1. Окно редактора свойства Columns

   
Кроме этого можно задать имена для выводимых колонок и настроить цвет и обрамление.
Если в таблице полей много, а вывести нужно меньшую их часть, то в этом случае, можно
добавить их по одному, нажимая на кнопку Add New. Либо, воспользовавшись кнопкой
Add All, добавить все поля сразу, а затем, удалить ненужные с помощью кнопки
Delete Selected. Если выбрать поле в правом окне редактора и раскрыть свойство
Title в окне Инспектора Объектов, то можно поменять имя заголовка
столбца, его цвет и выравнивание. Далее вводим строку кода в обработчик события
OnAсtion объекта-действия initial.

procedure TWebModule1.WebModule1initialAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled:Boolean);
begin
    Response.Content:=DataSetTableProducer1.Content;
end;

   
Оформим обработчик события ОnAсtion для действия по умолчанию, который может выглядеть
так:

procedure TWebModule1.WebModule1defaultAction(Sender:TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  Response.Content:='<H2>Ошибка запроса!</H2>';
  Response.Content:=Response.Content+'<a href=../dstr2.exe>
<h2>Назад</h2></a>';
end;

   
Первая часть задачи выполнена. Клиент может отправить запрос к базе данных на сервер
и получить отчет о запросе в окне браузера. Внешний вид итога запроса можно видеть на
рисунке 2.


Рис.2. Внешний вид итога запроса к базе данных в окне браузера

   
Далее реализуем вторую половину задачи: просмотрев весь список соревнований, клиент должен
иметь возможность получить полную информацию об интересующем его состязании.
   
Простейший вариант, это превратить строки с названиями состязания в первой колонке в
ссылки. И это можно сделать, если воспользоваться одним из трех событий поставщика,
возникающих в процессе формирования таблицы. Эти события называются OnCreateContent,
OnGetTableCaption и OnFormatCell.

   
Первое инициируется перед созданием таблицы. В нем можно внести последние изменения в
этот процесс или совсем отменить: если обработчик этого события вернет в параметре
Continue значение False, то таблица формироваться не будет.

   
Второе событие вызывается при формировании заголовка таблицы. В этом обработчике можно
изменить название таблицы и задать режим выравнивания текста заголовка.

   
Третье событие, вызывается при формировании содержимого каждой ячейки.

   
Ниже приводится текст обработчика этого события:

procedure TWebModule1.DataSetTableProducer1FormatCell(Sender:TObject;
                        CellRow, CellColumn: Integer; var BgColor:THTMLBgColor;
                        var Align: THTMLAlign; var VAlign:THTMLVAlign;
                        var CustomAttrs,CellData: String);
begin
   if (CellRow>0)and(CellColumn=0) then
       Celldata:='<a href=dstr2.exe\full?EventNo='+
       table1.Fields[0].AsString+'>'+Celldata+'</A>';
end.

   
Параметры этой процедуры включают в себя номера столбца и строки таблицы для обрабатываемой ячейки
(нумерация начинается с нуля), цвет фона ячейки, горизонтальное и вертикальное выравнивание,
дополнительные атрибуты ячейки и текст, помещаемый в ячейку. В операторе
if проверяются номера столбца и строки ячейки, и если ячейка не из первой строки
(строки заголовка) и находится в первом столбце, то ее содержимое меняется: добавляются соответствующие
теги HTML и данные о пути и запросе. В качестве имени пути здесь вставлена строка
full, но объекта-действия для этого пути пока нет.

   
Далее, за именем пути прописывается строка EventNo=, к которой добавляется содержимое
первого поля базы данных, поле EventNo, преобразованное в строку. В результате Query-часть запроса
для одной из строк таблицы будет иметь вид EventNo=7. Теперь нужно создать объект-действие
для пути /full. Это действие должно сформировать новый документ с подробными данными
о выбранном спортивном состязании. Для данной цели будет использоваться другой поставщик данных
из таблиц данных: ТDataSetPageProducer. Добавим его в форму приложения. В свойстве
DataSet этого компонента нужно указать таблицу, с которой работает поставщик, -
Table1 в данном случае. Затем заполняем свойство HTMLDoc шаблоном,
заготовкой того документа, который должен получить клиент.

   
Шаблоны использует еще один компонент из панели Internet: TPageProducer. Когда в
процессе обработки документа, компоненту встречается шаблон, он инициирует событие OnHTMLTag.
В обработчике этого события должна пройти замена шаблона на соответствующие данные. Но в
случае рассматриваемого компонента, TDataSetPageProducer, обработкой шаблонов можно и
не заниматься, если дать им имена совпадающие с именами полей таблицы данных. В этом
случае компонент сам произведет замену шаблонов на значения соответствующих полей текущей
записи таблицы данных. В качестве "шаблонного" документа можно использовать следующий текст:

<html>
<head>
<title>Обзор спортивного состязания</title>
</head>
<Table Width="100%" Border=1 BgColor="Silver"><Caption>Заказ билетов на 
спортивные соревнования</Caption>
<TR><TH Align="Right">Номер по порядку</TH>
<TH Align="Left"><#EventNo></TH></TR>
<TR><TH Align="Right">Название состязания</TH>
<TH Align="Left"><#Event_Name></TH></TR>
<TR><TH Align="Right">Дата проведения</TH>
<TH Align="Left"><#Event_Date></TH></TR>
<TR><TH Align="Right">Время проведения</TH>
<TH Align="Left"><#Event_Time></TH></TR>
<TR><TH Align="Right">Цена билета</TH>
<TH Align="Left"><#Ticket_price></TH></TR>
</Table>
<br><br>
<#Event_Description>
<br><br>
<#Event_Photo>
<br><br>
<a href="../dstr2.exe">Вернуться назад</a>
</body>
</html>

   
В тексте фрагмента программы хорошо видны шаблоны, имена которых совпадают с именами полей
таблицы events.db. В конце текста выводится ссылка, активизировав которую,
можно вернуться к полному списку записей таблицы.

   
Далее нужно создать объект-действие для значения пути full, у него в свойстве PathInfo
задается строка /full. Если выбрать из списка значений свойства Producer значение DataSetPageProducer1
и откомпилировать проект, то получим следующее: при выборе разных строк таблицы выводятся данные
только из первой записи. И это закономерно, так как данные для получения сведений из
нужной записи есть, но они никак не используются.

   
Очевидно, самым простым решением в данном случае было бы простое перемещение указателя в таблице
на отобранную запись. И сделать это можно в обработчике события OnAction объекта-действия full.
Но чтобы этот обработчик срабатывал первым, необходимо очистить свойство Producer и вызывать
нужный поставщик из обработчика события OnAction. Обработчик будет выглядеть следующим образом:

procedure TWebModule1.WebModule1fullAction(Sender: TObject;
          Request: TWebRequest; Response: TWebResponse; var Handled:Boolean);
var
   q1:string;
   options:TLocateOptions;
begin
   q1:=Request.QueryFields.Values['EventNo'];
   Table1.Locate('EventNo',q1,options);
   Response.Content:=DataSetPageProducer1.Content;
end;

   
Здесь в переменную q1 помещается значение для поля EventNo, затем выполняется переход
к соответствующей записи таблицы, которая становится теперь текущей записью, а в последней
строке вызывается функция Content поставщика данных, который подставляет на
место шаблонов, значения из текущей записи таблицы и возвращает сформированный документ свойству
Content объекта Response.

   
В таблице events.db имеются еще графические изображения и Mемо-поля,
их также нужно выводить в ответ на запрос пользователя. Сейчас вместо графики и текста
из Mемо-поля можно увидеть в браузере "условные обозначения" (MEMO) и (GRAPHIC).
Для работы с этими полями придется ввести в обработчик события OnHTMLTag компонента
TDataSetPageProducer следующий код:

procedure TWebModule1.DataSetPageProducer1HTMLTag(Sender:TObject;
                          Tag: TTag; const TagString: String;
                          TagParams: TStrings; var ReplaceText: String);
begin
   if CompareText(TagString,'Event_Photo')=0 then
        ReplaceText:='<img src=Photo?EventNo='+
        table1.Fields[0].AsString+'>';
   if CompareText(TagString,'Event_Description')=0 then
       ReplaceText:=Table1.FieldByName('Event_Description').AsString;
end;

   
Что касается обработки Mемо-поля, то здесь все делается в одну строку, а за
рисунком придется еще раз обратиться на Web-сервер. Здесь формируется тег HTML, используемый
для описания графических изображений, который ссылается на приложение (имя приложения и адрес сервера
браузер в данном случае подставляет сам) с новым значением пути Photo, за которым
следует ссылка на нужную запись таблицы данных. Естественно, нужно добавить в приложение еще
один объект-действие, обработчик события OnAction, код которого приводится ниже:

procedure  TWebModule1.WebModule1PhotoAction(Sender: TObject;
       Request: TWebRequest; Response: TWebResponse; var Handled:Boolean);
var
  B:TBitmap;
  S:TMemoryStream;
  q1:string;
  options:TLocateOptions;
begin
   q1:=Request.QueryFields.Values['EventNo'];
   Table1.Locate('EventNo',q1,options);
   B:=TBitmap.Create;
   B.Assign(Table1.FieldByName('Event_Photo'));
   S:=TMemoryStream.Create;
   B.SaveToStream(S);
   S.Position:=0;
   Response.ContentType:='image/x-xbitmap';
   Response.ContentStream:=S;
   B.Free;
end;

   
В вышеприведенном фрагменте вначале указатель в таблице устанавливается на нужную
запись, затем создается объект типа BitMap и в него переписывается содержимое
поля Event_Photo. Затем создается поток в памяти и в него переписывается нужный
графический образ. Далее остается установить указатель в потоке на начало и передать
Web-серверу указатель на поток и тип данных в потоке.

   
Пример ответа на запрос приведен на рисунке 3.


Рис.3. Ответ на запрос

   
Листинг программы приводится ниже.

unit DSTR1;

interface

uses
  SysUtils, Classes, HTTPApp, DBWeb, DB, DBTables, HTTPProd, DSProd,Graphics;

type
  TWebModule1 = class(TWebModule)
    Table1: TTable;
    DataSetTableProducer1: TDataSetTableProducer;
    DataSetPageProducer1: TDataSetPageProducer;
    procedure WebModule1initialAction(Sender: TObject;
      Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
    procedure WebModule1defaultAction(Sender: TObject;
      Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
    procedure DataSetTableProducer1FormatCell(Sender: TObject; CellRow,
      CellColumn: Integer; var BgColor: THTMLBgColor;
      var Align: THTMLAlign; var VAlign: THTMLVAlign; var CustomAttrs,
      CellData: String);
    procedure WebModule1fullAction(Sender: TObject; Request: TWebRequest;
      Response: TWebResponse; var Handled: Boolean);
    procedure DataSetPageProducer1HTMLTag(Sender: TObject; Tag: TTag;
      const TagString: String; TagParams: TStrings;
      var ReplaceText: String);
    procedure WebModule1PhotoAction(Sender: TObject; Request: TWebRequest;
      Response: TWebResponse; var Handled: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  WebModule1: TWebModule1;

implementation

{$R *.DFM}

procedure TWebModule1.WebModule1initialAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
    Response.Content:=DataSetTableProducer1.Content;
end;

procedure TWebModule1.WebModule1defaultAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
   Response.Content:='<H2>Ошибка запроса!</H2>';
   Response.Content:=Response.Content+'<a href=../dstr2.exe><h2>Назад</h2></a>';
end;

procedure TWebModule1.DataSetTableProducer1FormatCell(Sender: TObject;
  CellRow, CellColumn: Integer; var BgColor: THTMLBgColor;
  var Align: THTMLAlign; var VAlign: THTMLVAlign; var CustomAttrs,
  CellData: String);
begin
   if (CellRow>0)and(CellColumn=0) then
     Celldata:='<a href=dstr2.exe\full?EventNo='+
        table1.Fields[0].AsString+'>'+Celldata+'</A>';
end;

procedure TWebModule1.WebModule1fullAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
   q1:string;
   options:TLocateOptions;
begin
   q1:=Request.QueryFields.Values['EventNo'];
   Table1.Locate('EventNo',q1,options);
   Response.Content:=DataSetPageProducer1.Content;
end;

procedure TWebModule1.DataSetPageProducer1HTMLTag(Sender: TObject;
  Tag: TTag; const TagString: String; TagParams: TStrings;
  var ReplaceText: String);
begin
   if CompareText(TagString,'Event_Photo')=0 then
      ReplaceText:='<img src=Photo?EventNo='+table1.Fields[0].AsString+'>';
    if CompareText(TagString,'Event_Description')=0 then
      ReplaceText:=Table1.FieldByName('Event_Description').AsString;
end;

procedure TWebModule1.WebModule1PhotoAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  B:TBitmap;
  S:TMemoryStream;
  q1:string;
  options:TLocateOptions;
begin
   q1:=Request.QueryFields.Values['EventNo'];
   Table1.Locate('EventNo',q1,options);
   B:=TBitmap.Create;
   B.Assign(Table1.FieldByName('Event_Photo'));
   S:=TMemoryStream.Create;
   B.SaveToStream(S);
   S.Position:=0;
   Response.ContentType:='image/x-xbitmap';
   Response.ContentStream:=S;
   B.Free;
end;

end.

Текст приложения можно взять здесь.

   
На следующем шаге мы рассмотрим компонент TPageProducer.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий