Kodomo

Пользователь

Учебная страница курса биоинформатики,
год поступления 2010

Графический пользовательский интерфейс (GUI)

Взаимодействие с программой часто удобнее осуществлять через графический пользовательский интерфейс (GUI – Graphical User Interface) с кнопочками, окошечками, иконками и др. наглядными элементами. До Java графические библиотеки отражали особенности ОС и, меняя ОС, приходилось привыкать к новым графическим функциям, даже если не менялся язык программирования. Java же, как мы знаем, - кросс-платформенный язык и значит его графические библиотеки не должны зависеть от конкретной графической системы. В Java GUI состоит из двух частей: зависимой от ОС (обычно оно остается скрытым от разработчика) и независимой от ОС.

Есть две основные графические библиотеки java.awt.* и javax.swing.*. Первая содержит помимо всего прочего старые реализации графических элементов.

За графическое окно отвечает класс JFrame, и все конкретные окна должны его наследовать. Пример пустого окна:

   1 import javax.swing.JFrame;
   2 public class TestFrame {
   3         public static void main(String[] args) {
   4                 JFrame frame = new JFrame(“My First Frame”);
   5                 frame.setSize(400,350);
   6                 frame.setVisible(true);
   7         }
   8 }

Это окно вполне полноценно. Но если вы кликнет на крестик, окно скроется, но программа так и продолжит работать. Если вы хотите, чтобы с закрытием окна программа завершалась, надо добавить строчку:

   1 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Важными понятием GUI является компонент (JComponent). Это абстрактный класс – вершина иерархии компонентов в пакете swing. Примерами компонентов могут быть кнопки, лэйблы, текстовые поля и т.д. Рассмотрим основные свойства этого класса:

  1. Положение компонента описывается двумя целыми числами (тип int) x и y. В Java (как и во многих языках программирования) ось x проходит традиционно – горизонтально, направлена вправо, а ось у – вертикально, но направлена вниз, а не вверх, как принято в математике. Для компонента эта точка задает положение левого верхнего угла.

   1 setLocation(int x,int y)
   2 int getX(), int getY()
  1. Размер. Компонент имеет прямоугольную форму, а потому его размер описывается также двумя целочисленными параметрами – width (ширина) и height (высота).

   1 setSize(int x, int y), getWidth(), getHeigth(), setBounds()
  1. Видимость:  setVisible(boolean), isVisible() 

  2. Цвет:  set/get Foreground/Background() .

Цвет хранится в объекте класса Color:  Color(int r, int g, int b), Color.RED 

  1.  Container. Существует еще одно важное свойство другого характера. Очевидно, что практически всегда пользовательский интерфейс состоит из более чем одного компонента. В больших приложениях их обычно гораздо больше. Так вот к каждый компонент можно положить другой компонент (или даже несколько). Таким образом, компонент выступает в роли контейнера. Важно отметить, что компонент может находиться лишь в одном компоненте. Это означает, что все элементы сложного пользовательского интерфейса объединяются в иерархическое дерево. Каждый компонент знает, в каком компоненте он лежит, и какие компоненты лежат в нем. Соответственно положение компонента (x, y) отсчитывается от верхнего левого угла того компонента, в котором он находится.

Контейнеру можно добавлять компоненты, вызвая метод void add(JComponent).

Простые компоненты (наследники JComponent):

Пример окна с лейблом:

   1 import javax.swing.JFrame;
   2 import javax.swing.JLabel;
   3 public class TestFrame
   4 {
   5         public static void main(String[] args)
   6         {
   7                 JFrame frame = new JFrame("My First Frame");
   8                 frame.getContentPane().setLayout(null);// "заклинание", определяющее способ расположения компонентов
   9                 JLabel label = new JLabel("label");
  10                 label.setBounds(30,70,100,20);
  11                 frame.getContentPane().add(label);
  12                 frame.setSize(400, 350);
  13                 frame.setVisible(true);
  14                 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  15         }
  16 }

frame.getContentPane() возвращает главный контейнер окна.

Графические события

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

Что значит реагировать на события с точки зрения программирования? Это значит выполнять определенный код после наступления определенного события. У события всегда есть источник (объект, с которым событие ассоциируется), например кнопка. И слушатель или наблюдатель (он же обработчик). Это класс, содержащий код реакции на событие). Источник всегда знает, какие слушатели к нему прикреплены. Когда с наблюдаемым объектом что-то происходит (например, на кнопку нажали), создается объект "событие" (event), который "посылается" всем слушателям. Так слушатель узнает, например, о действии пользователя и может на него отреагировать в зависимости от свойств события.

Содержимое события

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

   1 Object getSource()
   2 int getX()
   3 int getY()
   4 int getClickCount()
   5 int getButton()

   1 Object getSource()
   2 char getKeyChar()
   3 int getKeyCode()

   1 Object getSource() 

