Окружение данных в Visual FoxPro
« Назад Объект DataEnvironmentобразуется при создании формы, набора форм или отчета. Объект функционирует как контейнер таких объектов, как Cursor, CursorAdapter и Relation, ассоциированных с формой, набором форм или отчетом. Объект Cursor образуется при добавлении в DataEnvironment таблицы, вида или курсора. Объект Relation отображает отношение между двумя таблицами. CursorAdapter – это буферизованный курсор, представляющий данные одного или нескольких источников. В качестве таковых могут браться таблицы VFP, представления удаленных данных (ODBC-курсоры), ActiveX-источники данных и XML-данные. Во время исполнения могут быть установлены только следующие свойства объекта DataEnvironment: DataSource, DataSourceType, InitialSelectedAlias, Name, OpenViews и Tag. Чтобы новое значение свойства имело действие, необходимо вызвать методы CloseTables и OpenTables объекта DataEnvironment. Попытка изменить другие свойства объекта приведет к генерации ошибки. На базе класса DataEnvironment может быть определен подкласс, например: define class DtEnv as DataEnvironment && … endDefine Интерактивно объект DataEnvironment создается в проектировщике окружения Data Environment Designer, который доступен при разработке формы, набора форм или отчета. С набором форм ассоциируется один объект DataEnvironment, ссылку на который содержит одноименное свойство формы. Находясь в проектируемой форме, окружение данных может быть сохранено в виде библиотеки класса – VCX-файла путем выполнения команды меню File – Save As Class – DataEnvironment. Все свойства, события и методы DataEnvironment отобразятся в окне свойств объекта после открытия этого файла в проектировщике классов Class Designer. В форму (набор форм) можно добавить объект класса DataEnvironment, пользуясь, например, методом AddObject. Однако VFP не рассматривает этот объект как собственное окружение формы, ссылку на которое хранит свойство DataEnvironment формы. Также на этапе проектирования можно использовать свойства DEClass и DEClassLibrary формы, чтобы задать и загрузить внешний класс DataEnvironment, например: define class SomeForm as Form DEClassLibrary = "MyProgram.prg" DEClass = "MyDE" endDefine Свойства DEClass и DEClassLibrary поддерживаются только для форм, визуальных классов и программ, но не имеются в наборах форм или в проектировщике отчетов. Замечание. Описание свойств, методов и событий объекта DataEnvironment см. в справке VFP, тема DataEnvironment Object. Пример. Создается форма, содержащая 2 элемента управления Grid (Сетка) соответственно с именами Grid1 и Grid2. Первый отображает список авторов, второй – книги выбранного автора и в качестве источника данных используют таблицу BooksAuthors. Определим прежде объекты DataEnvironment. Для представления данных об авторах и их книгах нам в соответствии с приведенной в разд. 2.2 моделью данных понадобятся таблицы Authors и Books, содержащие соответственно списки авторов и их книг, и таблица и BooksAuthors, связывающая эти два списка. Таблица BooksAuthors в чистом виде не отображается, но снабжает сетку Grid2 названиями книг выбранного автора. Все таблицы входят в базу данных HomeLibrary. Создадим новую форму, например d:\SomeForm.scx; откроем проектировщик DataEnvironment (команда меню View – DataEnvironment или контекстное меню формы), добавим в окружение упомянутые таблицы (команда меню DataEnvironment – Add). Далее установим связь между таблицами Authors и BooksAuthors так, как это показано на рис. 10.5 (чтобы установить связь, нужно захватить мышью поле AuthorId таблицы Authors и перетащить его к одноименному полю таблицы BooksAuthors). Рис. 10.5. Окружение формы SomeForm После выполнения описанных действий объект DataEnvironment будет содержать 3 курсора, по умолчанию получившие имена Cursor1, Cursor2 и Cursor3, и отношение с именем Relation1. Отношение Relation1 обеспечивает отображение в сетке Grid2 названий книг автора, выбранного в сетке Grid1. Иных записей сетка Grid2 не показывает. Имена курсоров, как и значения других свойств, можно изменить в окне редактирования свойств после выбора соответствующего объекта. Сохраним форму SomeForm и запустим ее на исполнение. В окне Data Session отобразятся открытые таблицы и установленное отношение (рис. 10.6). Рис. 10.6. Окно Data Session после открытия формы SomeForm Добавленные в окружение данных формы SomeForm таблицы открываются при запуске формы, поскольку свойство AutoOpenTables окружения равно .T. После открытия формы имена имеющихся в ее окружении объектов выведет следующий код: do form d:\SomeForm noShow dtEnv = SomeForm.DataEnvironment for each ob in dtEnv.Objects ? ob.Name endFor Возможный результат: Cursor1 Cursor2 Cursor3 Relation1 При закрытии формы закроются и таблицы ее окружения. Этого, правда, не случиться, если установить свойство AutoCloseTables окружения в .F. Значения свойств AutoOpenTables и AutoCloseTables могут быть изменены только на этапе проектирования. Добавим теперь, используя иконку панели управления Form Controls, в форму элемент управления Grid (сетка), установив его размеры достаточно большими для отображения полей Author и InputDate таблицы Authors. По умолчанию добавленная сетка получит имя Grid1. Далее выберем эту сетку, откроем при помощи контекстного меню построитель сетки (Builder), выберем на его вкладке Grid Items ранее открытую базу данных HomeLibrary, таблицу Authors и ее поля Author и InputDate (рис. 10.7). Рис. 10.7. Фрагмент вкладку Grid Items построителя сетки Отредактируем на вкладке Layout заголовки столбцов сетки и их размеры, приведя внешний вид объекта в соответствие с рис. 10.8. Рис. 10.8. Форма SomeForm Вторую сетку (Grid2), предназначенную для отображения книг выбранного автора, создадим без употребления построителя сетки по той причине, что в качестве источника данных ее столбца будет использовано выражение LookUp(Books.Book, BooksAuthors.BookId, Books.BookId, 'BookId') позволяющее взамен кода книги, хранящегося в поле BooksAuthors.BookId, выводить ее название. Определить такой источник данных в построителе сетки нельзя. Поэтому, добавив сетку в форму, приведем ее размеры в соответствие с рис. 10.8; остальные свойства сетки Grid2 и ее компонентов зададим программно, разместив в обработчике события Init формы следующий код: with ThisForm.Grid2 && Источник данных сетки .RecordSource = "BooksAuthors" && Число столбцов сетки .ColumnCount = 1 && Источник данных столбца сетки .Column1.ControlSource = "LookUp(Books.Book, ; BooksAuthors.BookId, Books.BookId, 'BookId')" && Выравнивание в столбце сетки .Column1.Alignment = 0 && Ширина столбца сетки .Column1.Width = ThisForm.Grid2.Width && Заголовок столбца сетки .Column1.Header1.Caption = "Книги автора" endWith Кроме того, в этот же обработчик добавим еще одну WITH-команду, обеспечивающую отображение сеток Grid1 и Grid2 без нижних полос прокрутки. with ThisForm .Grid1.ScrollBars = 2 .Grid2.ScrollBars = 2 endWith Замечание. В этом обработчике вместо ссылки ThisForm можно употребить и ссылку This: обе ссылки указывают на один и тот же объект – форму. Установим, употребив иконку панели управления Form Designer, следующий порядок обхода элементов управления формы: Grid1 – 1, Grid2 – 2 и "Закрыть" – 3. При таком порядке во вновь открываемой форме будет выбираться сетка Grid1, а в ней – первая запись таблицы Authors. Если теперь употребить Ctrl+Tab, активизируется элемент Grid2. Находясь на кнопке "Закрыть", для перехода на Grid1 нужно уже нажать не Ctrl+Tab, а просто Tab. Обработчик события Click кнопки "Закрыть" содержит один закрывающий форму оператор: ThisForm.Release Запустим форму и просмотрим результат (рис. 10.9). Рис. 10.9. Форма SomeForm сразу после открытия Замечание. В приведенных сетках допускается непосредственное редактирование данных любого поля. В реальных приложениях такая ситуация недопустима. Пример 2. Создается форма d:\NextForm.scx с одной сеткой, использующей в качестве данных курсор-адаптер. Курсор-адаптер добавим в окружение формы, выполнив команду меню DataEnvironment – Add CursorAdapter. Далее, выбрав в контекстном меню курсора-адаптера команду Builder, откроем построитель курсора-адаптера. Вкладку Properties объекта определим в соответствии с рис. 10.10. Рис. 10.10. Вкладку Properties курсора-адаптера CursorAdapter1 Тип источника данных Native означает, что данные будут извлекаться из таблиц VFP. На вкладке Data Access разместим в том числе и приведенные на рис. 10.11 данные. Рис. 10.11. Фрагмент вкладки Data Access Остальные, не отображенные на рис. 10.11 поля вкладки, задающие параметры доставки данных (Data fetching), способ буферизации, значение флажка Break on error, оставим без изменений. Запрос Select command сформирован частично при помощи построителя запроса, открываемого по кнопке Build… вкладки. Запишем его более наглядно: select ; Authors.Author, BooksAuthors.AuthorId, BooksAuthors.BookId, Books.Book, Books.Price ; from Authors ; inner join BooksAuthors on Authors.Authorid = BooksAuthors.AuthorId ; inner join Books on BooksAuthors.BookId = Books.BookId ; order by Authors.Author На вкладке Auto-Update активизируем флажок Auto-update и активизируем в соответствии с рис. 10.12 флажки рядом с именами полей Book и Price. Рис. 10.12. Фрагмент вкладки Auto-Update При этом поле Book отметим и как обновляемое и как ключевое. Тогда изменения в сетке формы значений полей Book и Price приведет к аналогичным изменениям соответствующих полей источника данных – таблицы Books. Остальные, не приведенные на рис. 10.12 элементы управления вкладки, такие, как переключатели групп Update using и SQL WHERE clause includes и др., оставим без изменений. Замечание. Смысл определяемых при задании курсора-адаптера данных см. в описании функции CURSORSETPROP( ) (разд. 15.13) и частично в разд. 15.14 и 20.6. Порядок организации запросов см. в описании команды SELECT – SQL. В качестве источника данных (свойство RecordSource) единственной сетки формы укажем созданный курсор-адаптер Cursoradapter1 (рис. 10.13). Рис. 10.13. Задание источника данных сетки Grid1 Использовать построитель сетки с таким источником данных нельзя, поэтому выполним ее настройку, устанавливая интерактивно соответствующие значения свойств сетки и ее столбцов. Заголовки столбцов сетки, а также значение ее свойства ScrollBars изменим программно, включив в обработчик события Init формы следующий код: with This.Grid1 .Column1.Header1.Caption = "Автор" .Column2.Header1.Caption = "Книга" .Column3.Header1.Caption = "Цена" && Отказываемся от горизонтальной полосы прокрутки .ScrollBars = 2 endWith Свойство ScrollBars сетки, если оно установлено в 2, обеспечивает отображение только вертикальной полосы прокрутки объекта Grid1. Перейдем теперь к интерактивному заданию свойств. Выберем элемент управления Grid1 и в окне Properties установим на вкладке Layout значение свойства ColumnCount (число столбцов сетки) в 3. Откроем далее раскрывающийся список объектов формы и выберем в нем элемент Column1 (рис. 10.14) и установим его свойство ControlSource (источник данных) в соответствии с рис. 10.15. Рис. 10.14. Активизируем объект Column1 сетки Grid1 Рис. 10.15. Задание источника данных для Column1 сетки Grid1 Аналогичным образом установим ControlSource для Column2 и Column3 соответственно в CursorAdapter1.Book и CursorAdapter1.Price. Изменим, оперирую мышью, ширину столбцов сетки, принимая во внимание размеры выводимых в них значений. Такие изменения выполняются в режиме редактирования столбцов. Смена столбца производится после позиционирования мыши на одной из строк столбца и нажатия на правую кнопку мыши; выбор заголовка столбца осуществляется аналогичным образом после позиционирования мыши на заголовке. Замечание. Перейти к редактированию свойств столбцов и их заголовков можно и иным способом, – выбрав в контекстном меню сетки пункт Edit. Теперь, когда заданы свойства формы, сетки и ее столбцов, внесен код в обработчики событий Init формы и Click кнопки "Закрыть", запустим форму и просмотрим приведенный на рис. 10.16 результат. Рис. 10.16. Первый запуск формы NextForm Если после открытия формы ее сетка не активизируется, то изменим в проектировщике форм порядок обхода ее элементов управления, назначив первый номер элементу Grid1. Такой же эффект будет получен, если в обработчик события Init формы добавить две следующие строчки: ThisForm.Grid1.TabIndex = 1 ThisForm.Command1.TabIndex = 2 && Кнопка "Закрыть" Впрочем, в рассматриваемом случае вторая добавленная строка может быть опущена. |