Контекстное меню

Контекстное меню — это неотъемлемый элемент любою современного приложения. Оно появляется около указателя мыши при нажатии ее правой кнопки (или нажатии клавиши Control в случае компьютеров Macintosh). Обычно структура контекстного меню зависит от того, какой элемент располагался под указателем в момент нажатия правой кнопки мыши — отсюда и его название. По умолчанию, у Flash-плейера имеется 4 разновидности контекстного меню. Наиболее стандартное из них отображается при щелчке над любым элементом фильма, кроме выделяемого текстового поля. В нем располагаются команды навигации, масштабирования, управления качеством отображения, печати, а также некоторые другие. У выделяемых текстовых полей имеется собственное контекстное меню, хранящее команды выделения, копирования, вырезки и вставки. Особое контекстное меню присуще гиперссылкам в тексте. И, наконец, четвертая разновидность контекстного меню отображается в том случае, если в плейере не проигрывается ни одного фильма. При этом в нем имеются только два пункта — «Movie not loaded» («Клип не загружен» — выполняет информационные функции) и «About Macromedia Flash Player» (открывает панель со сведениями о Flash-плейере).

До Flash MX 2004 в ActionScript не имелось практически никаких инструментов, позволяющих управлять контекстным меню плейера.


Существовала лишь возможность его сокращения до двух элементов — и больше ничего. Невозможность введения в контекстное меню собственных элементов в сочетании с отсутствием средств, позволяющих полностью отключить его появление, существенно усложняло жизнь разработчикам. Никакие ухищрения не давали возможности создать собственное контекстное меню. Лучшее, что можно было сделать, — это выводить собственное меню при нажатии не правой, а левой кнопки мыши. Однако данное решение нельзя назвать удовлетворительным, так как оно противоречит сложившимся традициям разработки интерфейсов (пользователь может просто не догадаться, что меню с настройками выводится нажатием левой клавиши мыши). Во Flash 7 появились новые классы — ContextMenu и ContextMenuItem, существенно расширяющие возможности по управлению контекстным меню. Используя их, можно индивидуально настраивать контекстное меню для каждого объекта, вводить в него собственные элементы, удалять часть или все встроенные элементы и решать еще ряд важных задач.

Настройка контекстного меню. Класс ContextMenu
Во Flash MX 2004 каждый клип, кнопка или текстовое поле потенциально может иметь собственное контекстное меню.


Соответственно каким-то образом необходимо создавать и хранить описания этих нестандартных меню. Для этого предназначены объекты специального класса ContextMenu, задающиеся по следующей схеме:

var myMenu:ContextMenu = new ContextMenu([handler]);

Здесь handier — необязательный параметр, указывающий на функцию, код которой должен быть проделан перед тем, как отобразится данное контекстное меню. В качестве параметров ей передается ссылка на клип, кнопку или текстовое поле, с которым связано контекстное меню (object), а также указатель на описывающий его объект класса ContextMenus (cont_menu). Эта функция полностью аналогична обработчику события onSelect, который имеет следующий синтаксис:

myMenu.onSelect=function(object, cont_menu:ContextMenu){}

Функция handler и событие onSelect обычно используются, если контекстное меню должно быть настроено исходя из текущего состояния фильма или того, какой объект его вызвал. Также их можно применять для определения события щелчка правой клавиши мыши.

Пользовательское меню обязательно должно быть связано с каким-то конкретным клипом, кнопкой, текстовым полем или фильмом на определенном уровне.


Для этого описывающий его объект должен быть присвоен специальному свойству menu, присущему классам MovieClip, Button и TextField. Если значение свойства menu равно undefined или null, то для данного объекта будет использоваться меню, принятое по умолчанию.

// При появлении контекстного меню в Output будет выводиться сообщение
var myMenu:ContextMenu = new ContextMenu[handler);
_root.menu = myMenu;
function handler():Void {
trace("Контекстное меню активизировано");
}