Чтобы между GUI и программой состоялся разговор на языке событий необходимо:

  1. описать класс слушателя: его методы будут вызываться графической системой при наступлении событий и
  2. зарегистрировать экземпляр этого класса в графической системе, то есть присоединить этого слушателя к источнику событий – какому-то компоненту.

Интерфейсы слушателей

Слушатель, получающий информацию о событиях, – это класс, расширяющий специальный интерфейс, соответствующий типу получаемых событий:

(Библиотека java.awt.event)

Интерфейс ActionListener содержит всего один метод:

   1 public interface ActionListener 
   2 {
   3         public void actionPerformed(ActionEvent e); 
   4 }

Чтобы кнопка реагировала как-то на ее нажатие, нужно добавить ей слушателя - объект класса, реализующий интерфейс слушателя (в данном случае ActionListener):

   1 class ButtonListener implements ActionListener 
   2 {
   3         public void actionPerformed(ActionEvent e) 
   4         {
   5                 System.out.println("Меня нажали!!!");
   6         }
   7 }

   1 JButton btn = new JButton();
   2 btn.addActionListener(new ButtonListener());

То же самое можно реализовать без описания класса слушателя отдельно, а воспользоваться анонимной реализацией (также бывает анонимное расширение):

   1 JButton btn = new JButton();
   2 btn.addActionListener(new ActionListener()
   3 {
   4         public void actionPerformed(ActionEvent e) 
   5         {
   6                 System.out.println("Меня нажали!!!");
   7         }
   8 });

Это удобно только в том случае, если вы собираетесь создавать всего один объект этого класса без названия.

Когда объект "кнопка" поймет, что на него нажали и пора оповестить об этом всех слушателей, он создаст послание ActionEvent, пробежится по всем зарегистрированным слушателям (ActionListener), и у каждого из них вызовет метод actionPerformed(ActionEvent).

Интерфейсы слушателей для события MouseEvent:

   1 public interface MouseListener extends EventListener
   2 {
   3    public void mouseClicked(MouseEvent e);
   4    public void mousePressed(MouseEvent e);
   5    public void mouseReleased(MouseEvent e);
   6    public void mouseEntered(MouseEvent e);
   7    public void mouseExited(MouseEvent e);
   8 }
   9 public interface MouseMotionListener extends EventListener
  10 {
  11    public void mouseDragged(MouseEvent e);
  12    public void mouseMoved(MouseEvent e);
  13 }

Для события KeyEvent:

   1 public interface KeyListener extends EventListener
   2 {
   3    public void keyTyped(KeyEvent e);
   4    public void keyPressed(KeyEvent e);
   5    public void keyReleased(KeyEvent e);
   6 
   7 }

Классы-адаптеры

Для интерфейсов некоторых слушателей написаны "пустые" реализации – адаптеры. Это сделано для удобства разработчиков. Удобно это потому, что если мы реализуем интерфейс, то нам придется реализовывать все методы, объявленные в нем, но ведь некоторые методы нам просто не нужны, и нам бы пришлось писать для них пустые реализации. В адаптерах ровно это и сделано. Например:

   1 public class MouseAdapter implements MouseListener
   2 {
   3    public void mouseClicked(MouseEvent e){}
   4    public void mousePressed(MouseEvent e){}
   5    public void mouseReleased(MouseEvent e){}
   6    public void mouseEntered(MouseEvent e){}
   7    public void mouseExited(MouseEvent e){}
   8 }

Пример про убегающую кнопку

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

   1 import java.awt.event.ActionEvent;
   2 import java.awt.event.ActionListener;
   3 import java.awt.event.MouseAdapter;
   4 import java.awt.event.MouseEvent;
   5 
   6 import javax.swing.JButton;
   7 import javax.swing.JFrame;
   8 
   9 public class RunningButton extends JFrame
  10 {
  11         private JButton but;
  12         
  13         public static void main(String[] args)
  14         {
  15                 RunningButton frame = new RunningButton();
  16                 frame.setVisible(true);
  17         }
  18         public RunningButton()
  19         {
  20                 super();
  21                 getContentPane().setLayout(null);
  22                 setDefaultCloseOperation(EXIT_ON_CLOSE);
  23                 setSize(500,300);
  24                 but = new JButton("CATCH ME!");
  25                 but.setBounds(100, 10, 150, 20);
  26                 but.addMouseListener(new ButtonMouseListener());
  27                 but.addActionListener(new ButtonActionListener());
  28                 this.getContentPane().add(but);
  29         }
  30         private class ButtonMouseListener extends MouseAdapter 
  31         {
  32                 public void mouseEntered(MouseEvent e)
  33                 {
  34                         but.setLocation((int)(Math.random()*
  35                                (but.getParent().getWidth()-but.getWidth())), 
  36                                (int)(Math.random()*
  37                                (but.getParent().getHeight()-but.getHeight())));
  38                 }
  39         }
  40         private class ButtonActionListener implements ActionListener
  41         {
  42                 public void actionPerformed(ActionEvent e)
  43                 {
  44                         System.out.println("You are a winner!!!");
  45                 }
  46         }
  47 }