Facebook google+ e-mail
Учимся программировать на JAVA
Практикум по программированию на языке Java

Занятие 10. Диалоговые окна (окончание). События (знакомство)

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

Графически эту иерархию панелей можно изобразить так:

Программируем на Java. Диалоговые окна

Самый большой (на рисунке – внешний) прямоугольник, охватывающий все меньшие – это панель содержимого. Панель содержимого создавать не надо; она существует и ею надо просто воспользоваться. Меньшие вложенные прямоугольники – панели, созданные программистом. На их количество не накладывается никаких ограничений; все определяется содержимым, которое необходимо отобразить. Обратившись к исходному коду метода сreateGUI () мы видим, что сначала создаются три панели – главная, панель для размещения метки и, наконец, нижняя панель для размещения кнопок:

JPanel mainPanel = new JPanel (new BorderLayout ()),

         lblPanel = new JPanel (new FlowLayout ()),

         botPanel = new JPanel (new FlowLayout (FlowLayout.RIGHT));

Повторимся: панели метки и кнопок вложены в главную панель. Главная панель по окончании формирования пользовательского интерфейса будет добавлена к панели содержимого диалогового окна. Но что за объекты создаются при описании панелей, что такое BorderLayout и FlowLayout? Даже начальных знаний английского языка должно быть достаточно, чтобы понять, что речь идет о способах расположения (layout) или расстановки компонентов внутри панелей. Здесь мы впервые сталкиваемся с менеджерами компоновки, т.е. механизмом размещения компонентов в панелях.

Главная панель – т.е. самая нижняя из трех созданных нами только что – имеет назначенный менеджер компоновки BorderLayout. Это означает, что компоненты, добавляемые в панель, размещаются по сторонам света – северу (north), югу (south), востоку (east), западу (west) и центру (center):

Программируем на Java. Диалоговые окна

Использовать все стороны – не обязательно; достаточно столько, сколько надо. Вот как это работает:

mainPanel.add (lblPanel, BorderLayout.CENTER);

mainPanel.add (botPanel, BorderLayout.SOUTH);

Здесь, панель меток добавляется в центр главной панели, а панель кнопок – на южную (нижнюю) сторону главной панели.

Панелям метки и кнопок назначен иной менеджер компоновки – FlowLayout, что означает расположение «в ряд» («гуськом», друг за другом). При этом можно указать какой стороны придерживаться – левой, правой или центра (аналогично тому, как мы выравниваем текст в текстовом редакторе, таком, например, как Microsoft Word). Из кода, приведенного выше, следует, что метка располагается в центре своей панели, а кнопки должны пристраиваться так, чтобы заполнять прежде всего правую часть нижней панели:

Программируем на Java. Диалоговые окна

Посмотрите еще раз на диалоговую панель – видите, так и есть: метка в центре, а кнопки – в ряд с выравниванием справа

Программируем на Java. Диалоговые окна

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

Имейте в виде, что панели, которые мы использовали, не имеют собственных видимых границ; это – всего лишь только прямоугольные области с определенными свойствами. Границу можно задать нарисовав рамку:

lblPanel.setBorder (BorderFactory.createEtchedBorder ());

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

Добавление компонентов в панели производится прозрачным образом:

lblPanel.add (confirmLabel);

botPanel.add (closeButton);

botPanel.add (okButton);

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

Кроме BorderLayout и FlowLayout есть и другие менеджеры компоновки, но мы не станем их описывать сейчас: придет время – все, что надо будет рассказано.

Следует иметь в виду, что размеры и расположение компонентов в конкретных панелях будут назначены не вами, а библиотекой swing. Может показаться, что это чрезмерное ограничение, но поверьте – разработчики библиотеки swing очень хорошо поработали и интерфейсы будут выглядеть может быть и не так, как вы себе представляли, но вполне прилично.

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

А нам остается только добавить, что метод createGUI () возвращает в конструктор окна диалога основную панель со всеми расположенными в ней компонентами:

