Таблица (Grid)

Объект Grid используется для отображения данных в табличной форме.

С первого взгляда он похож на таблицу в режиме просмотра Browse, но это только с первого. Данный элемент управления представляет собой объект-контейнер, включающий в себя несколько объектов. Об объектах, входящих в состав Grid, поговорим позже, а сейчас начнем создавать этот элемент при помощи построителя.

Откроем в окне конструктора форм нашу форму с вкладками. Разместим при объекта Grid в ранее созданных контейнерах. Но начнем, естественно, с одного.

После расположения его внутри первого контейнера выберем команду Builder контекстного меню. Ну и как всегда в таких случаях, происходит запуск построителя.

Окно Grid Builder (Построитель таблицы) содержит четыре вкладки, первую из которых мы и видим в данный момент. Она называется Grid Items (Элементы) и здесь мы можем сформировать список полей, которые будут размещены в нашем объекте. Для этого в раскрывающемся списке Databases and tables (Таблицы и базы данных) укажем нашу базу данных oidFox, после чего внизу отразится список имеющихся в базе данных таблиц.

Выбрав необходимую таблицу, мы увидим список полей данной таблицы в области AvaiJables fields (Имеющиеся поля). При помощи кнопок со стрелками перенесем те поля, которые мы хотим разместить в Grid, в область Selectee fields (Выбранные поля). На этом работу с первой вкладкой построителе можно считать законченной, и мы переходим ко второй — Style (Стиль).

Данная вкладка используется для задания стиля отображения данных в таблице. Всего имеется пять различных стилей. Рядом расположено окно пpeдварительного просмотра. Выбрав желаемый, переходим к третьей вкладке Layout (Расположение).

По умолчанию заголовки столбцов совпадают с их именами. Ясно, что это не всегда удобно. Для переопределения заголовка используется поле ввода Caption (Наименование). Раскрывающийся список Control type (Тип элемента управления) содержит список объектов, которые могут отображаться в этом столбце. Некоторые из них в данный момент недоступны — это зависит от типа поля.

Открываем последнюю, четвертую вкладку построителя — Relationship (Отношения).

Здесь можно указать ключевое поле для главной (родительской) таблицы и индекс подчиненной (дочерней). Это, как ты уже догадался, применяется при создании объекта Grid для многотабличных форм.

Закончив манипуляции с построителем, разместим на вкладке нашей формы надписи и поле ввода для добавления записей в таблицу, расположив его ниже объекта Grid.

Для события Keypress объекта Text 11 запишем код:
Добавление записей в таблицу

1
2
3
4
5
6
7
8
9
10
11
LPARAMETERS Nkeycode, Nshiftaltctrl
IF Nkeycode=13 && ЭТО КОД КЛАВИШИ ENTER
DO CASE
CASE EMPTY (This.Value)=.F.
SELECT Countries
APPEND BLANK
REPLACE Ccountry WITH This.Value
This.Value=""
_SCREEN.ACTIVEFORM.REFRESH()
ENDCASE
ENDIF

Теперь рассмотрим создание объекта Grid “вручную”, без использования построителя. Сделаем Grid, отображающий справочник городов. Для этого откроем нашу форму в конструкторе форм, щелкнем мышью на объекте pageFramei, и войдем в режим редактирования, воспользовавшись соответствующей командой контекстного меню (Edit). Выбрав на панели инструментов кнопку Grid, разместим наш объект во втором контейнере и начнем настройку его свойств, используя окно Properties (Свойства).

Перейдем на вкладку Layout окна Properties. За отображение числа столбцов (Column) отвечает свойство coiumncount. По умолчанию данное свойство имеет значение -1 (поэтому в таблице поначалу как бы ничего и нет). Так как нам нужен всего один столбец, в котором будут отображаться только названия городов, мы установим данное свойство равным единице. Источником данных для нашего объекта будет таблица со списком городов cities.

Для того чтобы определить источник данных, перейдем на вкладку Data окна Properties и зададим значение для свойства RecordSource (Источник данных).

Как я уже и говорил, объект Grid включает в себя несколько объектов, т.e. j является контейнером. Нажми на кнопку в раскрывающемся списке окна Properties и ты увидишь, какие именно объекты входят в состав нашего Grid.

Column — это столбец. Кроме уже известного нам Coiumncount, данный объект имеет множество других свойств. Рассмотрим некоторые из них:
• controisource — определяет источник данных для столбца;
• Alignment — выравнивает информацию в столбце;
• coiumnOrder — определяет порядок отображения столбцов;
• Backcolor — определяет цвет фона.

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

