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

Lab05_2010_draft3

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

Инспекторе объектов, либо на самой панели (рис. 30), и выберите пункт Change Variable Namе.

Рис. 30. Контекстное меню для изменения имени панели

В появившемся диалоговом окне (рис. 31). измените имя на jDrawingPanel и нажмите OK. Посмотрите, как внесенное изменение отразится в Инспекторе объектов.

Рис. 31. Окно для переименования переменной

Эта панель и станет полем для рисования. Изменим некоторые ее настройки: сделаем цвет панели (цвет фона для рисования) белым и добавим заметную границу. Для этого можно либо обратиться к панели Properties (рис. 32), либо с помощью пункта Properties контекстного меню элемента вызвать окно Properties (рис. 33).

Рис. 32. Панель Properties находится ниже Палитры компонентов

И панель Properties, и окно Properties имеют 4 вкладки: Properties (Свойства), Binding (Связь), Events (События), Code (Код). В ближайшее время нас будут интересовать только вкладки Properties и Events. Сначала поменяем два свойства – background (фон) и border (границу). Кнопки с многоточием возле этих (и других) свойств свидетельствуют о том, что изменение свойства нужно будет производить в диалоговом окне.

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

Примечание.

Если вы будете использовать для определения цветов вкладку System Palette, то при изменении цветовой схемы операционной системы Ваше приложение так же изменит «окраску».

Вы можете изучить их содержимое, переключаясь между ними, но затем вернитесь к вкладке Swatches (образцы), на которой и выберите белый цвет.

Рис. 33. Окно Properties, вызываемое с помощью контекстного меню

Свидетельством того, что Вы выбрали белый цвет, будет появление белого квадратика в прямоугольнике Recent (на вкладке Swatches) и установке значения (Value) в тройку 255, 255, 255. Нажмите ОК и Вы сможете увидеть, что панель jDrawingPanel поменяла свой цвет (рис. 35). Если Вы работаете с окном, а не с панелью Properties, можете не закрывать его, а просто переместить – следующим шагом станет установка границы.

Обратитесь к диалоговому окну для установки свойства border (рис. 36). В нижней половине этого диалогового окна отображаются свойства для каждого типа границы (если они есть). Вы можете поэкспериментировать с установкой разных границ и разными настройками их свойств. Если затрудняетесь в выборе, остановитесь на Soft Bevel Border с настройками по умолчанию (именно они показаны на рисунке) и нажмите OK. Результат применения этой настройки к панели jDrawingPanel показан на рис. 37. Чтобы рамка выделения не мешала восприятию, щелкните мышкой по белому полю, окружающему

форму, сняв тем самым выделение (можно также воспользоваться Инспектором объектов,

щелкнув по строке Form SimpleGraphicEditorView).

Никакие другие свойства изменять пока не будем.

Рис. 34. Диалоговое окно настройки цвета фона

Рис. 35. Панель jDrawingPanel изменила цвет

Рис. 36. Окно установки свойства border

Рис. 37. К jDrawingPanel добавилась граница

Для того, чтобы посмотреть, какой код был автоматически сгенерирован в результате Ваших действий, переключитесь в режим представления исходного кода (Source) и выполните поиск jDrawingPanel в тексте. Для этого нужно обратиться к меню Edit | Find или же воспользоваться клавиатурной комбинацией Ctrl + F (рис. 38). Любое из этих действий приведет к появлению строки ввода искомого текста и простейшего меню для перемещения между найденными вхождениями. Постарайтесь найти в коде слова background и border (в сочетании с jDrawingPanel, разумеется).

Рис. 38. Вхождения jDrawingPanel в код

§ 5. Понятие о событиях. Создание обработчиков событий

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

Графическая подсистема Java предоставляет возможность рисовать графические объекты разной сложности, но мы пока ограничимся самым простым.

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

Добавьте к классу SimpleGraphicEditorView два поля целого типа curX и int curY –

это будут текущие координаты мыши при рисовании (рис. 39).

Рис. 39. Поля для хранения текущих координат

А теперь нам потребуется некоторый теоретический экскурс, чтобы понять, как работает графический интерфейс (вообще и в Java, в частности). Java предлагает простую и эффективную модель работы с событиями, которую мы кратко опишем.

Событие (event) в программировании понимается как некое действие пользователя или как изменение состояния некоторого компонента (чаще всего элемента интерфейса). Любой графический пользовательский интерфейс в силу этого является управляемым по событиям (event-driven).

События–действия пользователя в Java условно считаются низкоуровневыми (в смысле языка – они являются наследниками класса AWTEvent), а связанные с изменением состояния компонента – высокоуровневыми. Высокоуровневые события возникают как следствие низкоуровневых: допустим, пользователь нажал и отпустил клавишу мыши над кнопкой JButton (сгенерировав тем самым низкоуровневое событие mouseClicked), после чего метод fireActionPerformed (он определен в классе AbstractButton, являющемся непосредственным предком JButton) создает (высокоуровневое) событие ActionEvent и оповещает о нем всех зарегистрированных слушателей.

Каждому типу события соответствует свой слушатель (listener). Контракт слушателя – это интерфейс, содержащий описания группы методов, соответствующий этому типу события. Так, например, интерфейс MouseMotionListener (отслеживающий движения мыши), расширяющий EventListener (слушатель «события вообще»), объявлен следующим образом:

