Вступление

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

Перейдем к построению…

НА ЗАМЕТКУ! Для реализации данного примера нам потребуется возможность Qlik динамически изменять данные во внутренних таблицах макета. Для включения данной возможности нужно в меню «Settings\Document Properties» на вкладке «Server» включить галочку «Enable Dynamic Data Update».

Основной механизм изменения свойств объектов для данного примера остается прежним. Будем менять расположение объектов в процедуре VB. А вот чтобы Qlik понимал, какие объекты листа ему двигать и насколько, воспользуемся опять возможностью Клика – присваивать любой идентификационный код для объектов.

Итак, идея:

Когда мы хотим раскрыть блок с дополнительной информацией, самое главное, чтобы процедура понимала, на какую величину делать сдвиг. Чтобы не делать это константой, создадим специальный объект, высота которого и будет той самой величиной сдвига.
В нашем примере, для каждого блока такими объектами являются просто фоновые фреймы («Text Object» с синей рамкой), которые мы видим, когда раскрываем любой блок.

Чтобы QlikView различал такие объекты от других, придумаем для них особую кодировку в их «Object ID». В моем примере идентификатор таких объектов начинается с буквы «A» (Area — область блока). После буквы сразу идет цифра. Для небольшого количества раскрываемых блоков на листе достаточно будет всего одной цифры (номера блока), поэтому «Object ID» для фрейма первого блока пропишем «A1», для второго «A2» и т.д.
Остальные элементы, входящие в структуру блока, нужно тоже особым образом отделить от остальных объектов листа. Для объектов, на которые надо нажимать, чтобы раскрыть/скрыть детализацию блока, придумаем кодировку «Object ID», начинающуюся с буквы «B» (Button), а для всех прочих текстовых объектов, входящих в визуализацию блока — пусть первая буква в их «Object ID» будет «X», ну, и все остальные объекты блоков — закодируем с буквы «G».
Общая же, объединяющая характеристика всех таких объектов, участвующих в визуализации блоков будет то, что на второй позиции в их «Object ID» будет идти цифра (от 1 до 9), характеризующая, к какому именно блоку относится наш объект.

НА ЗАМЕТКУ! Это ключевое отличие от стандартных объектов QlikView, у которых «Object ID» формируется по умолчанию как две буквы и только с третьей позиции идут цифры.

Итак, приступим. Для управления свертыванием/развертыванием блоков нам потребуется в скрипте документа создать специальную таблицу, в которую будем записывать состояние свернуто/развернуто того или иного блока. Для нашего примера из трех блоков надо создать 4 поля в таблице:

Blocks:
LOAD * INLINE [
Block00, Block71,Block72,Block73
1,1,1,1
0,0,0,0
];

И создадим одну переменную:
LET vBlock = 0;

В названии полей для блоков после «Block» идет сначала цифра «7», а уже потом номер блока 1, 2 или 3. Эта цифра «7» взята из ID листа, на котором мы работаем с этим элементом, так как на других листах тоже можно создавать такую технологию и, следовательно, должны быть созданы соответствующие поля с неповторяющимися именами. Поэтому вторая цифра — это номер листа.

Создадим управляющий элемент для первого блока. Пусть это будет обычный «Text Object». Напишем в свойстве «Text» текст: «► Подробнее…». Настроим для него нужную высоту, цвет фона и цвет текста. А «Object ID» на вкладке «General» пропишем как «B1».

Создадим второй «Text Object» для фрейма первого блока. Для него не нужно прописывать ничего в свойстве «Text», а включим только рамку (на вкладке «Layout» включаем галочку «Use Borders»). Настроим для него нужную высоту и цвет фона (белый). «Object ID» на вкладке «General» пропишем как «A1».


Пример (А)

Теперь процедура MoveBlocks — это процедура, раскрывающая или скрывающая выбранный блок и передвигающая остальные объекты. Скопируйте её целиком в редактор VB:

(меню: Tools\Edit Module…)

SUB MoveBlocks

rem узнаем — на каком листе мы находимся
SheetId = ActiveDocument.GetLayout.ActiveSheetId
SheetId = Mid(SheetId,Len(SheetId),1)

rem узнаем — на какой блок детализации мы нажали
set v = ActiveDocument.GetVariable(«vBlock»)
pCurrentBlock = Int(v.GetContent.String)

rem узнаем — раскрывать или скрывать надо блок
FieldName = «Block» & SheetId & pCurrentBlock
set pv = ActiveDocument.Fields(FieldName).GetPossibleValues
pCommand = pv.Item(0).Text

rem находим для разворачивающегося/сворачивающегося блока его высоту детализирующей области
pMovePoint = 0
set sh = ActiveDocument.ActiveSheet
for i = 0 to sh.NoOfSheetObjects-1
set obj = sh.SheetObjects(i)
if Mid(obj.GetObjectId,1,11)=»Document\A»& pCurrentBlock then pMovePoint = obj.GetRect.Height
next

if pCommand = 0 then pMovePoint = -pMovePoint
pLowLevel = 0

rem двигаем все объекты блоков, расположенные ниже выбранного
for i = 0 to sh.NoOfSheetObjects-1
set obj = sh.SheetObjects(i)
ObjId = obj.GetObjectId
ObjId = Mid(ObjId, InStr(ObjId,»\»)+1)
Id = Mid(ObjId,2,1)
if InStr(«123456789»,Id)>0 then
Id = Int(Id)
else
Id = 0
end if

if (InStr(«XGBA»,Mid(ObjId,1,1)) > 0) AND (Id > pCurrentBlock) then
rect = obj.GetRect
rect.Top = rect.Top + pMovePoint
obj.SetRect rect
end if

rem по особому имени последнего элемента блоков определяем нижний уровень
if Mid(ObjId,1,2)=»B4″ then
pLowLevel = rect.Top + rect.Height
end if
next