Объект Header — это не что иное, как заголовок столбца. По умолчанию он называется так же, как и соответствующее поле таблицы, но заголовок можно легко изменить, задав значение свойства caption.

Объект Text — это тот элемент управления, который определяет, в каком виде будет выводиться информация. В данном случае это обычное поле ввода. В Grid для отображения информации могут использоваться такие элементы управления, как счетчик (spiner), флажок (checkbox), поле редактирования (EditBox), раскрывающийся список (ComboBox).

Таким образом, настроив необходимые свойства для нашего второго объекта Grid, добавим в форму поле ввода, с помощью которого будем добавлять в справочник городов новые наименования. Код для события Keypress будет такой же, как и в предыдущем случае, только вместо таблицы стран нужно указать таблицу городов cities и, соответственно, изменить название поля в команде Replace.

А теперь самостоятельно добавь в третий контейнер экранной формы еще один Grid, в котором будет располагаться справочник улиц. Также не забудь добавить поле для ввода нового значения.

Ну и что теперь делать? Как все это будет работать? Сейчас разберем.

Во-первых, для полей ввода, отвечающих за ввод фамилии, имени, отчества, даты рождения и дополнительной информации о клиенте, необходимо в качестве источника данных назначить соответствующие переменные памяти. Их имена будут совпадать с именами полей таблицы Names.dbf за одним лишь исключением — перед именем поля необходимо ставить префикс т.

А вот в качестве источника данных для полей, указывающих страну, город и улицу, укажем не переменные памяти, а сами имена полей из соответствующих таблиц. Да еще и сделаем данные поля доступными только для чтения
(ReadOnly=.T.).

Посмотрим, как будет работать форма на этом этапе? Давай только еще немного отредактируем свойства наших элементов Grid. Конкретно нас интересует событие AfterRowCoichange, которое наступает после того, как мы перейдем на другую строчку Grid. Так вот, в первом объекте Grid (где страны) для данного события пишем следующий код:

1
2
THISFORM.REFRESH    () && после перехода на другой ряд Grid
&& форма просто перерисовывается с новыми данными.

Для второго Grid (Города):

1
THISFORM.PAGEFRAME1.PAGE1.ТЕХТ5.REFRESH()

То есть во втором случае мы только обновляем информацию для поля ввода

1
Text5.

Ну и почти то же самое для третьего Grid:

1
THISFORM.PAGEFRAME1.PAGE1.TEXT6.REFRESH()

А сейчас мы сделаем программу, которая будет запускать наше будущее приложение. Для этого в окне диспетчера проекта перейди на вкладку Code (Код) и выбери пункт Programs (Программы). Нажми кнопку New (Новая). В открывшемся окне напиши код

1
2
3
4
5
6
7
8
9
SET TALK OFF
SET ECHO OFF
SET DATE TO GERMAN
SET PATH TO C:\OLDFOX\
OPEN DATABASE Oldfox
USE Names IN 1 EXCLUSIVE
USE Depclients IN 2 EXCLUSIVE
DO FORM Main
&& Main - это название файла нашей формы

Вот и все. Сохрани эту программу под любым именем, и теперь можешь попробовать запустить форму на выполнение и позаполнять наши справочники. Сначала заполняется справочник стран — тут все просто, в поле ввода набираешь название и нажимаешь . Затем, указав в этом Grid нужную страну, также заносишь данные в справочник городов для этой страны. Указав город, заносим название улиц этого города.

Таким образом, у нас уже имеется форма с тремя связанными и, что совсем уже удивительно, работающими объектами Grid.

Ну а как же все-таки добавлять записи в таблицу names, где у нас “фамилии, пароли, явки” и т.д.? Кнопка Новая запись может иметь примерно такой программный код для события click

Код события Click для кнопки Новая запись

1
2
3
SELECT names && переходим в рабочую область с таблицей names.dbf
SCATTER MEMVAR BLANK && создаем переменные памяти
THISFORM.REFRESH() && обновляем информацию в экранной форме

Ничего сложного. Немного сложнее с кнопкой Сохранить
Код события click для кнопки Сохранить

