Настройка внешнего вида Grid DataWindowАх, как же пользователи любят всякие «красивости» и «удобности»!
Да-да, те самые, которые мы, программисты, обычно называем «бантиками и рюшечками» и очень не любим делать.
Хотя, с другой стороны, пользуясь ПО не собственного производства, программисты нет-нет, да и проворчат:
что им, сложно, что ли было настройки окна запомнить?… Да, действительно, не так это и сложно, но,
как правило, просто лень. Но приходится. Ибо куда же мы денемся без нашего «любимого ненавистного юзверя»?
Вот и ублажаем его, делаем эти самые «бантики и рюшечки», а потом ими любуемся и гордимся. Вот и встала
однажды передо мной такая проблема: захотел пользователь, чтобы мог он в «таблице» (Grid DataWindow) не
нужные ему столбцы прятать, ширину столбцов выставлять, да не просто так, а чтобы при следующем его входе
в программу, все это восстанавливалось. И вот, как я это реализовал…
Создаем служебную таблицу
Для хранения настроек DW лучше всего использовать таблицу. Моя выглядела так:
CREATE TABLE dw_settings (
user_name char (50) NOT NULLf , -- имя пользователя
dw_ID char (50) NOT NULL , -- идентификатор DW для которого храним настройку
col_num int NOT NULL, -- порядковый номер столбца
col_name char (50) NOT NULL , -- имя столбца
col_head char (50) NULL , -- заголовок столбца (его может и не быть)
col_visible char (1) NOT NULL , -- видим / не видим
col_width int NOT NULL); -- ширина столбца
За тем на таблицу был создан PRIMARY KEY во избежание дублирования записей:
ALTER TABLE dw_settings ADD CONSTRAINT
PK_dw_settings PRIMARY KEY CLUSTERED
(
user_name,
dw_ID,
col_num
);
Размерность полей я устанавливал исходя из особенностей своего приложения, так что в Вашем случае она может быть иной.
Реализация в приложении
Я достаточно долго думал, как реализовать функциональность этого «бантика» с наименьшими затратами.
Установку видимости и порядка следования столбцов лучше всего делать, все-таки, в отдельном сервисном окне.
Значит, реализуем функционал там. Однако очевидно, что заставлять пользователя вручную, цифрами, подбирать нужную ему
ширину столбца, по крайней мере, не разумно. Но, с другой стороны, что делать, если пользователь загонит мышкой ширину
столбца в 0? Значит, эта часть имеет право жить в двух местах. Далее. Если в DW открыта возможность перетаскивания столбцов,
то опять же порядок следования нужно разрешить менять и там, и там. Ладно, разберемся «по ходу пьесы».
Рисуем DW
Для того чтобы визуализировать настройки пользователю, я создал не большое Grid DataWindow dw_state:
В выборке участвуют все поля из таблицы. В визуальной части оставлены следующие поля: col_num, col_head, col_visible и col_width.
В свойствах поля col_visible выставлен стиль отображения CheckBox, DataValue for On = 1, DataValue for Off = 0. Установлена
сортировка по полю col_num. Update Properties по умолчанию. Retrieval Arguments :user и :dw соотносятся с полями user_name и dw_ID
в условии WHERE SQL-запроса.
Создаем окно
Для того чтобы работать с DW, нужно положить его на окно. Ну что же, создаем окно. Тип окна – response, размеры и стили – на Ваше
усмотрение. На окне располагаем пять элементов управления: DataWindow Control и четыре CommandButton – одну на «Применить», другую
на «Закрыть окно», и две на «Вверх» и «Вниз». DataObject для DW соответственно dw_state. Добавим instance переменную окна window
w_target.
На открытии окна нам нужно получить параметры для Retrieve нашего dw_state. Параметрами в данном случае являются значения имени
пользователя и уникального идентификатора DW, для которого выполняется настройка внешнего вида. Имя пользователя мы (в данном случае,
для примера) возьмем из объекта транзакции, а идентификатор DW получим из глобального объекта Message (забегая вперед, уточню, что
в Message идентификатор попадет, когда мы будем вызывать окно настроек).
Event open
DataWindow dw_target
String ls_user, ls_dwID, ls, ls_state, ls_name, ls_title
Long n, m, ll_width
ls_user = sqlca.userid
dw_target = Message.PowerObjectParm
ls_dwID = dw_target.dataobject
// опускаю проверки
// получим количество столбцов в DW
m = integer(dw_target.Describe("DataWindow.Column.Count"))
dw_1.SetTransObject(sqlca)
if dw_1.Retrieve(ls_user, ls_dwID) <= 0 then
// если Retrieve не вернул ни одной строки
// значит пользователь впервые вызвал настройку
// для этого DW
// считаем текущие настройки DW
// получим ссылку на окно
w_target = w_mdi_frame.GetFirstSheet ( )
// пройдем в цикле по столбцам DW
for n = m to 1 step -1
ls = "#" + string(n) + ".name"
ls_name = dw_target.Describe(ls)
// принимаем за аксиому, что имя заголовка = имя поля + _t
ls_title = dw_target.Describe(ls_name + "_t.text")
// проверим ниличие загоовка и если его нет, подставим пустую строку
if ls_title = "!" then ls_title = ""
ls_state = dw_target.Describe(ls_name + ".visible")
ll_width = Long(dw_target.Describe(ls_name + ".width"))
dw_1.insertrow(1)
dw_1.object.user_name[1] = ls_user
dw_1.object.dw_name[1] = ls_dwID
dw_1.object.col_num[1] = long(n)
dw_1.object.col_name[1] = ls_name
dw_1.object.col_head[1] = ls_title
dw_1.object.col_visible[1] = ls_state
dw_1.object.col_width[1] = ll_width
next
else
// обновим значения ширины столбцов
// пройдем в цикле по столбцам DW
for n = m to 1 step -1
ls = "#" + string(n) + ".name"
ls_name = dw_target.Describe(ls)
ll_width = Long(dw_target.Describe(ls_name + ".width"))
dw_1.object.col_width[n] = ll_width
next
end if
End event
Реализуем функционал чередования
Теперь нужно реализовать функционал изменения порядка столбцов. Для этого закодируем события clicked на кнопках «Вверх»
«Вниз» и «Применить».
Кнопка «Вверх»:
Event clicked
Long ll_Row, ll_value
// получим текущую строку
ll_Row = dw_1.GetRow()
if ll_Row <= 1 then return
// вытянем номер из столбца col_num
ll_value = dw_1.object.col_num[ll_Row]
// поднимем строку вверх уменьшив номер на 1
dw_1.object.col_num[ll_Row] = ll_value – 1
// а для строки которая спустиась увеличим номер на 1 вернув ей старый «чужой» номер
dw_1.object.col_num[ll_Row - 1] = ll_value
// пересортируем dw
dw_1.SetSort(‘col_num ASC’)
dw_1.Sort()
// установим строку
dw_1.SetRow(ll_value - 1)
End event
Кнопка «Вниз»:
Event clicked
Long ll_Row, ll_value
// получим текущую строку
ll_Row = dw_1.GetRow()
if ll_Row >= dw_1.RowCount() then return
// вытянем номер из столбца col_num
ll_value = dw_1.object.col_num[ll_Row]
// поднимем строку вверх увеличив номер на 1
dw_1.object.col_num[ll_Row] = ll_value + 1
// а для строки которая поднялась уменьшим номер на 1 вернув ей старый «чужой» номер
dw_1.object.col_num[ll_Row + 1] = ll_value
// пересортируем dw
dw_1.SetSort(‘col_num ASC’)
dw_1.Sort()
// установим строку
dw_1.SetRow(ll_value + 1)
End event
Ну а для кнопки «Применить» пишем только одну строчку:
Кнопка «Применить»:
Event clicked
dw_1.Update()
End event
«Поднятие» настроек «подопытного» DW
Теперь нужно позаботиться о применении настроек к DW при открытии окна. Для этого реализуем в окне следующую функцию:
Function wf_SetState()
DataStore dt_stor
String ls_user, ls_command
Long n, m
ls_user = sqlca.userid
// создадим DataStore
dt_stor = create DataStore
// используем существующий Data Object
dt_stor.DataObject = "dw_state"
dt_stor.SetTransObject(sqlca)
// если DataStore не вернул ни одной строки,
// значит обработка не нужна
if dt_stor.Retrieve(ls_user, dw_1.DataObject) <= 0 then return
// отсортируем DataStore по порядку столбцов
dt_stor.SetSort('col_num ASC')
dt_stor.Sort()
// получим количество столбцов в DW
m = integer(dw_1.Describe("DataWindow.Column.Count"))
if m <> dt_stor.RowCount() then return // ошибка!
// спрячем от поьзователя наши действия
dw_1.SetRedraw(FALSE)
// скроем все столбцы
for n = 1 to dw_1.RowCount()
dw_1.Modify('#' + String(n) + ".visible = 0")
next
// установим ширину и покажем те столбцы,
// которые нужно
for n = 1 to dt_stor.RowCount()
ls_command = dt_stor.object.col_name[n]
ls_command += ".width="
ls_command += String(dt_stor.object.col_width[n])
ls_command = dw_1.Modify(ls_command)
ls_command = dt_stor.object.col_name[n]
ls_command += ".visible="
ls_command += String(dt_stor.object.col_visible[n])
ls_command = dw_1.Modify(ls_command)
next
// отобразим поьзователю содержимое DW
dw_1.SetRedraw(TRUE)
End function
Последний штрих
В событие open окна, на котором расположено DW после Retrieve нужно вызвать функцию wf_SetState() для установки настроек DW.
Рядом с DW нужно разместить кнопку «Настройка», чтобы пользователь мог вызвать окно настроек, а в обработке события clicked
напишем всего две строчки:
Event clicked
// откроем окно настроек и передадим ему DW в качестве параметра
openwithparm(w_state, dw_1)
// так как тип окна настроек – response, то дальнейшая обработка
// в этом сценарии будет происходить только после закрытия окна
// настроек, а значит можно перечитывать настройки DW
wf_SetState()
End event
|