Если индивидуальные контекстные меню создаются для клипа и вложенного в него объекта, то собственное меню вложенного элемента будет иметь приоритет над меню клипа-хозяина. Таким образом, при щелчке по вложенному объекту будет появляться его собственное меню, а не меню, характерное для содержащего его клипа.

Если под указателем мыши в момент нажатия ее правой клавиши располагалось несколько объектов, выведено будет контекстное меню верхнего из них.

Тот факт, что некоторое контекстное меню относится к клипу, не означает, что команды навигации в нем (play, rewind и пр.) будут применяться по отношению к его временной диаграмме, Вне зависимости оттого, какому элементу принадлежит меню, стандартные команды в нем управляют проигрывающей головкой основной временной диаграммы фильма (именно поэтому команды навигации имеются и в контекстном меню кнопок).

Один объект класса ContextMenu можно использовать для задания нескольких контекстных меню.


Однако эту возможность стоит применять лишь в том случае, если настройки меню не будут меняться в зависимости от контекста. Иначе необходимо создавать копию соответствующего объекта для каждого элемента. С учетом особенностей операции присваивания в ActionScript этого нельзя сделать, используя оператор «=». Чтобы изготовить копию объекта, необходимо перезаписать все его свойства в пустой объект при помощи цикла for—in. Однако в случае объектов класса ContextMenu эту задачу можно решить и проще, благодаря наличию специального метода сору().

Пример:
// Создайте два клипа в виде кружков и назовите их clip1 и clip2
// В контекстном меню клипа clip1 не будет пункта print
var myMenu1:ContextMenu = new ContextMenu(handler);
myMenu1.builtInItems.print = false;
// Контекстное меню клипа clip2 будет повторять меню клипа clip1 с отличием
// в том, что из него также будет убран пункт quality
var myMenu2:ContextMenu = myMenu1.copy();
myMenu2.builtlnltems.quality = false;
clip1.menu = myMenu1;
clip2.menu = myMenu2;

Тестировав данный код, обнаруживаем, что почему-то пункт quality исчез из обоих меню.


Это означает, что копия, созданная методом сору(), каким-то образом связана с исходным объектом. Имеется две возможные причины этой особенности. Либо метод сору() реально не создает копии объекта, а всего лишь возвращает ссылку на него, либо объект builtInItems был передан копии не по значению, а по ссылке. Проверим оба варианта:

trace(nyMenu1==myMenu2); // Выводит: false
trace(myMenu1.builtInItems==myMenu2.builtInItems); // Выводит: true

Проверка показывает, что свойства builtInItems объектов myMenu1 и myMenu2 ссылаются на один и тот же объект. Причина этого — банальная недоделка в реализации интерпретатора ActionScript.

Разработчики просто не учли, что свойство builtInItems хранит составной объект данных, попытавшись передать его значение аналогичному свойству копии при помощи операции присваивания. Естественно, что при этом свойству builtInItems копии была присвоена ссылка на объект builtInItems исходного элемента, но не его копия.

Обнаруженный недостаток метода сору() означает, что применять его стоит лишь в том случае, если набор свойств объекта builtInItems будет одинаков как у исходного объекта класса ContextMenu, так и у его копии. В противном случае каждый объект необходимо создавать индивидуально.

Итак, с особенностями передачи объекта builtInItems при операции копирования мы разобрались.

Теперь поговорим о его назначении. Данный объект отвечает за отображение стандартных пунктов контекстного меню плейера. Каждому пункту соответствует отдельное свойство, имя которого совпадает с названием пункта: save, zoom (указывает на подменю с командами масштабирования — Zoom In, Zoom Out, Show All, 100 %), quality, play, loop, rewind, forward_back, print. Чтобы убрать элемент меню, описывающему его свойству объекта builtlnltems необходимо присвоить false.

За отображение пункта меню отвечает значение true одноименного ему свойства. Например:

// Код убирает из контекстного меню все команды навигации {чтобы они
// отображались изначально, в фильме должно быть не менее двух кадров)
var myMenu:ContextMenu = new ContextMenu();
with (myMenu.builtlnltems) {
play = forward_back=rewind=loop=false;
}
_root.menu = myMenu;