1
2
3
4
5
6
7
8
9
10
11
12
SELE Names
APPEND BLANK
GATHER MEMVAR
REPLACE Idcountry WITH Countries.Idcountry;
Ccountry WITH Countries.Ccountry
REPLACE Cstreet WITH Streets.Street
REPLACE Idcity WITH Cities.Idcity, Ccity WITH Cities.Ccity
REPLACE Idrooms WITH Rooms.Idroom
IE THISFORM.Pageframel.Pagel.Optiongroupl.Optionl.Value=l
REPLACE Csex WITH "M"
ELSE
UEPLACE Csex WITH "Ж" ENDIF

Но очевидно, что здесь необходимо каким-то образом предотвратить возможность ввода пустых записей в таблицу names. Один из вариантов — пробить значения полей ввода. Например, вот так

Проверка значения полей ввода

1
2
3
IF EMPTY(THISFORM.Pageframel.Pagel.Textl.Value)
-> = MESSAGEBOX("УКАЖИТЕ ФАМИЛИЮ КЛИЕНТА", "ОШИБКА...") ELSE
... <приведенный ранее код>... END IF

Как ты уже догадался, здесь Лис проверяет — а не забыл ли пользователь ввести фамилию клиента? Аналогичным способом можно осуществить проверку и других полей.

На второй вкладке нашей формы мы расположим информацию о тех клиентах, которые проживают в нашем отеле в настоящий момент.

Вторая вкладка нашей формы

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

Третья вкладка экранной формы

но нас в данный момент интересует совсем Другое обстоятельство — а откуда взялись записи в таблице с выбывшими клиентами (Depclients.dbf)? На второй вкладке нашей экранной формы есть кнопка Удалить запись. В нашем случае это будет означать, что при щелчке на этой кнопке запись о клиенте удаляется из таблицы names (клиент выехал) и добавляется в архив — таблицу depciients.

Код заполнения таблицы depciients

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
27
28
29
30
31
32
Объявляем локальную переменную (стоимость проживания в номере за сутки)
LOCAL Nroomprice
*переходим в рабочую область с таблицей
rooms SELЕСТ Rooms
* в таблице rooms переходим на запись с тем номером, где проживает клиент
LOCАТЕ FOR Idroom=Names.Idrooms
* присваиваем соответствующее значение нашей переменной
Nroomprice=Rooms .Nprice
*теперь переходим в таблицу
names SELECT Names
* создаем переменные памяти, в которых находится вся информация о текущей записи
SCATTER MEMVAR MEMO
* помечаем запись на удаление
DELETE
* переходим в рабочую область с таблицей
depclients SELECT Depclients
* добавляем пустую запись
APPEND BLANK
* заполняем ее значениями из таблицы
names GATHER MEMVAR MEMO
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
*переходим в рабочую область с таблицей
rooms SELЕСТ Rooms
* в таблице rooms переходим на запись с тем номером, где проживает клиент
LOCАТЕ FOR Idroom=Names.Idrooms
* присваиваем соответствующее значение нашей переменной
Nroomprice=Rooms .Nprice
*теперь переходим в таблицу
names SELECT Names
* создаем переменные памяти, в которых находится вся информация о текущей записи
SCATTER MEMVAR MEMO
* помечаем запись на удаление
DELETE
* переходим в рабочую область с таблицей
depclients SELECT Depclients
* добавляем пустую запись
APPEND BLANK
* заполняем ее значениями из таблицы
names GATHER MEMVAR MEMO
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* в таблице rooms переходим на запись с тем номером, где проживает клиент
LOCАТЕ FOR Idroom=Names.Idrooms
* присваиваем соответствующее значение нашей переменной
Nroomprice=Rooms .Nprice
*теперь переходим в таблицу
names SELECT Names
* создаем переменные памяти, в которых находится вся информация о текущей записи
SCATTER MEMVAR MEMO
* помечаем запись на удаление
DELETE
* переходим в рабочую область с таблицей
depclients SELECT Depclients
* добавляем пустую запись
APPEND BLANK
* заполняем ее значениями из таблицы
names GATHER MEMVAR MEMO
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* присваиваем соответствующее значение нашей переменной
Nroomprice=Rooms .Nprice
*теперь переходим в таблицу
names SELECT Names
* создаем переменные памяти, в которых находится вся информация о текущей записи
SCATTER MEMVAR MEMO
* помечаем запись на удаление
DELETE
* переходим в рабочую область с таблицей
depclients SELECT Depclients
* добавляем пустую запись
APPEND BLANK
* заполняем ее значениями из таблицы
names GATHER MEMVAR MEMO
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
*теперь переходим в таблицу
names SELECT Names
* создаем переменные памяти, в которых находится вся информация о текущей записи
SCATTER MEMVAR MEMO
* помечаем запись на удаление
DELETE
* переходим в рабочую область с таблицей
depclients SELECT Depclients
* добавляем пустую запись
APPEND BLANK
* заполняем ее значениями из таблицы
names GATHER MEMVAR MEMO
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* создаем переменные памяти, в которых находится вся информация о текущей записи
SCATTER MEMVAR MEMO
* помечаем запись на удаление
DELETE
* переходим в рабочую область с таблицей
depclients SELECT Depclients
* добавляем пустую запись
APPEND BLANK
* заполняем ее значениями из таблицы
names GATHER MEMVAR MEMO
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* помечаем запись на удаление
DELETE
* переходим в рабочую область с таблицей
depclients SELECT Depclients
* добавляем пустую запись
APPEND BLANK
* заполняем ее значениями из таблицы
names GATHER MEMVAR MEMO
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* переходим в рабочую область с таблицей
depclients SELECT Depclients
* добавляем пустую запись
APPEND BLANK
* заполняем ее значениями из таблицы
names GATHER MEMVAR MEMO
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* добавляем пустую запись
APPEND BLANK
* заполняем ее значениями из таблицы
names GATHER MEMVAR MEMO
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* заполняем ее значениями из таблицы
names GATHER MEMVAR MEMO
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* производим замену значения даты выезда на сегодняшнюю дату
REPLACE Ddepdate WITH DATE()
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* вычисляем количество прожитых в номере дней
REPLACE Ndays WITH Ddepdate-Darrdate
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* вычисляем полную стоимость проживания
REPLACE Ncost WITH Ndays*Nroomprice
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* опять переходим в область с таблицей
names SELECT Names
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* удаляем запись
PACK
* обновляем информацию в экранной форме
THISFORM.REFRESH
* обновляем информацию в экранной форме
THISFORM.REFRESH()