rem когда нижняя граница всех панелей опускается ниже 518, то надо двигать все прочие объекты
rem иначе возвращаем все прочие объекты на свои места (в начальное состояние)
if pLowLevel <= 518 then
rem сдвига нет, ставим прочие объекты в начальное состояние
pLowLevel = 0
else
rem вычислили сдвиг для прочих объектов
pLowLevel = pLowLevel-518
end if

for i = 0 to sh.NoOfSheetObjects-1
set obj = sh.SheetObjects(i)
ObjId = obj.GetObjectId
ObjId = Mid(ObjId, InStr(ObjId,»\»)+1)
if Mid(ObjId,1,2)=»ZZ» AND InStr(ObjId,»/»)>0 then
rect = obj.GetRect
rect.Top = Mid(ObjId, InStr(ObjId,»/»)+1, 3) + pLowLevel
obj.SetRect rect
end if
if Mid(ObjId,1,2)=»HH» AND InStr(ObjId,»/»)>0 then
rect = obj.GetRect
rect.Height = Mid(ObjId, InStr(ObjId,»/»)+1, 3) + pLowLevel
obj.SetRect rect
end if
next

END SUB
Продолжаем…

Теперь можно прописывать действия на нашу кнопку «► Подробнее…». Заходим в свойства этого объекта и на вкладке «Actions» добавляем первую команду External\Dynamic Update и в поле ввода «Statement» пропишем следующее действие:
UPDATE Blocks SET Block71=1 WHERE Block71=0

Добавляем вторую команду External\Set Variable и вписываем в ячейки Variable: vBlock, с присвоением значения Value: 1 и последняя третья команда External\Run Macro , где в поле «Macro Name» впишем имя процедуры MoveBlocks.

Чтобы фрейм «A1» показывался только, когда первый блок раскрыт, для него на вкладке «Layout» нужно прописать «Conditional Block71=1»

НА ЗАМЕТКУ! Если вы прописали Conditional до того как попробовали нажать на кнопку «Подробнее..», с прописанными командами, то фрейм «A1» исчезнет, так как по умолчанию оба значения в поле «Block71» не равны единице. Но если на неё нажать, то фрейм снова появится.

Можно сделать так, чтобы визуально, после нажатия на кнопку «► Подробнее…», треугольник поворачивался вниз «▼». Для этого надо у этого объекта «B1» просто на вкладке «General» изменить «Text» на формулу:

=IF(Block71=1,,)&Подробнее...

Теперь о том, как скрыть блок.

Это можно реализовать двумя способами:

Способ 1.

Первое — сделать внутри фрейма первого блока кнопку «▲ свернуть». Как мы определили чуть ранее «Object ID» всех текстовых объектов внутри блоков кодируем начальной буквой «X», далее номер блока, после идет просто порядковый номер.

Таким образом, для объекта «▲ свернуть» на вкладке «General» пропишем «Object ID» как «X11».

Далее нужно прописать на вкладке «Actions» вот такой набор команд:

Первая команда:
External\Dynamic Update

и в поле ввода «Statement» пропишем действие:
UPDATE Blocks SET Block71=0 WHERE Block71=1

Вторая команда:
External\Set Variable
и вписываем в ячейки Variable: vBlock, с присвоением значения Value: 1

И третья команда:
External\Run Macro
где в поле «Macro Name» указываем ту же процедуру MoveBlocks

Способ 2.

Второе – сделать, чтобы кнопка, которая развернула блок, она же и сворачивала.

Для этого сначала добавим в скрипте ещё одну переменную:

LET vSet = 0;

После этого для кнопки «► Подробнее…» добавим четвертую команду: External\Set Variable

Указываем Variable: vSet, а в Value формулу: =IF(Block71=1,0,1) и передвинем эту команду на первое место! (кнопкой «Promote»).

А вторую команду (где у нас «Dynamic Update») перепишем так:
UPDATE Blocks SET Block71=€(vSet) WHERE Block71=1-€(vSet)

Вот теперь, эта же кнопка может и сворачивать блок.

Пример (Б)

Рассмотрим, как сделать второй блок. Перед тем как начинать делать второй блок, сверните первый!

НА ЗАМЕТКУ! Когда начинаем создавать третий блок, сворачиваем и первый и второй.

Снова создаем «Text Object» в качестве кнопки для раскрытия второго блока. Напишем для него в свойстве «Text» выражение:
=IF(Block72=1,, )&Распределение по странам

Настроим для него такую же нужную высоту, цвет фона и цвет текста как для первого элемента «B1».

На вкладке General пропишем «Object ID» как «B2».

На вкладке Actions пропишем аналогичные команды…

Первая команда:
External\Set Variable, указываем Variable: vSet, а в Value формулу: =IF(Block72=1,0,1)

Добавляем вторую команду:
External\Dynamic Update и в поле ввода «Statement» пропишем следующую команду:
UPDATE Blocks SET Block72=€(vSet) WHERE Block72=1-€(vSet)

Добавляем третью команду:
External\Set Variable и вписываем в ячейки Variable: vBlock, с присвоением значения Value: 2

И последняя четвертая команда External\Run Macro, где в поле «Macro Name» впишем имя процедуры MoveBlocks

Создадим «Text Object» для фрейма второго блока. Для него не нужно прописывать ничего в свойстве «Text», включим только рамочку (на вкладке «Layout» включаем галочку «Use Borders»). Настроим для него нужную высоту и цвет фона. «Object ID» на вкладке «General» пропишем как «A2».

Чтобы фрейм «A2» показывался только, когда второй блок раскрыт, для него на вкладке «Layout» нужно прописать Conditional Block72=1

Пример (В)

На этом сегодня все! До встречи в эфире!