Используя свойства объекта builtInItems, нельзя отключить отображение двух пунктов меню:

Settings (открывает панель с настройками Flash-плейера) и About Macromedia Rash Player (вызывает панель с краткой информацией о плейере), Причиной невозможности убрать пункт Settings являются требования безопасности; пользователь сам должен определять, сколько фильм может записать данных на диск, имеет ли он право использовать камеру и микрофон. Иначе, например, несколькими строчками кода можно было бы создать своего рода swf-вирус, который бы забивал весь винчестер ненужным мусором. Почему нельзя убрать строчку «About Macromedia Flash Player», мы уже обсуждали выше. Кстати, в среде тестирования данная строчка заменяется пунктом Debugger (вызывает отладчик) — и его также нельзя убрать.

Полностью убрать контекстное меню плейера пока, увы, невозможно. И это очень плохо, так как при разработке игр и интерфейсов мы не можем применять события щелчка правой клавиши мыши. Будем надеяться, что Macromedia в одной из бли-,жайших версий Flash все-таки решится пожертвовать скрытой, но на редкость эффективной рекламой в виде обязательного пункта «About Macromedia Flash Player».

Свойства объекта builtInItems позволяют управлять отображением пунктов только стандартного меню плейера. С его помощью невозможно убрать элементы из меню текстового поля или, что очевидно, из меню, показывающего, что в плейере не прокручивается ни одного фильма и из меню гиперссылки.

Если нужно, чтобы в стандартном контекстном меню не отображалось ни одного пункта, кроме обязательных, необходимо перечислить все свойства объекта builtInItems при помощи цикла for— in, присваивая им значение false. И для этого даже не придется применять функцию ASSetPropFlags(), так как свойства builtInItems являются перечисляемыми изначально (в отличие от свойств всех остальных предопределенных объектов):

var myMenu:ContextMenu = new ContextMenu();
for (var i in myMenu.builtInItems) {
myMenu.builtInItems[i] = false;
}
_root.menu = myMenu;

Убрать все необязательные пункты из контекстного меню можно и проще. Если это нужно сделать для всех контекстных меню фильма, необходимо набрать следующую строку:

Stage.showMenu=false; // Оптимальный способ

Данные команды появились задолго до класса ContextMenu. И они имеют приоритет над ним. Если создать собственное контекстное меню, содержащее все стандартные команды плюс пользовательские элементы, а затем ввести одну из них, то в итоге в меню отобразятся только два обязательных пункта.

Если swf-фильм публикуется на HTML-странице, глобально минимизировать контекстное меню можно, и не обращаясь к ActionScript. Для этого достаточно присвоить значение false параметру menu тега (или одноименному атрибуту тега EMBED):



Если публикация осуществляется из среды разработки Flash, то для автоматического введения в генерируемый HTML-код приведенной строчки нужно убрать флажок из окошка Display Menu закладки HTML панели Publish Settings.

Если необходимо отключить отображение стандартных элементов только одного контекстного меню или требуется, чтобы удаление стандартных элементов меню не привело к исчезновению элементов пользовательских, применять приведенные выше подходы нельзя. В этом случае нужно использовать метод hideBuiltInItems() класса ContextMenu. Например:

// В контекстном меню будут только два обязательных стандартных пункта и
// пользовательский пункт "Привет", при выборе которого в Output Судет
// появляться соответствующее сообщение
var myMenu:ContextMenu = new ContextMenu();
var myItem:ContextMenuItem = new ContextMenuItem("Привет", function ()
{trace("Привет");}));
myMenu.customltems.push(myItem);
myMenu.hideBuiltInItems(); // Скрываем все стандартные элементы
_root.menu = myMenu;

