![]() |
Модераторы: LSD, AntonSaburov |
![]() ![]() ![]() |
|
Wowa |
|
||||||||||||
Эксперт ![]() Профиль Группа: Админ Сообщений: 15017 Регистрация: 14.9.2000 Где: Винград Репутация: 1 Всего: 290 |
Довольно часто при создании приложений с GUI (stand alone приложений или апплетов) приходится сталкиваться с необходимостью несколько изменить внешний вид и поведение стандартных компонентов пользовательского интерфейса. Иногда этого хочет заказчик. Иногда этого требует дизайнер интерфейсов. Так или иначе время от времени такая задача возникает. И не всегда представляется возможным создать комбинированный из нескольких других элемент пользовательского интерфейса. Например добавить кнопку закрытия в закладку компонента JTabbedPane. Или реализовать меню, которое может отображать пиктограмму над названием пункта меню и кроме этого позволит использовать JMenuBar непосредственно как контейнер для пунктов меню. Вот такое меню мы и реализуем.
Практически каждый кто писал на java приложения с GUI, использовал в своей работе классы имплементирующие меню. И наверняка каждый знает, что при создании меню есть определенные правила, все это хорошо описано в сановском туториал, книгах и статьях. И каждый знает об ограничениях, которые накладывает этот подход – чтобы использовать JMenuItem, необходимо создать экземпляр JMenu – контейнер для нашего итема, и уже только этот контейнер мы можем поместить в JMenuBar. Но ведь во многих windows-приложениях пункт меню может быть виден и использоваться прямо из панели меню. К сожалению разработчики Swing не заложили такой возможности в библиотеку. На самом деле это не сложно изменить. Для того чтобы проделать такой фокус нам нужно будет расширить класс JMenu – должен заметить, что мне не удалось реализовать прослушивание событий как это принято, пришлось пойти на ухищрения и изменить эту схему. Если кто то знает как это можно сделать, буду благодарен за комментарии и дополнения. Итак, задача: в создаваемом приложении реализовать пункт меню, который будет находиться непосредственно в панели меню, иметь возможность использовать картинки и текст, и его поведение будет соответствовать стандартному пункту меню – если какой то пункт выбран – можно перемещаться с помощью клавиш курсора влево-вправо и реагировать на клавиши пробел и Enter. Выглядеть это будет примерно так: ![]() При этом наше меню должно отображать пиктограмму и название итема – пиктограмма сверху а текст снизу, при этом корректно реагировать на ситуации когда пиктограмма или текст отсутствуют, и иметь возможность помещать как отдельные элементы, так и элементы-контейнеры. 1. Таким образом задача разбивается на следующие подзадачи: расширить функциональность классов которые создают меню чтобы их поведение удовлетворяло поставленным требованиям 2. корректно отрисовать наше меню. Начнем реализацию со второй подзадачи. Так как правильно и однотипно в панели меню отображаться должны и элементы-контейнеры(JMenu) и элементы-итемы (JMenuItem) напрашивается решение унаследовать наш класс от JMenu. Так мы и сделаем. Все что нужно будет изменить в нашем классе – это определить размеры нашего пункта меню и отрисовать его. В классе обьявлено несколько констант для отступов от границ пунктов меню и между пиктограммой и текстом, а также значения размера для пункта меню по умолчанию, если ни текст ни пиктограмма не были заданы. Также обьявлены экземплярные переменные icon и title для реализации заявленной функциональности – отображения пиктограммы и надписи.
В классе имплементированы два метода и конструктор с параметрами. В конструкторе инициализируем экземплярные переменные и определяем соответствующие размеры пункта меню.
Второй метод ответственнен за отображение. Вообще, чтобы нарисовать на Swing-компоненте то что нам хочется, достаточно переопределить метод paintComponent(Graphics). Метод обьявлен в классе JСomponent и служит для вызова делегированного paint() метода соответствующего ComponentUI обьекта. Метод isSelected() родительского класса JMenu возвращает true если наш пункт меню был выбран. В этом случае мы добавляем прорисовку рамки чтобы визуально выделить выбранный пункт и сдвигаем картинку и надпись на 1 пиксел вниз-вправо.
Вторая часть нашей задачи – сделать возможным добавление итема в контейнер JMenuBar. Казалось бы очевидное решение – изменить поведение контейнера чтобы он корректно обрабатывал добавление итемов. Однако на самом деле это не будет самым простым решением – придется переписать довольно много кода и придется создать класс, который будет наследовать JMenuItem и прорисовывать итем аналогично тому как мы сделали в первой части задачи. Можно пойти другим путем. У нас уже есть класс который умеет себя правильно и однотипно прорисовывать в контейнере. Контейнер корректно размещает инстансы этого класса и передает сообщения о действиях пользователя. Что нам нужно – это как то спрятать выпадающий список включенных элементов и дать возможность программисту реализовывать реакцию на действия с этим пунктом меню. Необходимость прятать выпадающий список появляется из-за того, что даже если мы не поместим ни одного итема в контейнер, то класс JMenu прорисовывает рамку этого списка, такой квадратик 2х2 пиксела. Выглядит не очень красиво. Этот выпадающий список реализован как popup-menu, координаты для отображения которого рассчитываются контейнером. Доступ обьявлен как private, напрямую добраться к нему нельзя. Но есть public - метод getPopupMenu(), и мы установим для внутреннего popup-menu размер 0х0 пикселов. Все, больше мы его не увидим. Итак, создаем наследника от ранее нами созданного класса PictMenu. В конструкторе делаем вызов getPopupMenu().setPreferredSize(new Dimension(0, 0)); Еще мы должны диспетчеризовать события клавиатуры, поэтому наш класс будет реализовывать интерфейс KeyEventDispatcher и мы зарегистрируем его в DefaultKeyboardFocusManager.
Интерфейс KeyEventDispatcher обьявляет единственный метод dispatchKeyEvent в который передается событие клавиатуры. События клавиатуры, которые необходимо обработать – нажатие enter или пробел – вызов метода-обработчика пункта меню, нажатие курсорных клавиш и клавиши esc уже умеет обрабатывать наш суперкласс JMenu. Поэтому мы обьявим метод с пустой реализацией doAction() который будет переопределяться и в котором будет код, реализующий действия при выборе пункта меню.
После вызова doAction() необходимо снять выделение с пункта меню. Для этого мы генерируем событие, как будто пользователь нажал клавишу esc и передаем его для обработки вызовом processKeyEvent().
Чтобы пункт меню так же реагировал на действия мыши регистрируем MouseListener и имплементируем методы mouseReleased() и mouseClicked(). В результате, создав два совсем простых класса мы получили значительное изменение функциональности меню стандартного пользовательского интерфейса. Полный код классов реализующих такое меню: PictMenu.java и SimplePictMenu.java. Работающий пример можно увидеть здесь. Автор: Виктор Вареников |
||||||||||||
|
|||||||||||||
![]() ![]() ![]() |
Правила форума "Java" | |
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Java: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |