Практическая работа Создание таблиц
Практическая работа
Создание таблиц
Создадим базу данных для отдела кадров какого-нибудь предприятия. Какие данные на сотрудника нам понадобятся? Прежде всего, фамилия, имя и отчество. Затем укажем пол (мужской или женский), семейное положение (холост или женат/замужем), количество детей. Также понадобятся дата рождения и дата поступления на работу. Стаж работы в годах. Образование. Военнообязанный сотрудник, или нет. Телефоны, по которым можно связаться с сотрудником в любое время. Должность сотрудника и отдел (если есть), в котором он числится. А также его домашний адрес. При этом учитываем, что сотрудник не обязательно является жителем города, где он работает. А вдруг он приехал на заработки из другого города? Или даже из другой страны? Следовательно, придется вводить и страну, и город - вдруг потребуется делать отчет по сотрудникам, прописанным в Украине, например? Вот сколько данных нужно будет вводить для отдела кадров! А ведь мы еще немного упростили их. Стаж работы подразделяется на общий и непрерывный. Эти данные учитываются при расчете больничных листов. Но для учебной базы данных такими деталями можно пренебречь.
Итак, первым делом оптимизируем данные, исходя из правил трех нормальных форм. В результате получаем целых четыре таблицы:
Главной здесь будет таблица LichData, которая содержит основные данные о сотруднике. Она имеет релятивные связи с другими таблицами. Поле "Ключ" будет автоинкрементным, то есть автоматически будет прибавляться на единицу, гарантируя нам уникальность ключа. В подчиненных таблицах имеется поле "Сотрудник" целого типа, по которому будет обеспечиваться связь. Причем ключевых полей в дочерних таблицах не будет.
Главная таблица поддерживает связь один-к-одному с таблицами Doljnost и Adres, и связь один-ко-многим с таблицей Telephones, ведь у сотрудника наверняка есть и домашний, и рабочий телефоны, а в карманах, возможно, лежит пару мобильников. То есть, один сотрудник может иметь много телефонов.
С полями и связями определились, пора создавать базу данных.
Сейчас нам потребуется сделать четыре таблицы. Поэтому дважды щелкаем по команде "Создание таблицы в режиме конструктора", и переходим к конструктору. В левой части мы вводим имя поля, причем русскими буквами. В поле "Тип данных выбираем тип", а на вкладке "Общие" делаем настройки поля. Описание поля заполнять необязательно. Итак, создаем поля:
1. "Ключ". Разумеется, имя поля пишем без кавычек. Выбираем тип данных "Счетчик", это автоинкрементный тип данных. В настройках убедитесь, что поле индексированно - Да (Совпадения не допускаются). Правой кнопкой щелкните по этому полю и выберите команду "Ключевое поле". Слева от поля появится значок ключа.
2. "Фамилия". Тип поля текстовый, размер 25 символов. Индексированное поле - Да (Совпадения допускаются). Ведь могут же попасться родственники или однофамильцы!
3. "Имя". Тип поля текстовый, размер 25 символов. Индексированное поле - Да (Совпадения допускаются).
4. "Отчество". Тип поля текстовый, размер 25 символов. Индексы не нужны.
5. "Пол". Текстовый, размер 3 символа. В формате поля укажите "муж/жен", конечно, без кавычек.
6. "Сем_Полож". Логический тип, формат поля "Да/Нет". Здесь мы будем указывать, состоит ли сотрудник (сотрудница) в браке.
7. "Детей". Числовой тип, размер поля Байт (трудно представить, что у кого-то будет более 255 детей!).
8. "Дата_Рожд". Тип поля - Дата/Время. Выберите формат "Краткий форма даты". Затем выберите тот же формат для поля "Маска". При попытке выбора маски выйдет запрос на подтверждение сохранения таблицы. Ответьте утвердительно, а вместо имени таблицы по умолчанию "Таблица 1" впишите "LichData", так будет называться наша первая таблица. После этого появится окно создания маски ввода. Выберите "Краткий формат даты", нажмите "Далее", после чего в окне "Маска ввода" наберите "00.00.0000". В результате мы будем иметь маску в виде "дд.мм.гггг".
9. "Дата_Пост". Все то же самое, что и в №8.
10. "Стаж". Тип поля числовой, размер - байт.
11. "Образование". Текстовый, размер поля 30 символов. Ведь здесь может быть и длинный текст, например "неоконченное высшее техническое".
12. "Военнообязанный". Логический тип, формат "Да/Нет".
При попытке закрыть это окно, выйдет запрос о сохранении таблицы "LichData". Ответьте утвердительно. Главная таблица сделана, осталось еще три.
Снова щелкаем "Создание таблицы в режиме конструктора". Вводим такие поля:
1. "Сотрудник". Тип поля - числовой, размер поля - длинное целое. Делать это поле ключевым не нужно, даже после того, как при попытке закрыть таблицу Access предложит вам сделать поле ключевым.
2. "Отдел", Текстовое, 15 символов.
3. "Должность", Текстовое, 20 символов.
Закрываем таблицу, даем ей имя "ВоЦпозт.", отказываемся от создания ключа.
Делаем следующую таблицу. Поля:
1. "Сотрудник". Тип поля - числовой, размер поля - длинное целое. Не ключевое.
2. "Страна". Тип текстовый, размер 15.
3. "Город". Тип текстовый, размер 20.
4. "Дом_Адрес". Тип текстовый, размер 100.
Закрываем таблицу, даем имя "Adres", отказываемся от создания ключа.
Делаем следующую таблицу. Поля:
1. "Сотрудник". Тип поля - числовой, размер поля - длинное целое. Не ключевое.
2. "Телефон". Тип текстовый, размер 17. Желательно задать маску. Сразу же выйдет запрос о сохранении таблицы, сохраните ее под именем "Telephones". Для этого выбираем маску (дважды щелкаем по ней), в окне нажимаем кнопку "Список". Настраиваем маску, как на рисунке:
3. "Примечание". Тип текстовый, размер 10. Формат "Рабочий/Домашний/Мобильный". Закрываем таблицу "Telephones", отказываясь от создания ключевого поля.
Все, база данных готова. Программу MS Access можно закрыть, больше она не понадобится. Пока база данных еще пустая, желательно сделать резервную копию файла ok.mdb, который и является полученной базой данных. Как видите, никаких связей между таблицами мы не делали - проще будет сделать их в проекте программы.
Разработка главной формы
На форму помещаем три обычных панели. Свойству Align верхней панели присваиваем значение alTop (весь верх). Затем свойству Align нижней панели присваиваем значение alBottom. Затем помещаем компонент Splitter с вкладки Additional панели инструментов, и его свойству Align также присваиваем alBottom, после чего он прижался к нижней панели. Splitter - это разделитель между панелями. С его помощью пользователь мышью сможет передвигать нижнюю панель, меняя ее размеры. И, наконец, свойству Align средней панели присвоил значение alClient, чтобы она заняла все оставшееся место на форме. Не забудьте очистить свойство Caption всех трех панелей.
Далее на верхнюю панель помещаем три компонента RadioButton с вкладки Standard палитры компонентов. В их свойствах Caption, соответственно, "Адрес", "Телефоны" и "Должность". Переключаясь между ними, пользователь сможет выводить в нижнюю, подчиненную сетку DBGrid нужные данные. Свойству Checked первой радиокнопки присваиваем значение True, чтобы включить ее. Раздел с переключателями разделили компонентом Bevel с вкладки Additional палитры компонентов. Его ширину (свойство Width) сделали равным 2 пикселям, превратив его в вертикальную разделительную полосу.
Далее создаем раздел поиска, поместив в него обычные Label, Edit и кнопку BitBtn.
В последнем разделе верхней панели находятся еще две кнопки BitBtn. Одна из них предназначена для редактирования текущей записи, другая - для добавления новой.
Вторая и третья панели содержат только по одному компоненту DBGrid из вкладки DataControls палитры компонентов, свойствам Align которых присвоено значение alClient.
Свойству Name формы присвоено значение fMain, свойство Caption формы имеет текст "Отдел кадров", модуль сохранен под именем Main.pas, а проект в целом называется ok (отдел кадров).
Создание модуля данных и установление связи с базой данных
Далее в проект добавлен модуль данных (File -> New -> Data Module). Модуль данных - это не визуальный контейнер для размещения на нем не визуальных компонентов. В основном, он предназначен для размещения в нем компонентов подключения к данным (TDataBase, ADOConnection и т.п.), компонентов - наборов данных (TTable/ADOTable, TQuery/ADOQuery, TStoredProc/ADOStoredProc) и компонентов DataSource, которые обеспечивают связь наборов данных и компонентов отображения/редактирования данных. Также модуль данных часто используют и для хранения глобальных переменных, общих функций и процедур, которые должны быть видны по всей программе. Модуль данных не имеет формы, но сохраняется как модуль в файле *.pas.
Свойству Name модуля данных мы присвоим имя fDM, а модуль сохраним как DM.pas. Теперь самое интересное. Добавляем в модуль компонент ADOConnection с вкладки ADO палитры компонентов. Этот компонент обеспечит связь других компонентов с базой данных при помощи механизма ADO. Связь обеспечивается свойством компонента ConnectionString. В общем-то, у таких компонентов, как ADOTable тоже есть это свойство, однако, имея четыре таблицы, придется четыре раза устанавливать связь. Проще единожды соединиться компонентом ADOConnection и использовать его для связи других компонентов.
Приступим к делу. Щелкните дважды по свойству ConnectionString компонента ADOConnection. Откроется окно подключения компонента к ADO:
Здесь мы можем подключиться тремя способами:
1. Использовать для связи созданный ранее link-файл.
2. Вписать в поле "Use Connection String" строку для связи с ADO.
3. Сгенерировать эту строку, нажав кнопку Build.
Воспользуемся третьим способом - нажмем кнопку Build. Открывается новое окно, содержащее настройки подключения:
Вначале нам предлагается выбрать поставщика OLE DB, или иначе, указать нужный для подключения драйвер. Для связи с базой данных MS Access больше всего подходит "Microsoft Jet 4.0 OLE DB Provider". Jet - это название механизма работы с СУБД, встроенного в MS Access. Этот механизм поддерживает как собственные БД MS Access, имеющие расширение *.mdb, так и ODBC. Его и выделяем в списке.
Нажимаем на кнопку "Далее", либо переходим к вкладке "Подключение". Здесь нам нужно выбрать или ввести базу данных. Тут есть одно замечание. Если мы выберем базу данных, то есть, нажмем на кнопку с тремя точками, откроем диалог выбора и найдем там наш файл, то база данных будет привязана к указанному адресу. Если вы желаете поместить базу данных в какой-то определенной папке, то так и поступите. Однако если вы поместили файл с базой данных (в нашем случае ok.mdb) там же, где находится программа, и не желаете зависеть от определенной папки (ведь пользователь может переместить вашу программу), то нужно вручную вписать только имя файла с БД, без всякого адреса. В этом случае вы не сможете проверить подключение, нажав на кнопку "Проверить подключение". Ну и не надо, обойдемся без проверки. Укажите только имя файла - ok.mdb (вы ведь уже поместили этот файл в папку с проектом?). Нажмите на кнопку "ОК".
Закрываем окно редактора связей, и нам остается открыть подключение. Однако перед этим переведите свойство LoginPrompt компонента ADOConnection в False. Если этого не сделать, то при каждой попытке соединиться с базой данных будет выходить запрос на пользовательское имя и пароль, нам это не нужно, наша база данных без пароля. Теперь свойство Connected переведите в True. Если вам удалось это сделать, и не вышло никаких сообщений об ошибке, то подключение состоялось.
Пойдем дальше. Установите в модуль данных четыре компонента ADOTable, по одному на каждую таблицу из нашей базы данных. Компонент ADOTable (также как и TTable из вкладки BDE) предназначен для создания набора данных.
Набором данных (НД) называется группа записей, полученных такими компонентами, как TTable/ADOTable, TQuery/ADOQuery, TStoredProc/ADOStoredProc из одной или нескольких таблиц базы данных. Все компоненты наборов данных являются потомками класса TDBDataSet, и имеют много общих свойств, методов и событий. Эти компоненты также называют наборами данных.
Табличные компоненты (TTable/ADOTable) являются наборами данных, которые получают из базы данных полную копию одной из таблиц, и предоставляют полученный набор данных визуальным компонентам отображения данных (DBGrid, DBEdit, DBMemo и проч.).
Компоненты запросов (TQuery/ADOQuery) для получения набора данных из базы данных используют SQL-запрос. Компоненты позволяют получить из одной или нескольких таблиц только те данные, которые удовлетворяют запросу.
Выделите все четыре ADOTable (удерживая клавишу ), и в их свойстве Connection выберите нашу связь ADOConnection1. Таким образом, все четыре ADOTable мы подключили к базе данных.
Выделите первый компонент ADOTable. Переименуйте его свойство Name в TLichData, а в свойстве TableName выберите главную таблицу базы - LichData. Буква "Т" в начале названия компонента укажет нам в дальнейшем, что это таблица. Рядом с компонентом установите компонент DataSource из вкладки Data Access палитры компонентов. Компонент DataSource предназначен для организации связи с наборами данных, и служит посредником между такими компонентами НД, как ADOTable, ADOQuery и между компонентами отображения данных, например, DBGrid, DBEdit и т.п. Свойство Name компонента DataSource переименуйте в DSLichData (DS - DataSource). В свойстве DataSet выберите таблицу TLichData.
То же самое нужно проделать еще три раза, подключая аналогичным образом компоненты DataSource к другим таблицам:
Затем свойство Active таблиц переведите в True, открыв их. Для тех, кто пропустил предыдущий курс, напомню, что таблицы можно открывать и закрывать не только в Инспекторе Объектов, но и программно. Как открыть, так и закрыть таблицы можно двумя абсолютно равноценными способами:
//Открываем таблицы: fDM.TLichData.Open; fDM.TDoljnost.Active := True; //Закрываем их: fDM.TLichData.Close; fDM.TDoljnost.Active := False;
Пойдем далее. Перейдите на главную форму. Выберите команду File -> Use Unit и подключите к ней модуль DM. Теперь мы сможем видеть таблицы из главной формы.
На вкладке DataControls сосредоточены визуальные (видимые пользователю) компоненты отображения данных, такие как DBGrid (сетка, отображающая все данные НД в виде таблицы, и позволяющая редактировать их), DBEdit (поле редактирования данных, предназначенная для ввода или редактирования одного поля записи, то есть, ячейки таблицы), DBMemo (для редактирования MEMO-полей) и т.д. Единственным исключением является компонент DBNavigator. Этот компонент предназначен не для отображения данных, а для перемещения по записям набора данных, для вставки новой записи или удаления старой, для перевода НД в режим редактирования или для подтверждения сделанных изменений в наборе данных.
Выделите верхнюю сетку DBGrid, в ее свойстве DataSource выберите fDM.DSLichData. В таком же свойстве нижней сетки выберите fDM.DSAdres. Сетки среагировали, и вы можете видеть названия полей. Разумеется, таблица еще пуста, данных пока нет. Кстати, выделите обе сетки, и установите в True их свойства ReadOnly - только чтение. Таблицы ведь будут связаны, и нам не нужно, чтобы пользователь вводил данные фрагментарно. Мы для этого сделаем отдельную форму, а эти сетки нужны только для просмотра.
Установление связи между таблицами
Теперь нужно между таблицами установить связь. Это требуется не только для того, чтобы в нижней сетке выходили данные только на сотрудника, выделенного в верхней сетке, но и для того, чтобы мы смогли в дальнейшем вводить связанные данные в окне редактора. Снова выделите модуль данных. Щелкните дважды по первой таблице, чтобы открыть редактор полей. Правой кнопкой щелкните по этому редактору и выберите команду Add all fields (добавить все поля). В окне редактора полей появились все поля таблицы:
Редактор полей предназначен для настройки параметров каждого поля, для добавления новых полей или удаления имеющихся. Если в редакторе полей нет ни одного поля, то в компоненте DBGrid будут отображены все поля таблицы, имеющие параметры по умолчанию. Если же мы добавили в редактор полей хотя бы одно поле, то сетка DBGrid его и отобразит. В редакторе мы можем для каждого поля изменить различные параметры, например, ширину колонки, название колонки, видимое это поле или нет, и т.п. Кроме того, редактор полей предоставляет возможность добавлять в набор данных новые поля, например вычисляемые или просматриваемые (lookup). Но эту возможность мы будем рассматривать в других лекциях.
Поле "Ключ" у нас автоинкрементное, предназначено для связи с другими таблицами. Пользователю его видеть не обязательно. Выделите его, и в свойстве Visible установите False. Теперь для пользователя оно будет невидимым. Здесь у нас есть два логических поля - "Сем_Полож" и "Военнообязанный". Чтобы True и False выходили на экране так, как нам нужно, свойству DisplayValues первого из этих полей присвойте значение "Женат;Холост" (разумеется, без кавычек), а второго - "Да;Нет". Первым здесь идет значение, которое будет обозначать True, вторым - False. Эти значения разделяются точкой с запятой, пробелы не нужны.
Таким же образом добавьте все поля в остальные три таблицы. У них невидимым следует сделать поле "Сотрудник" - этому полю автоматически будет присвоено такое же число, как у поля Ключ соответствующей записи. Логических полей у них нет. Однако для поля "Телефон" таблицы Telephones следует изменить свойство EditMask. Щелкните по нему дважды, открыв редактор маски, и в поле Input Mask введите маску "#(###)-###-##-##". Сохраните ее, нажав кнопку ОК. Для полей типа Дата в этом свойстве (в таблице LichData два таких поля) введите маску "##.##.####".
Далее кнопкой перейдите в редактор кода. В нижней части окна вы можете увидеть вкладку Diagram, перейдите на нее. Нам с вами потребуется сделать такие связи:
Рис. 2.10. Связи базы данных
Для начала в окно диаграмм нужно добавить наши таблицы. Найдите их в окне дерева объектов Object TreeView. Если у вас это окно закрыто, откройте его клавишами либо командой меню View -> Object TreeView. Ухватитесь в этом окне мышью за название главной таблицы LichData {TLichData} и перетащите ее в окно диаграмм. Таблица вместе с полями отобразится в окне. Если бы ранее мы не добавили все поля в окне редактора полей компонента ADOTable, то здесь мы не увидели бы полей. Точно также перетащите остальные таблицы, как на рисунке. Связи главная - подчиненная делают кнопкой Master / Detail Connector, которую вы можете увидеть в верхней части окна диаграмм (предпоследняя). Нажмите на кнопку, затем подведите указатель мыши к боковой границе главной таблицы, нажмите левую кнопку и, удерживая ее, проведите линию к боковой границе таблицы Adres. Как только вы отпустите кнопку, появится окно связей:
Рис. 2.11. Окно связей
Здесь в поле Detail Fields нужно выбрать поле, по которому будет осуществляться связь, в нашем случае это поле "Сотрудник". В поле Master Fields выбираем ключевое поле "Ключ". Затем нажимаем кнопку Add и кнопку OK. Связь установлена.
При установке связей главный / подчиненный важно начинать вести линию с главной таблицы к подчиненной. Если бы мы сделали иначе, то главной таблицей стала бы TAdres. Такую же связь установите и с остальными таблицами. Просто, не правда ли?
Сохраните проект, скомпилируйте его и запустите на выполнение. Если в сетках главного окна вы видите открытые таблицы, то все хорошо. Если нет, возможно, при изменении настроек ваши таблицы закрылись. В таком случае закройте программу (но не проект!), выделите таблицы, и их свойству Active снова присвойте значение True. Таблицы должны появиться в сетках главного окна, даже на этапе проектирования.
Создание окна редактора
Пойдем дальше. Теперь нам нужно сделать окно редактора данных. Создайте новую форму (File -> New -> Form). Ее свойство Name переименуйте в fEditor, а при сохранении формы дайте модулю имя Editor. Командой File -> Use Unit подключите к форме модуль данных DM. Теперь нам нужно установить на форму такие компоненты:
Здесь поступаем следующим образом: установим на форму четыре панели GroupBox с вкладки Standard, на каждую таблицу свой GroupBox. В свойстве Caption компонента GroupBox впишите "Личные данные", это название отразится в заголовке панели. Далее на эту панель следует установить восемь компонентов DBEdit с вкладки DataControls палитры компонентов, два DBCheckBox для редактирования логических данных, и один компонент DBComboBox для списка. Поясняющие компоненты Label установите и настройте самостоятельно. Немного доработаем компонент DBComboBox. Щелкните дважды по его свойству Items, открыв редактор. В нем введите две строки:
муж жен
Сохраните текст, нажав кнопку ОК. Теперь пользователь сможет указать пол сотрудника, выбрав нужную строку из списка.
Для таблицы Doljnost все еще проще: на панели GroupBox всего два компонента DBEdit и два поясняющих Label.
Для таблицы Adres используйте три DBEdit.
А вот для таблицы Telephones понадобится один DBEdit, один DBComboBox, сетка DBGrid и кнопка BitBtn. Сетка нужна для контроля введенных телефонов, ведь здесь связь один-ко-многим, и телефонов может быть несколько. В редакторе Items компонента DBComboBox введите три строки:
Рабочий
Домашний
Мобильный
Теперь займемся подключением компонентов контроля. Удерживая , выделите все компоненты контроля на первой панели (все компоненты, кроме Label). В их свойстве DataSource выберите fDM.DSLichData, подключив компоненты к нужному набору данных (таблице). Снимите общее выделение, и выделите первый DBEdit. В его свойстве DataField выберите поле "Фамилия". Это свойство подключает выбранный компонент к определенному полю таблицы. Таким же образом подключите к соответствующим полям остальные компоненты. Затем подключайте компоненты других таблиц, каждое к своей таблице и к соответствующему полю. Сетка DBGrid подключается к fDM.DSTelephones, и не имеет поля, разумеется. Она отображает все видимые поля таблицы.
В правой нижней части для удобства пользователя устанавливается навигационный компонент DBNavigator с вкладки Data Controls. Этот компонент предназначен для перемещения по записям, включения режима редактирования записи, сохранения или отмены сделанных изменений, добавления новой записи или удаления существующей. В его свойстве DataSource устанавливается fDM.DSLichData, чтобы подключить компонент к главной таблице. Нам нужна от этого компонента только возможность перехода на начало или конец таблицы, на следующую или предыдущую запись. Поэтому раскройте его свойство VisibleButtons (видимость кнопок компонента) и переведите в False все кнопки, кроме nbFirst, nbPrior, nbNext и nbLast. Нажатие на эти кнопки приведет к вызову соответствующих методов компонента ADOTable. Эти методы делают следующее:
First - переход на первую запись таблицы. Prior - переход на предыдущую запись. Next - переход на следующую запись. Last - переход на последнюю запись.
Когда у DBNavigator останется всего четыре кнопки, эти кнопки окажутся вытянутыми. Уменьшите ширину компонента, чтобы кнопки приняли более привычный вид.
Измененная запись в таблице сохраняется в трех случаях:
1. Применением метода Post.
2. При переходе на другую запись.
3. При добавлении новой записи.
Когда мы, заполнив одну таблицу, перейдем к другой, то в первой таблице запись еще не будет сохранена. Поле "Ключ" у нас автоинкрементное, на него завязаны остальные таблицы. До тех пор, пока мы не сохраним запись, в этом поле не будет никакого значения. Следовательно, данные в других таблицах не смогут привязаться к какой-то записи главной таблицы. Поэтому выделите первый GroupBox, и дважды щелкните по событию onExit на вкладке Events инспектора объектов. Это событие происходит всякий раз, когда пользователь перейдет к другой панели GroupBox, либо к кнопкам, расположенным в нижней части окна. В сгенерированной процедуре впишите код:
{Вышли из редактирования LichData}
procedure TfEditor.GroupBox1Exit(Sender: TObject); begin
if fDM.TLichData.Modified then fDM.TLichData.Post;
end;
Свойство Modified компонента ADOTable имеет логический тип - в нем содержится True, если данные были изменены, и False в противном случае. Метод Post этого компонента, как уже упоминалось, сохраняет измененную запись таблицы. При этом в поле "Ключ" попадет присвоенное автоматически значение. Таким образом, введенный код означает, что если запись была изменена, то следует ее сохранить. Сгенерируйте событие onExit для оставшихся панелей GroupBox и таким же образом сохраните изменения записей в соответствующих таблицах.
Далее сгенерируйте событие нажатия на кнопку "Добавить" в GroupBox с телефонными данными. Этой кнопкой мы будем добавлять новые записи в таблицу, ведь один сотрудник может иметь более одного телефона. Код в процедуре будет такой:
if fDM.TTelephones.Modified then
fDM.TTelephones.Post; fDM.TTelephones.Append; DBEdit14.SetFocus;
Вначале мы сохраняем измененные значения, если они были. Затем методом Append мы добавляем в таблицу новую запись. Добавить новую запись можно двумя методами:
1. Append - добавляет новую запись в конец таблицы.
2. Insert - добавляет новую запись в текущее положение курсора.
После добавления новой записи таблица уже будет в режиме редактирования, поэтому можно не вызывать метод Edit, который переводит таблицу в этот режим. Далее мы переводит фокус ввода на DBEdit с телефонными номерами, чтобы пользователю не пришлось делать это самому.
В процедуре нажатия на кнопку "Сохранить и выйти" код простой:
if fDM.TLichData.Modified then
fDM.TLichData.Post; if fDM.TDoljnost.Modified then
fDM.TDoljnost.Post; if fDM.TAdres.Modified then
fDM.TAdres.Post; if fDM.TTelephones.Modified then
fDM.TTelephones.Post; Close;
Здесь мы лишь сохраняем изменения во всех таблицах, если они были, и закрываем окно. Напоследок у нас осталась кнопка "Добавить сотрудника". Что мы должны сделать, если пользователь нажмет на эту кнопку? Добавить новую запись в каждую таблицу и перевести курсор в первый DBEdit, в котором редактируется фамилия. Это и делаем:
fDM.TLichData.Append; fDM.TDoljnost.Append; fDM.TAdres.Append; fDM.TTelephones.Append; DBEdit1.SetFocus;
С этой формой мы закончили, переходим к главной форме. Не забывайте время от времени сохранять проект. Если вы еще не подключили модуль Editor к главной форме командой File -> Use Unit, то сделайте это сейчас, чтобы можно было вызывать окно редактора из главной формы. Начнем с кнопки "Новый сотрудник". Как и в предыдущем примере, нам потребуется добавить новую запись в каждую таблицу, после чего открыть окно редактора:
fDM.TLichData.Append; fDM.TDoljnost.Append; fDM.TAdres.Append; fDM.TTelephones.Append; fEditor.ShowModal;
Сгенерируйте процедуру опClick для кнопки "Редактировать". Тут будет лишь одна строчка кода:
fEditor.ShowModal;
В результате откроется окно редактора, и компоненты будут отображать данные текущей записи. Предположим, пользователю будет удобней дважды щелкнуть по записи в верхней сетке DBGrid, чем нажимать кнопку. Поэтому выделите сетку с главной таблицей и сгенерируйте для нее событие ondblclick. Там введите такую же строчку кода.
По нашему замыслу, при открытии программы в верхней сетке DBGrid будут отображаться данные из главной таблицы, а в нижней - из таблицы Adres. Также будет выделена радиокнопка с надписью "Адрес". Если пользователю захочется посмотреть должность или телефоны текущего сотрудника, он будет щелкать соответствующую радиокнопку, и эти данные должны быть отображены в нижней DBGrid. Выделите первую радиокнопку с надписью "Адрес" и сгенерируйте для нее событие onclick, которое будет возникать, когда пользователь щелкнет по ней. В процедуре этого события впишите следующий код:
if RadioButton1.Checked then
DBGrid2.DataSource := fDM.DSAdres;
Здесь мы проверили, включена ли данная радиокнопка. Если да, то мы меняем связь нижней сетки DBGrid и подключаем ее к таблице Adres. Ведь связь сетки с таблицей осуществляется через соответствующий компонент DataSource, а у нас их четыре. Подключаясь то к одному, то к другому DataSource, мы можем программно менять отображенную в сетке таблицу.
Для события onclick радиокнопки с надписью "Телефоны" код будет таким:
if RadioButton2.Checked then
DBGrid2.DataSource := fDM.DSTelephones;
А для события onclick радиокнопки с надписью "Должность", соответственно, код будет следующим:
if RadioButton3.Checked then
DBGrid2.DataSource := fDM.DSDoljnost;
Таким образом, в нижней сетке мы отображаем то одну, то другую подчиненную таблицу, и всякий раз в этих таблицах будут показаны данные текущего сотрудника. Вот и весь код! Сохраните проект и скомпилируйте его.
Создание таблиц
Создадим базу данных для отдела кадров какого-нибудь предприятия. Какие данные на сотрудника нам понадобятся? Прежде всего, фамилия, имя и отчество. Затем укажем пол (мужской или женский), семейное положение (холост или женат/замужем), количество детей. Также понадобятся дата рождения и дата поступления на работу. Стаж работы в годах. Образование. Военнообязанный сотрудник, или нет. Телефоны, по которым можно связаться с сотрудником в любое время. Должность сотрудника и отдел (если есть), в котором он числится. А также его домашний адрес. При этом учитываем, что сотрудник не обязательно является жителем города, где он работает. А вдруг он приехал на заработки из другого города? Или даже из другой страны? Следовательно, придется вводить и страну, и город - вдруг потребуется делать отчет по сотрудникам, прописанным в Украине, например? Вот сколько данных нужно будет вводить для отдела кадров! А ведь мы еще немного упростили их. Стаж работы подразделяется на общий и непрерывный. Эти данные учитываются при расчете больничных листов. Но для учебной базы данных такими деталями можно пренебречь.
Итак, первым делом оптимизируем данные, исходя из правил трех нормальных форм. В результате получаем целых четыре таблицы:
Главной здесь будет таблица LichData, которая содержит основные данные о сотруднике. Она имеет релятивные связи с другими таблицами. Поле "Ключ" будет автоинкрементным, то есть автоматически будет прибавляться на единицу, гарантируя нам уникальность ключа. В подчиненных таблицах имеется поле "Сотрудник" целого типа, по которому будет обеспечиваться связь. Причем ключевых полей в дочерних таблицах не будет.
Главная таблица поддерживает связь один-к-одному с таблицами Doljnost и Adres, и связь один-ко-многим с таблицей Telephones, ведь у сотрудника наверняка есть и домашний, и рабочий телефоны, а в карманах, возможно, лежит пару мобильников. То есть, один сотрудник может иметь много телефонов.
С полями и связями определились, пора создавать базу данных.
Сейчас нам потребуется сделать четыре таблицы. Поэтому дважды щелкаем по команде "Создание таблицы в режиме конструктора", и переходим к конструктору. В левой части мы вводим имя поля, причем русскими буквами. В поле "Тип данных выбираем тип", а на вкладке "Общие" делаем настройки поля. Описание поля заполнять необязательно. Итак, создаем поля:
1. "Ключ". Разумеется, имя поля пишем без кавычек. Выбираем тип данных "Счетчик", это автоинкрементный тип данных. В настройках убедитесь, что поле индексированно - Да (Совпадения не допускаются). Правой кнопкой щелкните по этому полю и выберите команду "Ключевое поле". Слева от поля появится значок ключа.
2. "Фамилия". Тип поля текстовый, размер 25 символов. Индексированное поле - Да (Совпадения допускаются). Ведь могут же попасться родственники или однофамильцы!
3. "Имя". Тип поля текстовый, размер 25 символов. Индексированное поле - Да (Совпадения допускаются).
4. "Отчество". Тип поля текстовый, размер 25 символов. Индексы не нужны.
5. "Пол". Текстовый, размер 3 символа. В формате поля укажите "муж/жен", конечно, без кавычек.
6. "Сем_Полож". Логический тип, формат поля "Да/Нет". Здесь мы будем указывать, состоит ли сотрудник (сотрудница) в браке.
7. "Детей". Числовой тип, размер поля Байт (трудно представить, что у кого-то будет более 255 детей!).
8. "Дата_Рожд". Тип поля - Дата/Время. Выберите формат "Краткий форма даты". Затем выберите тот же формат для поля "Маска". При попытке выбора маски выйдет запрос на подтверждение сохранения таблицы. Ответьте утвердительно, а вместо имени таблицы по умолчанию "Таблица 1" впишите "LichData", так будет называться наша первая таблица. После этого появится окно создания маски ввода. Выберите "Краткий формат даты", нажмите "Далее", после чего в окне "Маска ввода" наберите "00.00.0000". В результате мы будем иметь маску в виде "дд.мм.гггг".
9. "Дата_Пост". Все то же самое, что и в №8.
10. "Стаж". Тип поля числовой, размер - байт.
11. "Образование". Текстовый, размер поля 30 символов. Ведь здесь может быть и длинный текст, например "неоконченное высшее техническое".
12. "Военнообязанный". Логический тип, формат "Да/Нет".
При попытке закрыть это окно, выйдет запрос о сохранении таблицы "LichData". Ответьте утвердительно. Главная таблица сделана, осталось еще три.
Снова щелкаем "Создание таблицы в режиме конструктора". Вводим такие поля:
1. "Сотрудник". Тип поля - числовой, размер поля - длинное целое. Делать это поле ключевым не нужно, даже после того, как при попытке закрыть таблицу Access предложит вам сделать поле ключевым.
2. "Отдел", Текстовое, 15 символов.
3. "Должность", Текстовое, 20 символов.
Закрываем таблицу, даем ей имя "ВоЦпозт.", отказываемся от создания ключа.
Делаем следующую таблицу. Поля:
1. "Сотрудник". Тип поля - числовой, размер поля - длинное целое. Не ключевое.
2. "Страна". Тип текстовый, размер 15.
3. "Город". Тип текстовый, размер 20.
4. "Дом_Адрес". Тип текстовый, размер 100.
Закрываем таблицу, даем имя "Adres", отказываемся от создания ключа.
Делаем следующую таблицу. Поля:
1. "Сотрудник". Тип поля - числовой, размер поля - длинное целое. Не ключевое.
2. "Телефон". Тип текстовый, размер 17. Желательно задать маску. Сразу же выйдет запрос о сохранении таблицы, сохраните ее под именем "Telephones". Для этого выбираем маску (дважды щелкаем по ней), в окне нажимаем кнопку "Список". Настраиваем маску, как на рисунке:
3. "Примечание". Тип текстовый, размер 10. Формат "Рабочий/Домашний/Мобильный". Закрываем таблицу "Telephones", отказываясь от создания ключевого поля.
Все, база данных готова. Программу MS Access можно закрыть, больше она не понадобится. Пока база данных еще пустая, желательно сделать резервную копию файла ok.mdb, который и является полученной базой данных. Как видите, никаких связей между таблицами мы не делали - проще будет сделать их в проекте программы.
Разработка главной формы
На форму помещаем три обычных панели. Свойству Align верхней панели присваиваем значение alTop (весь верх). Затем свойству Align нижней панели присваиваем значение alBottom. Затем помещаем компонент Splitter с вкладки Additional панели инструментов, и его свойству Align также присваиваем alBottom, после чего он прижался к нижней панели. Splitter - это разделитель между панелями. С его помощью пользователь мышью сможет передвигать нижнюю панель, меняя ее размеры. И, наконец, свойству Align средней панели присвоил значение alClient, чтобы она заняла все оставшееся место на форме. Не забудьте очистить свойство Caption всех трех панелей.
Далее на верхнюю панель помещаем три компонента RadioButton с вкладки Standard палитры компонентов. В их свойствах Caption, соответственно, "Адрес", "Телефоны" и "Должность". Переключаясь между ними, пользователь сможет выводить в нижнюю, подчиненную сетку DBGrid нужные данные. Свойству Checked первой радиокнопки присваиваем значение True, чтобы включить ее. Раздел с переключателями разделили компонентом Bevel с вкладки Additional палитры компонентов. Его ширину (свойство Width) сделали равным 2 пикселям, превратив его в вертикальную разделительную полосу.
Далее создаем раздел поиска, поместив в него обычные Label, Edit и кнопку BitBtn.
В последнем разделе верхней панели находятся еще две кнопки BitBtn. Одна из них предназначена для редактирования текущей записи, другая - для добавления новой.
Вторая и третья панели содержат только по одному компоненту DBGrid из вкладки DataControls палитры компонентов, свойствам Align которых присвоено значение alClient.
Свойству Name формы присвоено значение fMain, свойство Caption формы имеет текст "Отдел кадров", модуль сохранен под именем Main.pas, а проект в целом называется ok (отдел кадров).
Создание модуля данных и установление связи с базой данных
Далее в проект добавлен модуль данных (File -> New -> Data Module). Модуль данных - это не визуальный контейнер для размещения на нем не визуальных компонентов. В основном, он предназначен для размещения в нем компонентов подключения к данным (TDataBase, ADOConnection и т.п.), компонентов - наборов данных (TTable/ADOTable, TQuery/ADOQuery, TStoredProc/ADOStoredProc) и компонентов DataSource, которые обеспечивают связь наборов данных и компонентов отображения/редактирования данных. Также модуль данных часто используют и для хранения глобальных переменных, общих функций и процедур, которые должны быть видны по всей программе. Модуль данных не имеет формы, но сохраняется как модуль в файле *.pas.
Свойству Name модуля данных мы присвоим имя fDM, а модуль сохраним как DM.pas. Теперь самое интересное. Добавляем в модуль компонент ADOConnection с вкладки ADO палитры компонентов. Этот компонент обеспечит связь других компонентов с базой данных при помощи механизма ADO. Связь обеспечивается свойством компонента ConnectionString. В общем-то, у таких компонентов, как ADOTable тоже есть это свойство, однако, имея четыре таблицы, придется четыре раза устанавливать связь. Проще единожды соединиться компонентом ADOConnection и использовать его для связи других компонентов.
Приступим к делу. Щелкните дважды по свойству ConnectionString компонента ADOConnection. Откроется окно подключения компонента к ADO:
Здесь мы можем подключиться тремя способами:
1. Использовать для связи созданный ранее link-файл.
2. Вписать в поле "Use Connection String" строку для связи с ADO.
3. Сгенерировать эту строку, нажав кнопку Build.
Воспользуемся третьим способом - нажмем кнопку Build. Открывается новое окно, содержащее настройки подключения:
Вначале нам предлагается выбрать поставщика OLE DB, или иначе, указать нужный для подключения драйвер. Для связи с базой данных MS Access больше всего подходит "Microsoft Jet 4.0 OLE DB Provider". Jet - это название механизма работы с СУБД, встроенного в MS Access. Этот механизм поддерживает как собственные БД MS Access, имеющие расширение *.mdb, так и ODBC. Его и выделяем в списке.
Нажимаем на кнопку "Далее", либо переходим к вкладке "Подключение". Здесь нам нужно выбрать или ввести базу данных. Тут есть одно замечание. Если мы выберем базу данных, то есть, нажмем на кнопку с тремя точками, откроем диалог выбора и найдем там наш файл, то база данных будет привязана к указанному адресу. Если вы желаете поместить базу данных в какой-то определенной папке, то так и поступите. Однако если вы поместили файл с базой данных (в нашем случае ok.mdb) там же, где находится программа, и не желаете зависеть от определенной папки (ведь пользователь может переместить вашу программу), то нужно вручную вписать только имя файла с БД, без всякого адреса. В этом случае вы не сможете проверить подключение, нажав на кнопку "Проверить подключение". Ну и не надо, обойдемся без проверки. Укажите только имя файла - ok.mdb (вы ведь уже поместили этот файл в папку с проектом?). Нажмите на кнопку "ОК".
Закрываем окно редактора связей, и нам остается открыть подключение. Однако перед этим переведите свойство LoginPrompt компонента ADOConnection в False. Если этого не сделать, то при каждой попытке соединиться с базой данных будет выходить запрос на пользовательское имя и пароль, нам это не нужно, наша база данных без пароля. Теперь свойство Connected переведите в True. Если вам удалось это сделать, и не вышло никаких сообщений об ошибке, то подключение состоялось.
Пойдем дальше. Установите в модуль данных четыре компонента ADOTable, по одному на каждую таблицу из нашей базы данных. Компонент ADOTable (также как и TTable из вкладки BDE) предназначен для создания набора данных.
Набором данных (НД) называется группа записей, полученных такими компонентами, как TTable/ADOTable, TQuery/ADOQuery, TStoredProc/ADOStoredProc из одной или нескольких таблиц базы данных. Все компоненты наборов данных являются потомками класса TDBDataSet, и имеют много общих свойств, методов и событий. Эти компоненты также называют наборами данных.
Табличные компоненты (TTable/ADOTable) являются наборами данных, которые получают из базы данных полную копию одной из таблиц, и предоставляют полученный набор данных визуальным компонентам отображения данных (DBGrid, DBEdit, DBMemo и проч.).
Компоненты запросов (TQuery/ADOQuery) для получения набора данных из базы данных используют SQL-запрос. Компоненты позволяют получить из одной или нескольких таблиц только те данные, которые удовлетворяют запросу.
Выделите все четыре ADOTable (удерживая клавишу
Выделите первый компонент ADOTable. Переименуйте его свойство Name в TLichData, а в свойстве TableName выберите главную таблицу базы - LichData. Буква "Т" в начале названия компонента укажет нам в дальнейшем, что это таблица. Рядом с компонентом установите компонент DataSource из вкладки Data Access палитры компонентов. Компонент DataSource предназначен для организации связи с наборами данных, и служит посредником между такими компонентами НД, как ADOTable, ADOQuery и между компонентами отображения данных, например, DBGrid, DBEdit и т.п. Свойство Name компонента DataSource переименуйте в DSLichData (DS - DataSource). В свойстве DataSet выберите таблицу TLichData.
То же самое нужно проделать еще три раза, подключая аналогичным образом компоненты DataSource к другим таблицам:
Затем свойство Active таблиц переведите в True, открыв их. Для тех, кто пропустил предыдущий курс, напомню, что таблицы можно открывать и закрывать не только в Инспекторе Объектов, но и программно. Как открыть, так и закрыть таблицы можно двумя абсолютно равноценными способами:
//Открываем таблицы: fDM.TLichData.Open; fDM.TDoljnost.Active := True; //Закрываем их: fDM.TLichData.Close; fDM.TDoljnost.Active := False;
Пойдем далее. Перейдите на главную форму. Выберите команду File -> Use Unit и подключите к ней модуль DM. Теперь мы сможем видеть таблицы из главной формы.
На вкладке DataControls сосредоточены визуальные (видимые пользователю) компоненты отображения данных, такие как DBGrid (сетка, отображающая все данные НД в виде таблицы, и позволяющая редактировать их), DBEdit (поле редактирования данных, предназначенная для ввода или редактирования одного поля записи, то есть, ячейки таблицы), DBMemo (для редактирования MEMO-полей) и т.д. Единственным исключением является компонент DBNavigator. Этот компонент предназначен не для отображения данных, а для перемещения по записям набора данных, для вставки новой записи или удаления старой, для перевода НД в режим редактирования или для подтверждения сделанных изменений в наборе данных.
Выделите верхнюю сетку DBGrid, в ее свойстве DataSource выберите fDM.DSLichData. В таком же свойстве нижней сетки выберите fDM.DSAdres. Сетки среагировали, и вы можете видеть названия полей. Разумеется, таблица еще пуста, данных пока нет. Кстати, выделите обе сетки, и установите в True их свойства ReadOnly - только чтение. Таблицы ведь будут связаны, и нам не нужно, чтобы пользователь вводил данные фрагментарно. Мы для этого сделаем отдельную форму, а эти сетки нужны только для просмотра.
Установление связи между таблицами
Теперь нужно между таблицами установить связь. Это требуется не только для того, чтобы в нижней сетке выходили данные только на сотрудника, выделенного в верхней сетке, но и для того, чтобы мы смогли в дальнейшем вводить связанные данные в окне редактора. Снова выделите модуль данных. Щелкните дважды по первой таблице, чтобы открыть редактор полей. Правой кнопкой щелкните по этому редактору и выберите команду Add all fields (добавить все поля). В окне редактора полей появились все поля таблицы:
Редактор полей предназначен для настройки параметров каждого поля, для добавления новых полей или удаления имеющихся. Если в редакторе полей нет ни одного поля, то в компоненте DBGrid будут отображены все поля таблицы, имеющие параметры по умолчанию. Если же мы добавили в редактор полей хотя бы одно поле, то сетка DBGrid его и отобразит. В редакторе мы можем для каждого поля изменить различные параметры, например, ширину колонки, название колонки, видимое это поле или нет, и т.п. Кроме того, редактор полей предоставляет возможность добавлять в набор данных новые поля, например вычисляемые или просматриваемые (lookup). Но эту возможность мы будем рассматривать в других лекциях.
Поле "Ключ" у нас автоинкрементное, предназначено для связи с другими таблицами. Пользователю его видеть не обязательно. Выделите его, и в свойстве Visible установите False. Теперь для пользователя оно будет невидимым. Здесь у нас есть два логических поля - "Сем_Полож" и "Военнообязанный". Чтобы True и False выходили на экране так, как нам нужно, свойству DisplayValues первого из этих полей присвойте значение "Женат;Холост" (разумеется, без кавычек), а второго - "Да;Нет". Первым здесь идет значение, которое будет обозначать True, вторым - False. Эти значения разделяются точкой с запятой, пробелы не нужны.
Таким же образом добавьте все поля в остальные три таблицы. У них невидимым следует сделать поле "Сотрудник" - этому полю автоматически будет присвоено такое же число, как у поля Ключ соответствующей записи. Логических полей у них нет. Однако для поля "Телефон" таблицы Telephones следует изменить свойство EditMask. Щелкните по нему дважды, открыв редактор маски, и в поле Input Mask введите маску "#(###)-###-##-##". Сохраните ее, нажав кнопку ОК. Для полей типа Дата в этом свойстве (в таблице LichData два таких поля) введите маску "##.##.####".
Далее кнопкой
Рис. 2.10. Связи базы данных
Для начала в окно диаграмм нужно добавить наши таблицы. Найдите их в окне дерева объектов Object TreeView. Если у вас это окно закрыто, откройте его клавишами либо командой меню View -> Object TreeView. Ухватитесь в этом окне мышью за название главной таблицы LichData {TLichData} и перетащите ее в окно диаграмм. Таблица вместе с полями отобразится в окне. Если бы ранее мы не добавили все поля в окне редактора полей компонента ADOTable, то здесь мы не увидели бы полей. Точно также перетащите остальные таблицы, как на рисунке. Связи главная - подчиненная делают кнопкой Master / Detail Connector, которую вы можете увидеть в верхней части окна диаграмм (предпоследняя). Нажмите на кнопку, затем подведите указатель мыши к боковой границе главной таблицы, нажмите левую кнопку и, удерживая ее, проведите линию к боковой границе таблицы Adres. Как только вы отпустите кнопку, появится окно связей:
Рис. 2.11. Окно связей
Здесь в поле Detail Fields нужно выбрать поле, по которому будет осуществляться связь, в нашем случае это поле "Сотрудник". В поле Master Fields выбираем ключевое поле "Ключ". Затем нажимаем кнопку Add и кнопку OK. Связь установлена.
При установке связей главный / подчиненный важно начинать вести линию с главной таблицы к подчиненной. Если бы мы сделали иначе, то главной таблицей стала бы TAdres. Такую же связь установите и с остальными таблицами. Просто, не правда ли?
Сохраните проект, скомпилируйте его и запустите на выполнение. Если в сетках главного окна вы видите открытые таблицы, то все хорошо. Если нет, возможно, при изменении настроек ваши таблицы закрылись. В таком случае закройте программу (но не проект!), выделите таблицы, и их свойству Active снова присвойте значение True. Таблицы должны появиться в сетках главного окна, даже на этапе проектирования.
Создание окна редактора
Пойдем дальше. Теперь нам нужно сделать окно редактора данных. Создайте новую форму (File -> New -> Form). Ее свойство Name переименуйте в fEditor, а при сохранении формы дайте модулю имя Editor. Командой File -> Use Unit подключите к форме модуль данных DM. Теперь нам нужно установить на форму такие компоненты:
Здесь поступаем следующим образом: установим на форму четыре панели GroupBox с вкладки Standard, на каждую таблицу свой GroupBox. В свойстве Caption компонента GroupBox впишите "Личные данные", это название отразится в заголовке панели. Далее на эту панель следует установить восемь компонентов DBEdit с вкладки DataControls палитры компонентов, два DBCheckBox для редактирования логических данных, и один компонент DBComboBox для списка. Поясняющие компоненты Label установите и настройте самостоятельно. Немного доработаем компонент DBComboBox. Щелкните дважды по его свойству Items, открыв редактор. В нем введите две строки:
муж жен
Сохраните текст, нажав кнопку ОК. Теперь пользователь сможет указать пол сотрудника, выбрав нужную строку из списка.
Для таблицы Doljnost все еще проще: на панели GroupBox всего два компонента DBEdit и два поясняющих Label.
Для таблицы Adres используйте три DBEdit.
А вот для таблицы Telephones понадобится один DBEdit, один DBComboBox, сетка DBGrid и кнопка BitBtn. Сетка нужна для контроля введенных телефонов, ведь здесь связь один-ко-многим, и телефонов может быть несколько. В редакторе Items компонента DBComboBox введите три строки:
Рабочий
Домашний
Мобильный
Теперь займемся подключением компонентов контроля. Удерживая
В правой нижней части для удобства пользователя устанавливается навигационный компонент DBNavigator с вкладки Data Controls. Этот компонент предназначен для перемещения по записям, включения режима редактирования записи, сохранения или отмены сделанных изменений, добавления новой записи или удаления существующей. В его свойстве DataSource устанавливается fDM.DSLichData, чтобы подключить компонент к главной таблице. Нам нужна от этого компонента только возможность перехода на начало или конец таблицы, на следующую или предыдущую запись. Поэтому раскройте его свойство VisibleButtons (видимость кнопок компонента) и переведите в False все кнопки, кроме nbFirst, nbPrior, nbNext и nbLast. Нажатие на эти кнопки приведет к вызову соответствующих методов компонента ADOTable. Эти методы делают следующее:
First - переход на первую запись таблицы. Prior - переход на предыдущую запись. Next - переход на следующую запись. Last - переход на последнюю запись.
Когда у DBNavigator останется всего четыре кнопки, эти кнопки окажутся вытянутыми. Уменьшите ширину компонента, чтобы кнопки приняли более привычный вид.
Измененная запись в таблице сохраняется в трех случаях:
1. Применением метода Post.
2. При переходе на другую запись.
3. При добавлении новой записи.
Когда мы, заполнив одну таблицу, перейдем к другой, то в первой таблице запись еще не будет сохранена. Поле "Ключ" у нас автоинкрементное, на него завязаны остальные таблицы. До тех пор, пока мы не сохраним запись, в этом поле не будет никакого значения. Следовательно, данные в других таблицах не смогут привязаться к какой-то записи главной таблицы. Поэтому выделите первый GroupBox, и дважды щелкните по событию onExit на вкладке Events инспектора объектов. Это событие происходит всякий раз, когда пользователь перейдет к другой панели GroupBox, либо к кнопкам, расположенным в нижней части окна. В сгенерированной процедуре впишите код:
{Вышли из редактирования LichData}
procedure TfEditor.GroupBox1Exit(Sender: TObject); begin
if fDM.TLichData.Modified then fDM.TLichData.Post;
end;
Свойство Modified компонента ADOTable имеет логический тип - в нем содержится True, если данные были изменены, и False в противном случае. Метод Post этого компонента, как уже упоминалось, сохраняет измененную запись таблицы. При этом в поле "Ключ" попадет присвоенное автоматически значение. Таким образом, введенный код означает, что если запись была изменена, то следует ее сохранить. Сгенерируйте событие onExit для оставшихся панелей GroupBox и таким же образом сохраните изменения записей в соответствующих таблицах.
Далее сгенерируйте событие нажатия на кнопку "Добавить" в GroupBox с телефонными данными. Этой кнопкой мы будем добавлять новые записи в таблицу, ведь один сотрудник может иметь более одного телефона. Код в процедуре будет такой:
if fDM.TTelephones.Modified then
fDM.TTelephones.Post; fDM.TTelephones.Append; DBEdit14.SetFocus;
Вначале мы сохраняем измененные значения, если они были. Затем методом Append мы добавляем в таблицу новую запись. Добавить новую запись можно двумя методами:
1. Append - добавляет новую запись в конец таблицы.
2. Insert - добавляет новую запись в текущее положение курсора.
После добавления новой записи таблица уже будет в режиме редактирования, поэтому можно не вызывать метод Edit, который переводит таблицу в этот режим. Далее мы переводит фокус ввода на DBEdit с телефонными номерами, чтобы пользователю не пришлось делать это самому.
В процедуре нажатия на кнопку "Сохранить и выйти" код простой:
if fDM.TLichData.Modified then
fDM.TLichData.Post; if fDM.TDoljnost.Modified then
fDM.TDoljnost.Post; if fDM.TAdres.Modified then
fDM.TAdres.Post; if fDM.TTelephones.Modified then
fDM.TTelephones.Post; Close;
Здесь мы лишь сохраняем изменения во всех таблицах, если они были, и закрываем окно. Напоследок у нас осталась кнопка "Добавить сотрудника". Что мы должны сделать, если пользователь нажмет на эту кнопку? Добавить новую запись в каждую таблицу и перевести курсор в первый DBEdit, в котором редактируется фамилия. Это и делаем:
fDM.TLichData.Append; fDM.TDoljnost.Append; fDM.TAdres.Append; fDM.TTelephones.Append; DBEdit1.SetFocus;
С этой формой мы закончили, переходим к главной форме. Не забывайте время от времени сохранять проект. Если вы еще не подключили модуль Editor к главной форме командой File -> Use Unit, то сделайте это сейчас, чтобы можно было вызывать окно редактора из главной формы. Начнем с кнопки "Новый сотрудник". Как и в предыдущем примере, нам потребуется добавить новую запись в каждую таблицу, после чего открыть окно редактора:
fDM.TLichData.Append; fDM.TDoljnost.Append; fDM.TAdres.Append; fDM.TTelephones.Append; fEditor.ShowModal;
Сгенерируйте процедуру опClick для кнопки "Редактировать". Тут будет лишь одна строчка кода:
fEditor.ShowModal;
В результате откроется окно редактора, и компоненты будут отображать данные текущей записи. Предположим, пользователю будет удобней дважды щелкнуть по записи в верхней сетке DBGrid, чем нажимать кнопку. Поэтому выделите сетку с главной таблицей и сгенерируйте для нее событие ondblclick. Там введите такую же строчку кода.
По нашему замыслу, при открытии программы в верхней сетке DBGrid будут отображаться данные из главной таблицы, а в нижней - из таблицы Adres. Также будет выделена радиокнопка с надписью "Адрес". Если пользователю захочется посмотреть должность или телефоны текущего сотрудника, он будет щелкать соответствующую радиокнопку, и эти данные должны быть отображены в нижней DBGrid. Выделите первую радиокнопку с надписью "Адрес" и сгенерируйте для нее событие onclick, которое будет возникать, когда пользователь щелкнет по ней. В процедуре этого события впишите следующий код:
if RadioButton1.Checked then
DBGrid2.DataSource := fDM.DSAdres;
Здесь мы проверили, включена ли данная радиокнопка. Если да, то мы меняем связь нижней сетки DBGrid и подключаем ее к таблице Adres. Ведь связь сетки с таблицей осуществляется через соответствующий компонент DataSource, а у нас их четыре. Подключаясь то к одному, то к другому DataSource, мы можем программно менять отображенную в сетке таблицу.
Для события onclick радиокнопки с надписью "Телефоны" код будет таким:
if RadioButton2.Checked then
DBGrid2.DataSource := fDM.DSTelephones;
А для события onclick радиокнопки с надписью "Должность", соответственно, код будет следующим:
if RadioButton3.Checked then
DBGrid2.DataSource := fDM.DSDoljnost;
Таким образом, в нижней сетке мы отображаем то одну, то другую подчиненную таблицу, и всякий раз в этих таблицах будут показаны данные текущего сотрудника. Вот и весь код! Сохраните проект и скомпилируйте его.