Алгоритм метода hideBuiltInItems() заключается в простом присвоении всем свойствам объекта builtInItems значения false. Поэтому, если вам необходимо, чтобы в меню отображался только один или два стандартных пункта, наиболее рационально отключить вначале вывод всех стандартных элементов, а затем присвоить необходимым свойствам объекта builtInItems значение true:

// Из стандартных элементов меню отображаться будет только print
var myMenu:ContextMenu = new ContextMenu();
myMenu.hideBuiltInIterns();
myMenu.builtInItens.print=true;
_root.menu = myMenu;

Метод hideBuiltInItems() не позволяет скрывать элементы меню текстовых полей. В ActionScript в принципе невозможно убрать или как-то изменить контекстное меню выделяемого текстового поля (но в случае полей типа Dynamic и Input можно добавить собственные элементы).

Отключение некоторых или даже всех команд стандартного контекстного меню — это одна из самых важных для практики задач из тех, которые решаются с использованием ActionScript. Минимизированное контекстное меню у баннера, игры или Flash-сайта является одним из признаков того, что данный проект был создан достаточно профессиональным разработчиком. Почему? Дело в том, что команды меню совершенно не взаимосвязаны с кодом фильма, Главная проблема, которая из этого вытекает, заключается в том, что пользователь может осуществлять навигацию по временной диаграмме всегда. И это очень плохо. Например, представьте, что вы создали игру, размещенную на трех кадрах. На первом кадре будет находиться меню с установками (уровень сложности, имя игрока и т. д.), на втором — сама игра, на третьем — заставка, выводящаяся в случае победы. Естественно, что переход с первого кадра на второй должен быть осуществлен лишь тогда, когда игрок заполнит нее поля и нажмет кнопку начала игры. Соответственно перевод проигрывающей головки со второго кадра на третий должен быть произведен лишь по завершении игры.

Запрограммировать подобное поведение фильма очень просто. Но если при этом не скрыть команды навигации контекстного меню, пользователь сможет нажать play или rewind — и перейти на следующий кадр «незаконно». Аналогично, перейти на предыдущий кадр можно при помощи команд back и rewind, Подобные переходы почти наверняка собьют работу алгоритма. И это не самое худшее. Представьте, что вы создали платный сайт, получить доступ к которому можно только по паролю. Строка с запросом пароля располагается на первом кадре, главная страница — на втором. Нажав play, пользователь сможет перейти к основному разделу, даже не зная пароля. Подобных примеров можно привести очень много, причем источником потенциальных проблем могут быть не только команды навигации, но и другие команды контекстного меню или главного меню автономного проигрывателя. Например, совсем нежелательно, чтобы созданные вами баннеры заказчик рассматривал в полноэкранном режиме, так как при этом гораздо проще обнаружить дефекты.

Дополнительные сложности возникают, если ваш фильм будет проигрываться в автономном плейере. При этом потенциально опасные команды имеются не только в контекстном меню, но и в главном меню плейера — их тут даже больше (например, чего стоит один лишь Full Screen — команда перехода в полноэкранный режим). От-почить команды главного меню при помощи класса ContextMenu невозможно. Главное меню убирается лишь в том случае, если контекстные меню минимизируются глобально при помощи свойства showMenu объекта Stage или параметра showmenu функции fscommand().

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

Stage.showMenu=false;

Введение в контекстное меню собственных команд
Вo Flash MX 2004 стало возможным вводить собственные элементы в контекстное меню плейера.

Это большой прорыв, существенно облегчающий качественную: разработку интерфейсов (особенно с учетом того, что убрать контекстное меню плейера невозможно, а следовательно, нельзя создавать и полностью собственные контекстные меню). Носителем возможности по добавлению собственных элементов в контекстные меню является особый класс ContextMenuItem.

Один объект класса ContextMenultem соответствует одной команде контекстного меню. Синтаксис его создания следующий:

var myMenuItem:ContextMenuItem=new ContextMenultem (caption, callback_func,
separator_before, enabled, visible);

