Вступление
Часто размерностей, задающих фильтрацию и отбор данных в проекте, бывает очень много и встает вопрос, как разместить такое количество объектов выбора одновременно и в тоже время компактно… Об одном из таких подходов и пойдет далее пример. В нём мы выделим правую вертикальную полоску экрана для полного списка, имеющихся в проекте размерностей, а когда будем нажимать на название, то будет появляться уже сам объект выбора, причём предыдущий открытый объект выбора по другой размерности будет сворачиваться для экономии места.
НА ЗАМЕТКУ! Для реализации данного примера нам потребуется возможность клика динамически изменять данные во внутренних таблицах макета. Для включения данной возможности нужно в меню «Settings\Document Properties» на вкладке «Server» включить галочку «Enable Dynamic Data Update».
Итак, приступим.
Для управления свертыванием/развертыванием меню нам потребуется в скрипте документа создать специальную таблицу, в которую будем записывать состояние выбрана/не выбрана та или иная размерность в нашем меню. Для нашего примера из десяти меню выбора размерностей надо создать 11 полей в таблице:
1 2 3 4 5 6 7 8 9 |
LMenu: LOAD * INLINE [ _LMenu00, _LMenu01,_LMenu02,_LMenu03,_LMenu04,_LMenu05,_LMenu06,_LMenu07, (в той же первой строке... продолжить) _LMenu08,_LMenu09,_LMenu10 1,1,1,1,1,1,1,1,1,1,1 0,0,0,0,0,0,0,0,0,0,0 ]; |
И создадим одну переменную:
1 |
LET vCurrentLMenu = 0; |
Элементы выбора меню по нашим размерностям реализуем с помощью «Text Object».
Создадим первый такой «Text Object». В качестве «Text» напишем штрих-код.
Слегка доработаем объект, чтобы он походил на меню выбора…
Продолжаем на вкладке General параметр «Horizontal Alignment» выберем «Left».
Для визуального выделения, что меню выбрано, настроим цвет фона объекта. Зайдём в настройки цвета «Background Color» и выберем, как в нашем примере, тип цвета «Two Colors Gradient». Первый цвет (Base Color) выберем как расчетный (Calculated) и пропишем следующую формулу:
1 |
IF( _LMenu01=1, RGB(214,74,85), RGB(224,224,200)) |
Для второго цвета (Second Color) аналогично выберем «Calculated» и пропишем:
1 |
IF( _LMenu01=1, RGB(175,54,54), RGB(182,182,166)) |
Для лучшего управления проектом в будущем, все константы цвета, используемые в формулах, лучше вынести в переменные, которые потом, при необходимости можно легко изменять. Для этого пропишем эти константы:
1 2 3 4 5 6 |
LET cLMenuSelect_top = `RGB(214,74,85)`; LET cLMenuSelect_down = `RGB(175,54,54)`; LET cLMenuNoSelect_top = `RGB(224,224,200)`; LET cLMenuNoSelect_down = `RGB(182,182,166)`; LET cLMenuSelect_font = `RGB(255,255,255)`; LET cLMenuNoSelect_font = `RGB(0,0,0)`; |
(последние две переменные — будем использовать для цвета текста размерностей на меню)
С учетом введенных переменных, формула «Base Color» станет такой:
1 2 3 |
IF( _LMenu01=1, €(cLMenuSelect_top), €(cLMenuNoSelect_top)) и для "Second Color": IF( _LMenu01=1, €(cLMenuSelect_down), €(cLMenuNoSelect_down)) |
На вкладке Fonts:
Выберем шрифт: Tahoma, полужирный, 9.
А цвет шрифта — выберем «Solid Color», расчетный (Calculated) и пропишем следующую формулу:
IF( _LMenu01=1, €(cLMenuSelect_font), €(cLMenuNoSelect_font))
Высоту объекта сделаем поменьше, например 26 пикселей.
Получили пример (А).
Теперь самое главное: чтобы динамически менять у объектов клика параметры, мы воспользуемся встроенным Visual Basic и напишем на нём пару процедур. Войдем в редактор Visual Basic, выберем в меню «Tools\Edit Module…».
В окне редактора на левой панели настроек выберем: «VBScript». Параметр «Requested Module Security» выберем «System Access», а параметр «Current Local Security» — «Allow System Access».
Первая процедура — это процедура, раскрывающая выбранный объект при выборе меню и передвигающая остальные объекты на свои места. Скопируйте её целиком в редактор VB:
(меню: Tools\Edit Module…)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
SUB SelectLMenu Distance = 1 rem (зазор в пикселях между объектами-названиями размерностей) NameSheetID = ActiveDocument.GetLayout.ActiveSheetId NameSheetID = Mid(NameSheetID, InStr(NameSheetID,"\")+1) set v = ActiveDocument.GetVariable("vCurrentLMenu") CurrentLMenu = Int(v.GetContent.String) set sh = ActiveDocument.ActiveSheet FoundM = 0 for m = 1 to 10 iFrame = -1 for i = 0 to sh.NoOfSheetObjects-1 set obj = sh.SheetObjects(i) Id = obj.GetObjectId Id = Mid(Id, InStr(Id,"\")+1) if m<=9 then NameObjectLMenu = "LM0" & m & NameSheetID NameObjectFRame = "FR0" & m & NameSheetID else NameObjectLMenu = "LM" & m & NameSheetID NameObjectFRame = "FR" & m & NameSheetID end if rem (если FR встретился раньше, чем LM, то запоминаем его номер) IF Mid(Id,1,8)=NameObjectFRame AND FoundM < m THEN iFrame = i END IF rem (нашли объект меню LM) IF Mid(Id,1,8)=NameObjectLMenu THEN rect = obj.GetRect if m=1 then rect.Top = 110 else rect.Top = CurrentY + Distance obj.SetRect rect CurrentY = rect.Top + rect.Height FoundM = m rem (если FR уже найден, то ставим его на место) IF iFrame > -1 THEN set obj = sh.SheetObjects(iFrame) rect = obj.GetRect rect.Top = CurrentY if m=CurrentLMenu then CurrentY = CurrentY + rect.Height end if obj.SetRect rect END IF END IF rem (если FR встретился после LM, то ставим его на место) IF Mid(Id,1,8)=NameObjectFRame AND FoundM = m THEN rect = obj.GetRect rect.Top = CurrentY if m=CurrentLMenu then CurrentY = CurrentY + rect.Height end if obj.SetRect rect iFrame = -1 END IF next next END SUB |
А также вторую процедуру, которая нужна для первоначальной установки объектов после расчета основного скрипта загрузки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
SUB SetLMenu Distance = 1 rem (зазор в пикселях между объектами-названиями размерностей) NameSheetID = ActiveDocument.GetLayout.ActiveSheetId NameSheetID = Mid(NameSheetID, InStr(NameSheetID,"\")+1) set sh = ActiveDocument.ActiveSheet FoundM = 0 form = 1 to 10 iFrame = -1 for i = 0 to sh.NoOfSheetObjects-1 set obj = sh.SheetObjects(i) Id = obj.GetObjectId Id = Mid(Id, InStr(Id,"\")+1) if m<=9 then NameObjectLMenu = "LM0" & m & NameSheetID NameObjectFRame = "FR0" & m & NameSheetID else NameObjectLMenu = "LM" & m & NameSheetID NameObjectFRame = "FR" & m & NameSheetID end if rem (если FR встретился раньше, чем LM, то запоминаем его номер) IF Mid(Id,1,8)=NameObjectFRame AND FoundM < m THEN iFrame = i END IF rem (нашли объект меню LM) IF Mid(Id,1,8)=NameObjectLMenu THEN rect = obj.GetRect if m=1 then rect.Top = 110 else rect.Top = CurrentY + Distance obj.SetRect rect CurrentY = obj.GetRect.Top + obj.GetRect.Height FoundM = m rem (если FR уже найден, то ставим его на место) IF iFrame > -1 THEN set obj = sh.SheetObjects(iFrame) rect = obj.GetRect rect.Top = CurrentY obj.SetRect rect END IF END IF rem (если FR встретился после LM, то ставим его на место) IF Mid(Id,1,8)=NameObjectFRame AND FoundM = m THEN rect = obj.GetRect rect.Top = CurrentY obj.SetRect rect iFrame = -1 END IF next next END SUB |
Как можно заметить в первой процедуре (SelectLMenu), чтобы передать в неё информацию, на какой же элемент меню нажалиЭ, мы передаём её через переменную
vCurrentLMenu, поэтому первый триггер, который мы пропишем для нашего первого элемента меню будет: External\Set Variable —> vCurrentLMenu с присвоением значения =1
И вот тут идея:
Почему мы не стали использовать эту переменную для отображения состояния нашего меню? Да потому, что в клике, при нажатии на команды «Back» или «Forward» значение переменных меняется (также как и состояние выборки) на предыдущее! А это элемент интерфейса, и если он выбран/настроен, то не должен меняться.
Решение — перенести переменные управления в поля макета. Вот для чего мы создали ранее таблицу «_LMenu» с полями «_LMenu01», «_LMenu02» и т.д. (по количеству меню).
Поэтому запишем в эти поля таблицы информацию, что мы выбрали первый элемент. Добавим вторую команду к триггеру, после команды присвоения переменной:
External\Dynamic Update и в поле ввода «Statement» пропишем следующий список команд:
1 2 3 4 5 6 7 8 9 10 |
UPDATE _LMenu SET _LMenu01=1 WHERE _LMenu01=0; UPDATE _LMenu SET _LMenu02=0 WHERE _LMenu02=1; UPDATE _LMenu SET _LMenu03=0 WHERE _LMenu03=1; UPDATE _LMenu SET _LMenu04=0 WHERE _LMenu04=1; UPDATE _LMenu SET _LMenu05=0 WHERE _LMenu05=1; UPDATE _LMenu SET _LMenu06=0 WHERE _LMenu06=1; UPDATE _LMenu SET _LMenu07=0 WHERE _LMenu07=1; UPDATE _LMenu SET _LMenu08=0 WHERE _LMenu08=1; UPDATE _LMenu SET _LMenu09=0 WHERE _LMenu09=1; UPDATE _LMenu SET _LMenu10=0 WHERE _LMenu10=1; |
Как видим, мы только в «_LMenu01» записали «1», а во все остальные поля «0».
Осталось только подключить процедуру VB, которая «раскрывает» выбранный элемент меню. Для этого в меню «Settings\Document Properties» на вкладке «Triggers», в нижнем блоке «Variable Event Triggers», находим переменную:
vCurrentLMenu, которую мы уже создали, и для неё пропишем триггер «OnChange»:
External\Run Macro и в поле ввода «Macro Name» впишем имя нашей процедуры: SelectLMenu
Теперь всякий раз, когда мы будем нажимать на элемент меню, переменная vCurrentLMenu будет меняться. От этого (по триггеру) будет запускаться процедура «SelectLMenu», в которой считывается значение этой переменной и далее выполняются нужные манипуляции с объектами меню.
Пример (Б)
Осталось научить клик понимать какие объекты листа относятся к динамическому меню, а какие нет.
И вот тут ещё одна возможность клика! Мы можем любому объекту клика присваивать любой идентификационный код! То есть на вкладке «General» в поле «Object ID» мы вправе вписать любой свой идентификатор, закодировав в нём нужную нам информацию о данном объекте и для передачи этой информации в процедуры обработки. Если вы уже обратили внимание на процедуры VB, которые мы с вами добавили, то в них делается поиск объектов, ID которых начинается с «LM» или с «FR». Иными словами, мы в «Object ID» для элементов меню выбора (в нашем случае это «Text Object» с названиями размерностей) должны закодировать следующую конструкцию: LM{NN}SH{LL}, где первые буквы «LM» означают кратко «Left Menu», далее {NN} идет порядковый номер меню «01», «02» и т.д., после идет ID листа, на котором мы строим меню с его порядковым номером {LL}.
Для нашего примера (ID листа которого «SH06») составной идентификатор для первого элемента меню будет «LM01SH06», что и нужно прописать в «Object ID».
А вот объект выбора, который при этом появляется при нажатии меню, должен иметь «Object ID» формата как «FR01SH06»! Именно такой объект ищется в процедуре SelectLMenu и передвигается по вертикали к своему нажатому меню (когда нажато первое меню списка).
Итак, создав сначала элементы меню (объекты с ID начинающиеся на LM…), создаем и сами фреймы — объекты клика, которые будут появляться при раскрытии меню и позволят управлять выбором наших размерностей. В простом варианте — это обычные объекты клика, списки (ListBox).
В примере (В) созданы два элемента меню и два списка для выбора размерностей. Как их следует назвать приведено справа на сносках.
Осталась одна деталь, но самая важная. Когда все элементы уже разработаны, нужно для объектов выбора размерностей прописать условие их показа. А именно для первого ListBox, которое имеет название «FR01SH06» нужно на вкладке «Layout» прописать условие «Conditional» _LMenu01=1.
Для второго списка «FR02SH06» условие уже будет _LMenu02=1 и т.д. (думаю, зависимость понятна).
Теперь вы без труда создадите всё меню полностью.
Чтобы привести всё меню после окончания разработки в начальное состояние (т.е. свернуть всё), нужно проапдэйтить все поля с _LMenu01 по _LMenu10 в ноль и вызвать процедуру SetLMenu.
Обе эти команды можно прописать в триггере на переход на страницу и (или) добавить в приложение кнопку «свернуть всё» и прописать эти команды в её триггере (или на вкладке «Actions» если это «Text Object»).
Первая команда:
1 2 3 4 5 6 7 8 9 10 11 12 |
External\Dynamic Update и в поле ввода "Statement" пропишем следующий список команд: UPDATE _LMenu SET _LMenu01=0 WHERE _LMenu01=1; UPDATE _LMenu SET _LMenu02=0 WHERE _LMenu02=1; UPDATE _LMenu SET _LMenu03=0 WHERE _LMenu03=1; UPDATE _LMenu SET _LMenu04=0 WHERE _LMenu04=1; UPDATE _LMenu SET _LMenu05=0 WHERE _LMenu05=1; UPDATE _LMenu SET _LMenu06=0 WHERE _LMenu06=1; UPDATE _LMenu SET _LMenu07=0 WHERE _LMenu07=1; UPDATE _LMenu SET _LMenu08=0 WHERE _LMenu08=1; UPDATE _LMenu SET _LMenu09=0 WHERE _LMenu09=1; UPDATE _LMenu SET _LMenu10=0 WHERE _LMenu10=1; |
И вторая команда:
External\Run Macro
в поле ввода «Macro Name» пишем процедуру: SetLMenu
Итак, наш интерфейс готов.
Друзья, на этом все на сегодня! До новых встреч в эфире!
Свежие комментарии