public interface MouseMotionListener extends EventListener {

void mouseDragged(MouseEvent evt);

void mouseMoved(MouseEvent evt);

end;

Таким образом, слушатель, реализующий этот интерфейс, должен реализовать эти методы, тем самым предусмотрев, что компонент будет делать, если мышь перемещается с нажатой клавишей (dragged), и что – если с не нажатой (moved). Заметим, что этот интерфейс содержит всего два описания событий, другие слушатели могут содержать их

куда больше (например, посмотрите в документации объявление интерфейса MouseListener, содержащего все остальные события мыши). С одной стороны, это удобно: все события собраны в нескольких интерфейсах, если происходит какое-либо составное событие, то всё необходимое для его обработки расположено в одном месте. С другой стороны — контракт интерфейса предусматривает реализацию всех описанных в нем методов, но для решения конкретной задачи все методы редко бывают нужны.

Поэтому в Java наряду со слушателями есть абстрактные классы-адаптеры, реализующие интерфейсы слушателей. Каждый из этих классов содержит все описанные в соответствующем интерфейсе методы, но каждый из этих методов имеет «пустое» тело. Например, объявление класса MouseMotionAdapter выглядит так:

public abstract class MouseMotionAdapter implements MouseMotionListener {

void mouseDragged(MouseEvent evt) {};

void mouseMoved(MouseEvent evt) {};

end;

Это позволяет программисту объявлять наследника от класса-адаптера и реализовывать в этом наследнике только необходимые ему методы (для остальных сохраняется «пустая» реализация, присутствующая в классе-предке). Так, в нашем случае необходимо будет следить только за событием mouseDragged, а обычное перемещение мыши отслеживать нет необходимости. (Заметим, впрочем, что использование классовадаптеров или интерфейсов – в значительной степени дело вкуса каждого программиста).

Каждый компонент способен добавлять и удалять слушателей тех или иных событий (методом addZZZListener(<объект-слушатель>), где ZZZ – это и есть тип события, например MouseMotion). Кроме того, компонент способен уведомлять слушателя обо всех изменениях, которые произошли в его состоянии. Ну а слушатель, в свою очередь, обеспечивает реализацию того или иного действия.

NetBeans берет на себя все «стандартные» действия по определению классаслушателя (как наследника класса-адаптера), созданию объекта-слушателя и добавления его к компоненту. Программисту остается написать только собственно тело метода, определяющего реакцию на то или иное событие. Будем называть такие методы обработчиками событий.

Примечание.

Описанная выше модель событий была применена впервые в JavaBeans и затем в библиотеке графических компонентов Swing. Использование компонентов AWT выглядело иначе, но мы его не касаемся: библиотека AWT считается устаревшей (впрочем, библиотека Swing основана на ней). Подробно о модели событий можно прочитать, например, в книге И.А. Портянкина «Swing: Эффектные пользовательские интерфейсы. Библиотека программиста».

Начнем с добавления обработчика события mousePressed (нажата клавиша мыши). Переключитесь в режим отображения визуальных компонентов (Design), выделите элемент jDrawingPanel и на панели Properties или в окне Properties переключитесь на вкладку Events. Наименования событий в списке на вкладке Events расположены по алфавиту. Нажмите на стрелку выпадающего списка в соответствующей событию mousePressed строке (там, где написано <none>) и Вы увидите «заготовленное» название обработчика события jDrawingPanelMousePressed. Выберите его, и произойдет

автоматическое переключение в режим отображения исходного кода, в котором появится «заготовка обработчика события» (рис. 41). Если Вы использовали окно Properties для создания заготовки события, его можно пока закрыть.

Рис. 40. Фрагмент вкладки Events окна Properties

Рис. 41. Заготовка обработчика события нажатия на клавишу мыши

Несмотря на то, что заготовка метода отмечена серым цветом, как и другой автоматически сгенерированный код, тело метода можно редактировать. Текстовый курсор указывает на строку с комментарием, приглашающим добавить собственный код обработки события. Этот код будет весьма простым: в переменные curX и curY будут помещаться координаты мыши в момент нажатия на ее клавишу. Координаты текущего положения мыши (как и ряд других «характеристик») содержатся в объекте evt. Более подробно изучить возможности этого объекта, являющегося экземпляром класса MouseEvent, можно с помощью документации Java (для получения кратких сведений об этом классе воспользуйтесь вкладкой Javadoc).

Обращение к методам getX() и getY() позволит нам узнать текущие координаты мыши в момент, когда была нажата ее клавиша (рис. 42):

Рис. 42. Тело метода jDrawingPanelMousePressed()

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

мыши в текущее, то «предыдущее положение» должно быть задано вне метода, обеспечивающего рисование.

Примечание.

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

Теперь аналогичным образом следует создать заготовку обработчика события mouseDragged. Переключитесь в режим Design и выполните необходимые действия с помощью панели или окна Properties. После автоматического переключения в режим Source Вы увидите код, как на рис. 43.

Рис. 43. Заготовка обработчика события перемещения мыши с нажатой клавишей

Тело вновь созданного метода будет несколько сложнее. Во-первых, нужно будет получить новые текущие координаты мыши (для этого будут использованы локальные переменные x и y). Во-вторых, потребуется провести отрезок прямой между точкой с «предыдущими» координатами (curX и curY) и точкой с новыми координатами. Для того, чтобы провести отрезок прямой, потребуется обратиться к графическому контексту панели jDrawingPanel – получить ее объект Graphics. Затем нужно будет обновить значения «предыдущих» координат, записав в них текущие значения. Это гарантия того, что на следующем «шаге», когда событие mouseDragged вновь произойдет, «стартовой» точкой для проведения нового отрезка послужит конец предыдущего.

Код, который следует написать во вновь созданном обработчике события, показан на рис. 44. Обратите внимание, что класс Graphics потребуется импортировать из пакета java.awt: среда сообщит о том, что этот класс ей неизвестен и, как обычно, предложит либо добавить в код предложение импорта, либо создать такой класс (конечно, выбирать нужно именно добавление предложения импорта).

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