return mainPanel;

которая, как мы неоднократно говорили, будет «прикреплена» поверх панели содержимого диалогового окна.

Последнее, о чем нужно сказать в связи с нашим диалоговым окном – это метод

public boolean getExitFlag () {return exitFlag;}

Назначение метода простое: он возвращает текущее значение флага. На что тут следует обратить внимание? Прежде всего, метод объявлен открытым (public). Это важно, т.к. мы хотим вызывать метод из другого класса, в нашем случае из класса приложения MoneyForNothing

if (exitApp.getExitFlag ()) {

     dispose ();

     System.exit (0);

}

Метод этот, очевидно, возвращает логическое (boolean) значение, которое впоследствии анализируется.

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

Напомним, что неформально событие (англ. event) можно определить как некую информацию, которая сигнализирует о том, что, где и с чем произошло. Событий существует великое множество: нажатие на кнопку, ввод текста, выбор из списка, изменение размеров окна, прокрутка в таблице с данными и т.д. Кроме того, важно помнить, что события происходят асинхронно. Это означает, что события никак «не договариваются» между собой – кому наступать раньше, а кому позже. Они происходят тогда, когда происходят (перефразируя знаменитую фразу из фильма «Форрест Гамп», можно сказать, что «event happens») и уже дело программиста решить – обрабатывать то или иное событие, как именно обрабатывать или просто игнорировать его. Конечно, чтобы события не пропадали (а они могут генерироваться очень быстро и в большом количестве), в библиотеке swing имеется очередь событий, но это тема, которой мы касаться не будем.

Например, движение указателя мыши по окну графического интерфейса порождает определенное событие, позволяющее, в частности, отслеживать координаты указателя. Если ваша программа не предназначена для рисования (вроде программы Paint из стандартного дистрибутива Microsoft Windows), то вы, скорее всего этими событиями не будете интересоваться и проигнорируете их. Но ситуация изменится, если вы нажмете какую-либо кнопку мыши; теперь уже нужно знать в каком месте графического интерфейса произошло нажатие кнопки и обработать событие. Если курсор мыши находился над кнопкой и вы нажали левую клавишу мыши, то это приводит к появлению события нажатия кнопки. Если вы нажали левую кнопку мыши на пустом месте, то, скорее всего, такое событие не нужно принимать во внимание.

Еще пример: допустим, вы разрабатываете приложение для просмотра HTML-страниц. Пока указатель мыши находится над обычным текстом, то курсор мыши имеет одну форму (обычно – стрелка или вертикальная черточка), но как только указатель «налезает» на гиперссылку, курсор должен поменять вид (на ладонь с выставленным указательным пальцем).

Давайте перейдем к конкретному примеру кода воспользовавшись опять же хорошо знакомым нам файлом ConfirmExitDialog.java:

okButton.addActionListener (new ActionListener () {

     public void actionPerformed (ActionEvent e) {

         exitFlag = true;

         dispose ();

     }

});

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

Чтобы событие было полезным, оно должно кому-то предназначаться (что толку в событии если оно никому «не интересно»). Кому же предназначено то или иное событие, кто является ее «потребителем»?

Конечно, можно написать для каждого компонента, который способен порождать события свой специальный код и встраивать этот код непосредственно в код приложения. Но это плохой (а точнее – очень плохой) метод обработки событий. И вовсе не потому, что он не будет работать – если постараться, то будет. Причина в том, что вы замусорите основной код приложения громоздким кодом обработки событий. Лучше поступить так: создать специализированные объекты, которым и поручить обработку событий. Не надо всякий раз изобретать отдельный велосипед на все случаи жизни; достаточно создать не много объектов, но «заточенных» именно для такой работы.

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

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

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

 

Занятие 9. Диалоговые окна (начало)

 

Занятие 11. События (взгляд с высоты)

 

Автор: Alex Tuesday

 

Все уроки ... 24.05.2014