Подчинённые поля со списком (ComboBox-ами) в ленточной (табличной) форме (+ Пример)
Работа со подчинёнными полями со списком (ComboBox-ами) в ленточной форме (обрабатывается 2 уровня подчинённости).
В базе данных хранятся только коды значений списков, а в ленточной форме поля со списком связаны с текстовыми значениями из временной таблицы, таким образом достигается сохранение отображаемых текстовых значений зависимых полей со списком (ComboBox-ов).
Процедура обновления временной таблицы находится в модуле: modForms_UPD - Процедура: RefreshForm_Штатное_Расписание().
* В Форме «Штатное_Расписание» столбец «Поле контроля» содержит значения ключей списков записанные в таблицу «Сотрудники».
* В таблице «ztemp_Table» поле «tempVal01» заполняется данными «Название Организации» только в целях дальнейшей сортировки по этому полю.
* Запросы «frmШтатное_Расписание_UPD_01 ... 04» - сохранены только для наглядности примера и в процедуре RefreshForm_Штатное_Расписание() не задействованы.
* Автоматическое пополнение справочников при вводе в списки новых значений
* Фильтрация формы по двум полям
* Автоподстановка значений полей по данным полей фильтрации, т.е. если отфильтровано название предприятия то оно применяется автоматически.
* Выбор поля сортировки формы
* Перемещение по записям как в таблице (клавишами вверх и вниз).
* Редакция или удаление уже существующих значений справочников (элементов списков).
Обычно, в поле со списком, мы связываем с данными «Ключ» (ID записи), а в поле отображаем текстовое значение по этому ключу.
При использовании подчинённых полей со списком мы меняем его свойство «Источник записей» (RowSource) в зависимости от значения другого поля в форме, но при использовании в ленточной форме, изменение свойства RowSource у одного поля, приводит к изменению его у всех ComboBox-ов ПО ВСЕМ записям формы и ОТОБРАЖАЕМЫЕ текстовые значения полей в других записях «Слетают».
Выход — это хранить в БД кроме Ключа (ID) и его текстового значение для отображения в ленточной (табличной) форме, а это нам не нужно и совсем не экономично.
В примере для хранения текстовых значений ComboBox-ов используется временная таблица «ztemp_Table» и данные в них «развёрнуты» наоборот, т.е.:
* Первое поле списка: Текстовое значение записи из источника строк
* Второе поле списка: Ключ (ID) записи из источника строк
* Кол-во столбцов: 2
* Ширина столбцов поля (допустим): 8cm;0cm
* Связанный столбец: 1
А как же ключ значения?
А Ключ (ID) записываем в нужное нам поле рабочей таблицы по событию «После Обновления» ComboBox-а, вот и вся «механика».
* Таблица «atpTableModel»: Шаблон временной таблицы
* Таблица «ztemp_Table»: Временная таблица для хранения текстовых значений ComboBox-ов – подключается из временной БД, смотрите модуль «modDBTemp»
* Таблица «Должности»: Справочник должностей сотрудников, подчинённо связан с таблицей «Отделы»
* Таблица «Организации»: Справочник организаций
* Таблица «Отделы»: Справочник отделов организаций, подчинённо связан с таблицей «Организации»
* Таблица «Сотрудники»: Список сотрудников по разным организациям, расписанные по разным отделам и на разных должностях.
* Запрос «frmШтатное_Расписание»: Источник записей для формы «frmШтатное_Расписание», и обратите внимание как там устроена связь между таблицами «Сотрудники» и «ztemp_Table»
* Запросы «frmШтатное_Расписание_UPD_00 ... 04» сохранены только для наглядности примера и нигде, в коде, не задействованы. Служат для тестового заполнения таблицы «ztemp_Table» данными, те-же действия выполняет процедура «RefreshForm_Штатное_Расписание» из модуля «modFormsTempDataUPD»
* Формы «Должности», «Организации», «Отделы»: Для Редактирования - удаления данных соответствующих справочников.
* Форма «Штатное_Расписание»: Основной пример.
* Форма «Штатное_Расписание_Простая»: Облегчённый пример, просто для упрощения понимания сути примера.
Для чёткого определения что пользователь вносил изменения в ComboBox-ы создаём переменную для хранения значений до редакции.
Private Type Old_ID_Values
ID01 As Long
ID02 As Long
ID03 As Long
End Type
Private OldVal As Old_ID_Values
Private Sub Form_Current()
OldVal.ID01 = Nz(Me!Орг_IDN)
OldVal.ID02 = Nz(Me!Отд_IDN)
End Sub
На открытии формы «Штатное_Расписание_Простая» заполняем временную таблицу текстовыми данными.
Private Sub Form_Open(Cancel As Integer)
Dim s As String
RefreshTempData_Сотрудники
s = "SELECT ОргНазвание, Организация_ID FROM Организации ORDER BY ОргНазвание;"
Me!cbОрганизацияНазвание.RowSource = s
Me!cbОрганизацияНазвание.ControlSource = "tempVal01"
Me!cbОрганизацияНазвание.ColumnCount = 2
Me!cbОрганизацияНазвание.BoundColumn = 1
Me!cbОрганизацияНазвание.ColumnWidths = "4536;0"
s = "SELECT ОтдНазвание, Отдел_ID FROM Отделы WHERE (Организация_IDN=[Forms]![Штатное_Расписание_Простая]![Орг_IDN]) ORDER BY ОтдНазвание;"
Me!cbОтделНазвание.RowSource = s
Me!cbОтделНазвание.ControlSource = "tempVal02"
Me!cbОтделНазвание.ColumnCount = 2
Me!cbОтделНазвание.BoundColumn = 1
Me!cbОтделНазвание.ColumnWidths = "4536;0"
s = "SELECT ДлжНазвание, Должность_ID FROM Должности WHERE (Отдел_IDN=[Forms]![Штатное_Расписание_Простая]![Отд_IDN]) ORDER BY ДлжНазвание;"
Me!cbДолжностьНазвание.RowSource = s
Me!cbДолжностьНазвание.ControlSource = "tempVal03"
Me!cbДолжностьНазвание.ColumnCount = 2
Me!cbДолжностьНазвание.BoundColumn = 1
Me!cbДолжностьНазвание.ColumnWidths = "4536;0"
End Sub
Для корректного отображения списка значений на Получение фокуса подчинёнными ComboBox-ми обновляем их источники строк.
Private Sub cbОтделНазвание_GotFocus()
Me!cbОтделНазвание.Requery
End Sub
Private Sub cbДолжностьНазвание_GotFocus()
Me!cbДолжностьНазвание.Requery
End Sub
При обновлении значения в каждом ComboBox-е сохраняем выбранное ID и обновляем подчинённые контроли.
Private Sub cbОрганизацияНазвание_BeforeUpdate(Cancel As Integer)
If Me!cbОрганизацияНазвание.ListIndex = -1 Then
Me!Орг_IDN = 0
Else
Me!Орг_IDN = Me!cbОрганизацияНазвание.Column(1)
End If
If OldVal.ID01 <> Me!Орг_IDN Then
Me!Отд_IDN = 0
Me!cbОтделНазвание = Null
Me!Долж_IDN = 0
Me!cbДолжностьНазвание = Null
OldVal.ID01 = Me!Орг_IDN
End If
End Sub
Private Sub cbОтделНазвание_BeforeUpdate(Cancel As Integer)
If Me!cbОтделНазвание.ListIndex = -1 Then
Me!Отд_IDN = 0
Else
Me!Отд_IDN = Me!cbОтделНазвание.Column(1)
End If
If OldVal.ID02 <> Me!Отд_IDN Then
Me!Долж_IDN = 0
Me!cbДолжностьНазвание = Null
OldVal.ID02 = Me!Отд_IDN
End If
End Sub
Private Sub cbДолжностьНазвание_AfterUpdate()
If Me!cbДолжностьНазвание.ListIndex = -1 Then
Me!Долж_IDN = 0
Else
Me!Долж_IDN = Me!cbДолжностьНазвание.Column(1)
End If
End Sub
Вот и весь необходимый минимум, остальные «фишки» смотрите в форме «Штатное_Расписание».
MSA-2003 + MSA-2007 ( 346 kB) Пример
|