Тут поневоле вспоминаются триггеры и хранимые процедуры — ведь весь этот код можно было (с небольшими изменениями) занести в контейнер базы данных в виде триггера удаления. И еще одно дополнение — данный метод подходит в том случае, когда нам нужно “выселить” клиента раньше срока, ну допустим, кому-то срочно нужно выехать домой. А как быть с остальными?

Не искать же по всей базе данных (а в твоем пятизвездочном отеле уже ежедневно проживает по 15 тыс. человек) тех, у кого дата предполагаемого выезда совпадает с сегодняшним числом!

Конечно, нет. Достаточно немного изменить код и наша программа сама при каждом запуске будет удалять из базы данных необходимые записи.

Измененный код заполнения таблицы depclients

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SELECT Names
SCAN FOR Ddeptdate=DATE ()
LOCAL Nroomprice
SELECT Rooms
LOCATE FOR Idroom=Names.Idrooms
Nroomprice=Rooms.Nprice
SELECT Names
SCATTER MEMVAR MEMO
DELETE
SELECT Depclients
APPEND BLANK
GATHER MEMVAR MEMO
REPLACE Ndays WITH Ddepdate-Darrdate
REPLACE Ncost WITH Ndays*Nroomprice
SELECT Names
ENDSCAN
PACK
THISFORM.REFRESH ()

А если этот код еще и поместить в метод init нашей формы, то все получится именно так, как мы задумали. Но при этом есть и грустный момент — посмотри теперь на нашу форму.

Вид формы изменился при модификации кода приложения

Что случилось? Почему вместо Grid мы теперь видим какую-то белую “дыру? А это результат использования команды PACK. Более того, я тебя сейчас еще обрадую — тот же эффект мы будем наблюдать каждый раз, когда будем удалять записи из таблицы, являющейся источником данных для объек-3 та Grid. Избежать этого довольно просто, нужно сделать следующее: перед использованием команды удаления необходимо “очистить” источник данных для Grid, а потом восстановить его.

Очистка и восстановление Grid

1
2
3
4
SELECT Names
THISFORM.Pageframel.Page2.Gridl.Recordsource=.NULL.
PACK
THISFORM.Pageframel.Page2.Gridl.Recordsource="NAMES"

И еще одно замечание по этому поводу: в восстановленном объекте Gril столбцы будут отображаться в том порядке, в котором были расположена поля при создании таблицы. Отсюда вывод — если порядок отображения не соответствует желаемому, можно модифицировать таблицу, изменив порядок следования полей. Если же это невозможно, то следует назначать источник данных не для всего Grid, а отдельно для каждого столбца.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100