Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Lab05_2010_draft3

.pdf
Скачиваний:
33
Добавлен:
07.06.2015
Размер:
2.53 Mб
Скачать

Рис. 44. Тело метода jDrawingPanelMouseDragged()

Сохраните проект и запустите его на выполнение. Попробуйте «порисовать» мышкой на «слегка приподнятой» белой панели (рис. 45).

Примечание.

Если панель имеет не белый цвет, попробуйте выполнить не компиляцию, а построение (building) проекта и запустить его независимо от среды – просто дважды щелкнув по значку приложения в папке dist.

Рис. 45. На белой панели можно рисовать

А теперь потратим несколько минут, чтобы посмотреть, какой именно код был сгенерирован NetBeans в качестве «обеспечения» обработчика события. Проще всего выполнить поиск использующих вхождений обработчика события с помощью контекстного меню Find Usages (рис. 46) (можно воспользоваться и пунктом меню Call Hierarchy).

Рис. 46. Поиск использующих вхождений

В появившемся диалоговом окне (рис. 47) можно указать, требуется ли искать в комментариях (Search in Comments; по умолчанию поиск проводится), требуется ли искать использование в коде (Find Usages; по умолчанию поиск проводится), а также выбрать проекты, в которых поиск проводится. По умолчанию предлагается искать во всех открытых проектах – Open Projects, в раскрывающемся списке Вы обнаружите также проект SimleGraphicEditor. Поскольку никакие другие проекты в среде не открыты, то разницы, какой именно из пунктов будет выбран, нет.

Рис. 47. Диалоговое окно Find Usages

После того, как Вы нажмете кнопку Find, к вкладкам, открытым в нижней части среды, добавится вкладка Usages, показывающая, что использующее вхождение метода jDrawingPanelMouseDragged встречается единожды (рис. 48).

Рис. 48. Использующие вхождения метода jDrawingPanelMouseDragged()

Примечание.

Вкладка Usages в действительности станет последней среди открытых вкладок. Она была перемещена вручную в целях оптимизации рисунка.

Выполните двойной щелчок на выделенном жирным шрифтом названии метода jDrawingPanelMouseDragged(evt). Это приведет к переходу к собственно вызову этого метода в коде (рис. 49). Рассмотрим, что же там происходит.

Собственно вызов метода jDrawingPanelMouseDragged(evt) происходит в теле другого метода – mouseDragged(java.awt.event.MouseEvent evt). Заметим, что вызов – единственная строка в теле этого другого метода, так что его можно считать просто «оболочкой». Метод mouseDragged() входит в состав объекта – экземпляра анонимного внутреннего класса, наследника класса-адаптера MouseMotionAdapter, и является единственным переопределенным методом по отношению к классу-предку (зеленый значок, отмечающий строку с заголовком метода, Вы можете видеть в колонке с номерами строк). Этот экземпляр анонимного внутреннего класса и является тем самым слушателем, который обеспечивает реакцию панели jDrawingPanel на событие перемещения мыши с нажатой клавишей.

Рис. 49. Фрагмент автоматически сгенерированного кода с вызовом jDrawingPanelMouseDragged(evt)

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

действия, принадлежит не слушателю, а какому-то другому классу (в нашем случае это SimpleGraphicEditorView). Конечно, такое решение разработчиков является отчасти спорным (во взаимодействие слушателя и компонента jDrawingPanel «вмешивается» контейнер, который этот компонент содержит), но все же приемлемым в большинстве случаев.

Если Вы посмотрите на код чуть выше, то увидите, что в точности также организовано добавление слушателя события mouseListener, метод которого mousePressed представляет собой оболочку для метода jDrawingPanelMousePressed() класса

SimpleGraphicEditorView.

§ 6. Создание класса-наследника JPanel для обеспечения перерисовки

Если Вы свернете окно приложения или перекроете его другими окнами, нарисованное исчезает. Это вполне «естественный» процесс – когда окно приложения перекрывается другими окнами, то по возвращении его на «верхний уровень отображения» операционной системе (в действительности цепочка «ответственных» достаточно длинная) требуется перерисовать его содержимое. Поскольку рисунок не является неотъемлемой частью компонента, на котором он был выполнен, перерисовывается только сам компонент – и уже без рисунка.

Конечно, в большинстве случаев такое поведение приложения неудобно. «Бороться» с этим можно разными путями. Одним из наиболее естественных представляется определение наследника класса JPanel, который будет снабжен средствами хранения рисунка, выполненного на нем. Тогда при перерисовке компонента можно будет восстановить и «пользовательское» изображение.

Выберите в меню File пункт New File (рис. 50) и в открывшемся диалоговом окне (рис. 51) – категорию Java и тип файла Java Class.

Рис. 50. Создание нового файла в существующем проекте

Рис. 51. Файл создается для нового класса

