Разработка кроссплатформенных мобильных приложений в Delphi #4
В четвертой части настоящего цикла мы вновь возвратимся к разработке «настольного» приложения и попытаемся более подробно разобраться с технологией связывания объектов LiveBinding. Данный механизм универсален и подходит как для мобильных, так и настольных приложений. Более того, этот механизм работает и в VCL. Знакомство же с LiveBinding лучше начать именно в классическом проекте.
Прежде всего, нам придется выполнить несколько однотипных задач, работа над которыми может показаться рутинной. Речь идет о создании форм редактирования списков, а именно, списка единиц измерений и списка продуктов. Данные формы будут вызываться из меню главной формы, которое нам также предстоит создать.
Итак, в модуле данных поместим два компонента TFDTable и настроим их на работу с таблицами tblUnit и tblFoodstuff (по аналогии с набором данных для работы с таблицей tblRecipe). Двойным щелчком на компоненте откроем редактор полей, добавим все поля (пункт контекстного меню Add all fields).
Важно понимать, что практически во всех реализациях компоненты наборов данных наследуются от класса TDataSet и работают с некоторым набором полей. Здесь имеются в виду экземпляры классов, наследников TField (TIntegerField, TStringField и т.д.). Набор полей можно создать в режиме проектирования (design-time) и настроить свойства полей с помощью «инспектора объектов». Если рассматривать TFDTable, то помимо полей, соответствующих физическим полям таблицы, можно создать и другие типы полей, например, вычисляемое (Caclulated) или подставляемое (LookUp) поле. Значения этих полей будут вычисляться динамически в ходе работы программы, а не браться из источника данных. Чуть ниже мы рассмотрим пример создания таких полей.
В том же случае, если набор полей не создан в режиме проектирования, при открытии набора данных в процессе работы программы, набор полей будет создан автоматически.
Ниже приведен фрагмент файла формы модуля данных uDM.dfm, содержащий описание одного из наборов данных и связанных с ними полей. Текстовое представление формы можно получить, если в контекстном меню формы выбрать пункт «View as Text». Для того, что бы вернуться в обычный режим представления формы, следует нажать «View as Form».
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<span style="color: #000000; font-weight: bold;">object</span> FDTUnits<span style="color: #000066;">:</span> TFDTable IndexFieldNames <span style="color: #000066;">=</span> <span style="color: #ff0000;">'Id'</span> Connection <span style="color: #000066;">=</span> FDConnection1 UpdateOptions<span style="color: #000066;">.</span><span style="color: #006600;">UpdateTableName</span> <span style="color: #000066;">=</span> <span style="color: #ff0000;">'tblUnit'</span> TableName <span style="color: #000066;">=</span> <span style="color: #ff0000;">'tblUnit'</span> Left <span style="color: #000066;">=</span> <span style="color: #0000ff;">112</span> Top <span style="color: #000066;">=</span> <span style="color: #0000ff;">208</span> <span style="color: #000000; font-weight: bold;">object</span> FDTUnitsId<span style="color: #000066;">:</span> TFDAutoIncField FieldName <span style="color: #000066;">=</span> <span style="color: #ff0000;">'Id'</span> Origin <span style="color: #000066;">=</span> <span style="color: #ff0000;">'Id'</span> ProviderFlags <span style="color: #000066;">=</span> <span style="color: #000066;">[</span>pfInWhere<span style="color: #000066;">,</span> pfInKey<span style="color: #000066;">]</span> ReadOnly <span style="color: #000066;">=</span> <span style="color: #000000; font-weight: bold;">True</span> <span style="color: #000000; font-weight: bold;">end</span> <span style="color: #000000; font-weight: bold;">object</span> FDTUnitsUnitName<span style="color: #000066;">:</span> TStringField FieldName <span style="color: #000066;">=</span> <span style="color: #ff0000;">'UnitName'</span> Origin <span style="color: #000066;">=</span> <span style="color: #ff0000;">'UnitName'</span> Required <span style="color: #000066;">=</span> <span style="color: #000000; font-weight: bold;">True</span> Size <span style="color: #000066;">=</span> <span style="color: #0000ff;">25</span> <span style="color: #000000; font-weight: bold;">end</span> <span style="color: #000000; font-weight: bold;">object</span> FDTUnitsAbbr<span style="color: #000066;">:</span> TStringField FieldName <span style="color: #000066;">=</span> <span style="color: #ff0000;">'Abbr'</span> Origin <span style="color: #000066;">=</span> <span style="color: #ff0000;">'Abbr'</span> Required <span style="color: #000066;">=</span> <span style="color: #000000; font-weight: bold;">True</span> Size <span style="color: #000066;">=</span> <span style="color: #0000ff;">7</span> <span style="color: #000000; font-weight: bold;">end</span> <span style="color: #000000; font-weight: bold;">end</span> |
Созданные наборы данных, необходимо открыть при запуске программы. Модифицируем процедуру ConnectToDB следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<span style="color: #000000; font-weight: bold;">function</span> TDM<span style="color: #000066;">.</span><span style="color: #006600;">ConnectToDB</span><span style="color: #000066;">:</span> <span style="color: #000066; font-weight: bold;">Boolean</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">begin</span> <span style="color: #000000; font-weight: bold;">try</span> FDConnection1<span style="color: #000066;">.</span><span style="color: #006600;">Connected</span> <span style="color: #000066;">:</span><span style="color: #000066;">=</span> <span style="color: #000000; font-weight: bold;">True</span><span style="color: #000066;">;</span> FDTRecipe<span style="color: #000066;">.</span><span style="color: #006600;">Open</span><span style="color: #000066;">;</span> FDTUnits<span style="color: #000066;">.</span><span style="color: #006600;">Open</span><span style="color: #000066;">;</span> FDTFoodstuff<span style="color: #000066;">.</span><span style="color: #006600;">Open</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">except</span> <span style="color: #000000; font-weight: bold;">end</span><span style="color: #000066;">;</span> Result <span style="color: #000066;">:</span><span style="color: #000066;">=</span> FDConnection1<span style="color: #000066;">.</span><span style="color: #006600;">Connected</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">end</span><span style="color: #000066;">;</span> |
Следующим шагом разработки приложения станет создание новой формы для отображения и редактирования таблицы (списка) единиц измерения. Естественно, это будет FM HD форма. Значение свойства Position установим как poMainFormCenter, для того, что бы данная форма отображалась посредине главной формы.
В список используемых модулей секции implementation добавим модуль данных:
1 2 3 4 5 |
<span style="color: #000000; font-weight: bold;">implementation</span> <span style="color: #008000; font-style: italic;">{$R *.fmx}</span> <span style="color: #000000; font-weight: bold;">uses</span> uDM<span style="color: #000066;">;</span> |
Поместим на форме компоненты TGrid, TPanel. На панели поместим кнопку, поле ввода и метку TLabel, как это показано на рисунке. Единственное назначение кнопки – закрыть форму. Свойству ModalResult определим значение mrOk.
Мы сохраняем названия визуальных компонентов по умолчанию исключительно из соображений наглядности. В рабочих проектах, естественно, их лучше переименовать.
С помощью редактора LiveBinding свяжем визуальные компоненты с источниками данных. В самых общих чертах,LiveBinding это механизм, позволяющий связывать свойства различных объектов, но не при помощи жёсткой ссылочной компилированной связи, а на основе гибких выражений (expressions). Механизм LiveBindings базируется на шаблоне «наблюдатель» (observer). Так, изменение некоторого свойства объекта А, с помощью LiveBinding может повлечь за собой изменение свойства объекта Б. Связи между объектами могут быть однонаправленными и двунаправленными. Такой подход очень удобно использовать для отображения данных из наборов данных. Фактически, если в стандартном подходе VCL для отображения данных из таблиц требовались специальные DB-ориентированные (DB-Aware) визуальные компоненты, то LiveBindings позволяет использовать для этой цели самые обычные элементы управления («контролы). Более того, визуальные компоненты не требуют специальной подготовки, для работы с LiveBindings. Преимущество такого подхода очевидно. Давайте рассмотрим данный процесс чуть внимательнееболее подробно.
Итак, откроем LiveBinding Designer и найдем элемент, соответствующий набору данных, FDTUnits. Если элементы из модуля данных не отображаются в LiveBinding дизайнере, то следует сделать обновление (в контекстном меню выбрать пункт Refresh Designer). Попытаемся связать значение свойства Text поля ввода Edit1 со значением поля UnitName в наборе данных. Используем обычное перетаскивание (drag-n-drop).
Что же произошло на самом деле?
Помимо того, что в дизайнере визуально отобразилась связь, на форме появилось два новых не визуальных компонента. Компонент TBindSourceDB с помощью свойства DataSet осуществляет связь с исходным набором данных (в нашем случае DM.FDTUnits). Обратите внимание на то, что как только была установлена связь между свойством визуального компонента и полем, в LiveBinding дизайнере объект DM.FDTUnits оказался вложенным в новый объект BindSourceDB1, и этот объект появился на форме.
Нетрудно догадаться, какое значение свойства DataSet будет у данного объекта. Для тех, кто мыслит в терминах «классической VCL разработки», проще всего воспринимать TBindSourceDB как некий аналог TDataSource. Вы можете точно также «бросить» этот компонент на форму и указать значение свойства DataSet. А затем «привязать» к нему контрол. Только теперь это будет не специальный DB-контрол, а любой визуальный компонент. А, следовательно, вы должны указать, какое именно свойство компонента и каким образом должно отображать (и, возможно, изменять) данные из набора данных. Давайте посмотрим, как это сделать.
Кроме BindSourceDB1 на форме появился и еще один объект — BindingsList1. Он является хранилищем для всех связей между объектами. Связи эти могут быть разных типов. Как видно из рисунка, в нашем случае в BindingsList была добавлена связь типа TLinkControlToField.
Вы можете отредактировать ее свойства, например, сделать связь не двунаправленной, а однонаправленной.
Если вы попробуете добавить новую связь, то увидите, что существует довольно много различных типов связей, практически позволяющих связать «всё со всем».
Теперь свяжем Grid и BindNavigator с набором данных. Для компонента BindNavigator достаточно задать свойство DataSource. При этом в списке связей BindingsList1 новая связь не создается. А вот при связывании Grid’а, напротив, создается объект типа TLinkGridToDataSourceBindSourceDB.
В инспекторе объектов мы можем отредактировать список полей. Для этого вызовем свойство Columns и в редакторе полей нажмем кнопку Add All Fields. К слову, этот редактор очень напоминает редактор полей в TDBGrid. Для каждого из полей можно отредактировать свойства, в частности ширину поля и текст заголовка. Кроме этого, можно создать новое поле, и задать выражение (свойство CustomFormat) для отображения в столбце таблицы. Так для того, что бы отобразить комбинацию Id и аббревиатуры, мы можем задать такое выражение:
1 2 |
DataSet.FieldByName('Id').AsString +" - "+DataSet.FieldByName('Abbr').AsString |
Как следует из вышесказанного, механизм LiveBinding предоставляет достаточно широкие возможности для отображения данных. LiveBinding дизайнер, в свою очередь, позволяет визуализировать и упростить процесс связывания визуальных компонентов с источником данных.
В заключение рассмотрим еще один прием работы с LiveBinding. В дизайнере сделайте активным поле Abbr элемента DM. FDTUnits и в контекстном меню выберите пункт Link to new control… (Связать с новым элементом управления…). В появившемся списке выберите значение TEdit.
Нажмите кнопку «Ок» и на форме будет размещен новый элемент управления TEdit и «приклеенная» к нему метка TLabel. Вам останется только поместить данный объект в нужную позицию и задать нужное значение свойства Text метки.
Вызов форм редактирования списков из главной формы организуем с помощью меню. На главной форме поместим компонент TMainMenu. Двойным щелчком вызовем редактор меню. И создадим несколько пунктов, так как это показано на рисунке.
Для пункта меню “Единицы измерения” зададим следующий обработчик события OnClick:
1 2 3 4 |
<span style="color: #000000; font-weight: bold;">procedure</span> TfMain<span style="color: #000066;">.</span><span style="color: #006600;">aSprUnitExecute</span><span style="color: #000066;">(</span>Sender<span style="color: #000066;">:</span> <span style="color: #000066; font-weight: bold;">TObject</span><span style="color: #000066;">)</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">begin</span> fSprUnits<span style="color: #000066;">.</span><span style="color: #006600;">ShowModal</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">end</span><span style="color: #000066;">;</span> |
Естественно, модуль с формой-списком необходимо подключить к главной форме.
1 2 3 4 5 |
<span style="color: #000000; font-weight: bold;">implementation</span> <span style="color: #008000; font-style: italic;">{$R *.fmx}</span> <span style="color: #000000; font-weight: bold;">uses</span> uAddRecipe<span style="color: #000066;">,</span> uSprUnit<span style="color: #000066;">;</span> |
Форму-список продуктов вы можете сделать по аналогии.
В этой части цикла мы более детально рассмотрели механизм связывания LiveBinding, его назначение и принципы его работы. Далее мы продолжим реализацию функционала программы.
Источник: habrahabr.ru