Форма поиска банка Primer. Часть 3. Добавляем диалоговые окна
Продолжаем формировать в демо-банке “Primer” управляющую форму для отбора кандидатов по заданным критериям.
Предыдущие статьи серии:
Сегодня займемся полями txtEducation
и txtCareer
, в которых должны
фиксироваться ограничения на направление образования кандидата
и занимаемые им в прошлом должности.
Для заполнения обоих полей будем использовать псевдословари, т.е.
выводимые в отдельном окне списки возможных значений: всех имеющихся
в банке значений характеристики ОБ4 - “Направление (специальность)”
для поля txtEducation
и характеристики ТД3 “Должность” для поля txtCareer
.
Нам необходимо создать сами диалоговые окна, заполнить их списками соответствующих значений и организовать работу пользователя: выбор значений, фиксацию выбора или отказ от фиксации. Поскольку функционал диалогового окна для обоих полей практически не отличается, мы создадим одну дополнительную форму и будем передавать в ее идентификатор нужной характеристики банка через таблицу параметров.
Далее следует организовать взаимодействие этого окна с главной формой, т.е.
получение от него выбранных пользователем значений и использование
этих значений в запросе.
Приступаем.
Создание диалогового окна
Внешний вид управляющей формы, реализующей диалоговое окно, представлен на рисунке:
Мы будем использовать элемент с именем listbox1
(класс ListBox)
для вывода списка значений, и две кнопки btnOk
и btnCancel
для фиксации выбора. В качестве дополнительного элемента используем
надпись labInfo
, в которой будем выводить информацию о количестве выбранных
на текущий момент значений списка.
Как и для основной формы зададим для нашего окна тип границы - “Окно диалога” и вид окна - “Всплывающее”. Кнопки размера окна отключим, и сделаем его модальным.
Заполняем список
После открытия окна нам необходимо заполнить список нужными значениями. подготовим функцию, которая выполняет эту работу:
function fill_list(field,selection)
В качестве параметров будем передавать в эту функцию идентификатор поля
field
в виде строки формата “<мнемокод базы=""><номер поля="">"
(например, "ОБ4" или "ТД3") и массив строк `selection` с перечнем значений,
которые должны быть отмечены в списке.номер>мнемокод>
function fill_list(field,selection)
Me.listbox1.ShowCheck = true
Me.listbox1:Clear()
local code, fnum = field:match("(%u%u)(%d+)")
local req = "ОТ "..code.."01 "..fnum.." УЗ"
local rs = GetBank():StringRequest(req)
local strings = {}
if rs and rs.Count > 0 then
for rec in rs.Records do
val = rec:GetValue(tonumber(fnum)):trim()
if val ~= "" then
table.insert(strings,vals[i])
end
end
table.sort(strings)
for i=1,#strings do
Me.listbox1:Add(strings[i])
if table.getkey(selection,strings[i]) then
Me.listbox1:SetItemChecked(Me.listbox1.ItemsCount)
end
end
end
if Me.listbox1.ItemsCount > 0 then
Me.listbox1.SelectedIndex = 1
end
end
Функция используя значение параметра field
формирует и
исполняет строчный запрос на отбор записей базы,
содержащих уникальные значения в указанном поле. Таким образом мы получаем
некое подобие индекса по данному полю: набор записей, в которых присутствуют все возможные значения данного поля, в т.ч. пустые, по одной записи для каждого значения.
Далее перебирая записи мы извлекаем из каждой значение нужного поля,
сортируем полученный массив по алфавиту и выводим в список listbox1
.
У значений, которые присутствуют в массиве selection
, устанавливается отметка.
Подготовим также обработчик события CheckStateChanged
списка. Будем выводить в надпись labInfo
сведения о количестве отмеченных в списке значений.
function listbox1_CheckStateChanged( event )
Me.labInfo.Text = "Выбрано: "..Me.listbox1.CheckedCount
end
Передаем параметры от главной формы в окно
Наше диалоговое окно будет использоваться для заполнения двух разных полей, а, значит, должно отображать разные списки значений. Информацию о том, какие именно значения нужно вывести в данный момент, будем передавать из главной формы через таблицу аргументов.
В главной форме объявим таблицу args
с полями field
, title
и selection
, в которые перед вызовом диалогового окна будем записывать идентификатор нужного поля, заголовок для окна и массив значений списка, которые следует отметить. Последний элемент будет задействован, если пользователь откроет окно, т.е. выполнит выбор значений поля, несколько раз. В этом случае в массив selection
будут записаны значения, выбранные в прошлый раз.
Например, для поля txtEducation
вызов диалогового окна будет выглядеть так:
args = {field = "ОБ4", title="Направления подготовки",selection = education}
GetBank():OpenForm("словарик",0,Me,args)
Здесь мы используем для заполнения поля selection массив education, в котором будем хранить выбранные пользователем значения списка в течение всего сеанса работы с формой поиска. Этот массив следует объявить в начале модуля формы.
Аналогичным образом будет выглядеть вызов окна для поля txtCareer
:
args = {field = "ТД3", title="Опыт работы",selection = career}
GetBank():OpenForm("словарик",0,Me,args)
Массив career
также нужно объявить в начале модуля формы.
В самом диалоговом окне переданные аргументы доступны нам через глобальную переменную Arg
. в обработчике события Load формы выполним анализ этих аргументов и используем их для заполнения списка:
function Форма_Load ( form, event )
if Arg and type(Arg.field) == "string" and Arg.field:match("%u%u%d+") then
if type(Arg.selection) ~= "table" then
Arg.selection = {}
end
fill_list(Arg.field, Arg.selection)
end
if Arg and Arg.title then
Me.Text = Arg.title
end
Me.ApplyControl = Me.btnOk
Me.CancelControl = Me.btnCancel
end
Здесь мы также назначили кнопки btnOk
и btnCancel
элементами, которые активируются при нажатии клавиш Enter и Esc.
Возвращаем результаты из окна в главную форму
Кога пользователь нажимает в диалоговом окне кнопки Ok или Отмена мы должны закрыть окно и сообщить главной форме о сделанном выборе. Для этого мы снова используем глобальную переменную Arg
окна.
Поскольку таблицы в Lua передаются по ссылке, то локальная переменная args
главной формы и глобальная переменная Arg
окна ссылаются на один и тот же объект в памяти. А значит, изменения, которые мы внесем в Arg
в модуле окна, будут видны в главной форме через args
.
Итак, создадим обработчики события Click для кнопок btnOk
и btnCancel
.
function btnOk_Click( control, event )
if Arg then
Arg.ModalResult = 1
Arg.selection = Me.listbox1.CheckedItems
end
Me:CloseForm()
end
function btnCancel_Click( control, event )
if Arg then
Arg.ModalResult = 0
end
Me:CloseForm()
end
В первом из них мы создаем в таблице Arg
новое поле с именем ModalResult
, записываем в него единицу и записываем в поле selection
таблицы Arg
массив отмеченных пользователем значений списка listbox1
, во втором - записываем в поле ModalResult
ноль.
В главной форме обработаем полученные результаты: если пользователь нажал Ok (поле ModalResult
таблицы аргументов содержит единицу), сохраним отмеченные им значения в массиве education (для поля txtEducation
) или career (для поля txtCareer
) и выведем в соответствующее поле формы список отмеченных значений.
if args.ModalResult == 1 then
education = args.selection
Me.txtEducation.Text = table.concat(education,"; ")
end
Приведем полностью листинг обработчиков нажатия кнопок выбора из списков:
function btnEducation_Click( control, event )
args = {field = "ОБ4", title="Направления подготовки",selection = education}
GetBank():OpenForm(2,0,Me,args)
if args.ModalResult == 1 then
education = args.selection
Me.txtEducation.Text = table.concat(education,"; ")
end
end
function btnCareer_Click( control, event )
args = {field = "ТД3", title="Опыт работы",selection = creer}
GetBank():OpenForm(2,0,Me,args)
if args.ModalResult == 1 then
career = args.selection
Me.txtCareer.Text = table.concat(career,"; ")
end
end
Обрабатываем закрытие окна
Обработаем также возможную попытку пользователя зарыть окно кнопкой в системном меню или заголовке формы. Для перехвата используем событие UnLoad формы, которое позволяет, помимо прочего, отменить операцию закрытия.
function Форма_UnloadForm( form, mode, event )
if mode == Form.UECloseScript then
return true
end
if not Arg or type(Arg.selection) ~= "table" then
return true
end
if #Arg.selection ~= Me.listbox1.CheckedCount or SelectionChanged() then
local answ = MsgBox("Сохранить изменения?",BtnYesNoCancel+IconQuestion)
if answ == IdCancel then
return false
end
if answ == IdYes then
Arg.ModalResult = 1
Arg.selection = Me.listbox1.CheckedItems
elseif answ == IdNo then
Arg.ModalResult = 0
end
end
return true
end
Если форма закрывается путем вызова метода CloseForm в скрипте (т.е. была нажата кнопка Ok или Cancel) или окно было отрыто без аргументов (т.е. не вызвано из главной формы, а открыто как самостоятельное), данный обработчик не выполняет никакой работы. В противном случае обработчик сравнивает массив изначально отмеченных элементов, переданных главной формой в Arg.selection
, с массивом отмеченных элементов списка listbox1
. Если они отличаются, предлагает сохранить изменения.
Функция SelectionChanged
вызывается лишь в том случае, если размеры массивов совпадают и возвращает true если различаются их элементы.
function SelectionChanged()
local items = Me.listbox1.CheckedItems
local n = Me.listbox1.CheckedCount
for i=1,n do
if not table.getkey(Arg.selection,items[i]) then
return true
end
end
return false
end
Включаем выбор пользователя в запрос
Добавим в функцию MakeRequest
код, включающий в строчный запрос условия на образование и опыт работы.
-- образование
if #education > 0 then
local tmp = {}
table.foreach(education, function(k,item) tmp[k] = "4 РВ "..item:quote([["]]) end)
conditions.edu = "ОБ02 "..table.concat(tmp, " ИЛИ ")
table.insert(conditions,"201 ОБ02")
end
Здесь мы создаем вспомогательный массив tmp, в который копируем все элементы из education
, заключая каждый из них кавычки и дописывая к нему слева номер поля “Направление (специальность)” базы “Образование” и вид сравнения “Равно”. Иными словами формируем набор условий для записей этой базы. Далее объединяя условия связкой ИЛИ, формируем и сохраняем в поле edu
таблицы conditions
критерий отбора для связанных записей базы ОБ, а в условия отбора для корневой базы “Лицо” добавляем элемент “201 ОБ02” (лицо связано по ссылке № 201 с записями базы “Образование”).
Таблица conditions
принимает примерно такой вид:
conditions = {
[1] = "9 МР 31.12.ГГГГ",
[2] = "9 БР 00.00.ГГГГ",
[3] = 201 ОБ02,
["edu"] = [[ОБ02 4 РВ "налоги" ИЛИ 4 РВ "экономика"]]
}
Аналогичные действий выполняем для массива career
:
-- опыт работы
if #career > 0 then
local tmp = {}
table.foreach(career, function(k,item) tmp[k] = "3 РВ "..item:quote([["]]) end)
conditions.career = "ТД03 "..table.concat(tmp, " ИЛИ ")
table.insert(conditions,"90 ТД03")
end
И включаем сформированные критерии отбора для связанных баз в запись запроса:
if conditions.edu then
req = req.." "..conditions.edu
end
if conditions.career then
req = req.." "..conditions.career
end
Полный текст функции MakeRequest
на данный момент:
function MakeRequest()
-- Формирование строчной записи запроса
local req = "ОТ ЛЦ01"
conditions = {}
-- возраст
if Me.txtAgeFrom.Text ~= "" then
local cur_year = DateTime.Now.Year
local val = tonumber(Me.txtAgeFrom.Text)
table.insert(conditions,"9 МР 31.12."..(cur_year - val))
end
if Me.txtAgeTo.Text ~= "" then
local cur_year = DateTime.Now.Year
local val = tonumber(Me.txtAgeTo.Text)
table.insert(conditions,"9 БР 00.00."..(cur_year - val))
end
-- образование
if #education > 0 then
local tmp = {}
table.foreach(education, function(k,item) tmp[k] = "4 РВ "..item:quote([["]]) end)
conditions.edu = "ОБ02 "..table.concat(tmp, " ИЛИ ")
table.insert(conditions,"201 ОБ02")
end
-- опыт работы
if #career > 0 then
local tmp = {}
table.foreach(career, function(k,item) tmp[k] = "3 РВ "..item:quote([["]]) end)
conditions.career = "ТД03 "..table.concat(tmp, " ИЛИ ")
table.insert(conditions,"90 ТД03")
end
-- стаж
AgeValidation({Control = Me.txtExperience})
if Me.txtExperience.Text ~= "" then
conditions.experience = tonumber(Me.txtExperience.Text)
end
if #conditions > 0 then
req = req.." "..table.concat(conditions," И ")
if conditions.edu then
req = req.." "..conditions.edu
end
if conditions.career then
req = req.." "..conditions.career
end
end
return req
end
Дополнительные материалы
- форма Словарик и текст ее модуля;
- текст модуля формы поиска на данный момент{: target=”_blank”}.
Страница создана на основе шаблона flexible-jekyll