После нажатия на кнопку Next в следующем диалоговом окне (рис. 52) Вам понадобится указать имя нового класса (Class Name) (назовите его JGraphicPanel), в пакете какого типа он будет находиться (кроме подходящего нам Source Packages в качестве местоположения (Location) доступно также Test Packages) и собственно этот пакет (Package). По умолчанию в качестве пакета предлагается пакет simplegraphiceditor, что нас устраивает. Строки Project и Created File недоступны для редактирования, среда заполнит их автоматически.

Нажатие кнопки Finish приведет к генерации нового файла, содержащего заготовку класса JGraphicPanel (рис. 53).

Рис. 52. Определение имени и местоположения нового класса

Рис. 53. Заготовка класса JGraphicPanel

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

предложения импорта (рис. 54) (вообще говоря, можно написать extends javax.swing.JPanel, что избавит от необходимости писать предложение импорта).

Рис. 54. Добавляем предложение extends

Опишем во вновь созданном классе следующие поля (рис. 55):

currentX и currentY целого типа – их назначение будет таким же, как у curX и curY в предыдущей «реализации»;

bufImage типа BufferedImage, отвечающее за «сохранение» нарисованного. Разумеется, типы Color и BufferedImage придется импортировать: тип Color определен в пакете java.awt, а тип BufferedImage – в пакете java.awt.image.

Рис. 55. Объявления полей в новом классе

Теперь напишем конструктор этого класса. Конечно, можно выполнить всю работу по его написанию вручную, но среда NetBeans может оказать нам небольшую помощь. Вызовите контекстное меню, щелкнув, например, по свободной строке после объявления поля bufImage и обратитесь к пункту контекстного меню Insert Code (также можно использовать клавиатурную комбинацию Alt + Insert) (рис. 56). Появится список методов, которые среда может сгенерировать (рис. 57). Выберите Constructor, и это приведет к появлению на экране диалогового окна Generate Constructor (рис. 58).

В левой панели этого окна предлагается выбрать конструктор(ы) суперкласса (Select super constructor), которые планируется переопределить в классе-наследнике, а в правой – поля, которые будут проинициализированы в конструкторе.

Рис. 56. Контекстное меню «Вставить код»

Рис. 57. Список того, что может автоматически сгенерировать среда NetBeans

Рис. 58. Окно Generate Constructor

Отметьте в левой панели конструктор класса JPanel() без параметров; в правой же никакие поля выделять не нужно. Каждая поставленная галочка в правой панели означает,

что в заголовке вновь создаваемого конструктора появится соответствующий параметр, имя которого будет совпадать с именем поля, а в коде конструктора – оператор присваивания вида this.<имя поля> = <имя параметра>. Нажмите кнопку Generate. В результате Вы увидите заготовку конструктора (рис. 59).

Рис. 59. Заготовка конструктора

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

Рис. 60. Конструктор дополнен необходимым кодом

Еще один вопрос, который нужно решить, – каким образом разместить объект класса JGraphicPanel в окне приложения. Существуют специальные классы – так называемые менеджеры расположения (Layout managers), которые позволяют создавать пользовательские интерфейсы любой сложности даже без использования визуальных редакторов. В пакете JDK имеются стандартные менеджеры расположения; разумеется, можно самостоятельно разработать свой собственный менеджер (для этого понадобится написать класс, реализующий интерфейс LayoutManager). Пролистав секцию generated code в файле SimpleGraphicEditorView.java (или выполнив поиск в этом файле по слову Layout), Вы можете увидеть код, добавляющий элементы в окно приложения, например, такой, как на рис. 61.

Поскольку создание компонента, который можно было бы поместить в палитру компонентов NetBeans и использовать его так же, как стандартные компоненты, пока не входит в наши планы, то определять размещение объекта – экземпляра класса JGraphicPanel в окне приложения придется вручную. Вместо того, чтобы попытаться определить его позицию относительно окна приложения, мы поступим «проще» –

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

Рис. 61. Пример использования менеджера расположения

В связи с изменившимся назначением переименуем jDrawingPanel в jGraphicPanelContainer. Сделать это можно несколькими способами. Во-первых, с помощью пункта контекстного меню Change Variable Name, использование которого демонстрировалось в начале § 4 (рис. 30). Во-вторых, с помощью диалогового окна Properties, вызываемого из контекстного меню в режиме Design, или в «уменьшенной версии» этого же окна, расположенного в правой части среды. Для этого нужно будет переключиться на вкладку Code (рис. 62) и обратиться к окну Variable Name (рис. 63), нажав кнопку с многоточием. В появившемся окне можно впечатать новое имя панели.

Рис. 62. На вкладке Code отображается имя переменной

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

Переключитесь на вкладку SimpleGraphicEditorView.java в главном окне NetBeans,

перейдите в режим Source, и с помощью контекстного меню Refactor (вызванного щелчком правой клавиши мыши по объявлению переменной jDrawingPanel, расположенного в нижней части файла) выполните операцию Rename (рис. 64).

Соседние файлы в предмете Программирование на Java