Здесь:
• caption — имя команды (точнее, текст, который будет отображаться в ее строке). Не может быть длиннее 100 символов. Ширина панели контекстного меню будет зависеть от ширины строки команды с самым длинным именем (отсюда и ограничение на количество символов в имени команды). В имени команды обязательно должен быть хотя бы один отображаемый символ. Составить его из одних пробельных символов нельзя — при этом соответствующий пункт введен в меню не будет. Попытка создать имя, разнесенное по нескольким строчкам, за счет добавления в строку caption символов переноса строки будет системой проигнорирована: один пункт контекстного меню может занимать только одну строку.

Имена двух пользовательских команд не могут совпадать. Иначе будет выведена лишь одна из них.

Имя пользовательской команды не должно совпадать с именем команды стандартной. Иначе пользовательская команда попросту не будет отображена. Причем это ограничение действует, даже если стандартные команды скрыты. Если элемент добавляется в контекстное меню клипа или кнопки, его имя не может совпадать с названием стандартной команды контекстного меню текстового поля (равно как и наоборот). Например, вы не можете создать команду сору, копирующую клип, так как команда с таким именем имеется в контекстном меню текстовых полей. Имена команд считаются идентичными без учета регистра (т. е. команда Loop будет забракована так же, как и loop). Ввести в меню команду, имеющую вид стандартной, просто прибавив к соответствующей строке один или несколько пробелов, невозможно (пробельные символы в начале и в конце имени команды отбрасываются).

Следующие слова и сочетания не могут в принципе входить в имя пользовательской команды контекстного меню: Macromedia, Flash Player, Settings. Это означает, что, например, создать пункт меню «Подключиться к сайту Macromedia» или «Закрыть окно Flash Player» невозможно. Причина описанного ограничения заключается, скорее всего, в исключительной важности двух пунктов стандартного меню — «Settings» и «About Macromedia Flash Player»;

• callback func — функция, которая должна быть вызвана при выборе данного пункта меню. В качестве параметров ей передается ссылка на клип, кнопку или текстовое поле, к которому относится контекстное меню, а также ссылка на объект класса ContextMenultem, описывающий выбранный пункт меню. Функция callback_func обязательна для задания, так как без ее наличия невозможно будет среагировать на событие выбора пункта меню. Однако ее можно заменить обработчиком события onSelect, который принимает тот же набор параметров и вызывается при тех же обстоятельствах. Если в коде не будет ни функции callback_func, ни обработчика события onSelect, связанного с данным объектом класса ContextMenultem, пользовательский пункт меню отображен не будет. Если создать одновременно функцию callback_func и обработчик события onSelect, то при выборе элемента меню будет активирована только функция обработчика (т. е. она имеет приоритет);

• separator_before — необязательный параметр, определяющий, будет ли отображаться линия разделителя перед данным пунктом меню (true) или же нет (false). По умолчанию элемент меню выводится без разделителя, Обычно разделители применяются, если необходимо разбить контекстное меню на несколько подменю, команды которых связаны исходя из выполняемых функций;

• enabled — необязательный параметр, задающий активность пункта меню. Если он равен true, то данный пункт можно будет задействовать. Если ему соответствует false, пункт меню будет отображаться серым контурным шрифтом, однако выбрать его будет невозможно. Параметр enabled применяется, если по умолчанию данный элемент меню должен быть неактивен;

• visible — параметр определяет, будет ли пункт отображаться в контекстном меню (true) или же нет (false). Он полезен, если элемент меню должен выводиться лишь при соблюдении некоторого условия.

Все пользовательские команды выводятся одним блоком, размешенным над командами стандартными. Команды пользовательские всегда отделяются от стандартных при помощи линии разделителя.

Ввести собственные элементы можно как в контекстные меню клипов, кнопок и главных временных шкал, так и в меню текстовых полей типа Dynamic и Input.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Action Script на эту тему:
Определение кода введенного символа. Метод getAscii()
Проверка активности специальных режимов. Метод isToggled()
Проверка нажатия клавиши. Метод isDown()
Работа с клавиатурой
Работа с мышью