Программирование на языке Java 9. СОЗДАНИЕ ГРАФИЧЕСКОГО ИНТЕРФЕЙСА ПОЛЬЗОВАТЕЛЯ С ПОМОЩЬЮ БИБЛИОТЕК AWT И SWING Язык Java содержит 2 библиотеки классов, предназначенных для разработки приложений, реализующих графический интерфейс пользователя (GUI – graphics user interface): - библиотека AWT (Abstract Window Toolkit – набор абстракций для работы с окнами) поставляется в составе JDK в пакете java.awt - библиотека JFC (Java Foundation Classes) более известная как Swing поставляется в составе JDK в пакете javax.swing. Рис.9.1 В первых версиях языка (Java 1.0, 1.1) программистам была доступна только библиотека AWT, JFC пакет впервые был представлен общественности на "JavaOne developer" конференции в 1997 году и был включен в версию Java 2. Он расширяет функциональность обычных компонентов (меток, кнопок, переключателей, списков и т.п.) и добавляет новые: панели со вкладками, панели с прокруткой, деревья и таблицы и др. Важно отметить, что в отличие от AWT-компонентов Swing-компоненты не реализованы специфическим для платформы кодом. Вместо этого они написаны полностью на Java, поэтому являются платформно независимыми. Такие элементы принято называть облегченными (lightweight). Хотя Java 2 продолжает поддерживать пакет AWT, но по приведенным выше причинам Sun настоятельно рекомендует использовать Swing. Для облегчения работы программистов 108 Программирование на языке Java названия Swing элементов начинаются с буквы J в отличие от названий в AWT (например, Button в AWT и JButton в Swing). Часть иерархии классов библиотек AWT и Swing представлена на рис.9.1. Основные классы библиотек AWT и Swing Основное понятие, заложенное в графические библиотеки – компонент графической системы. Компонент – отдельный, полностью определенный элемент, который можно использовать в GUI независимо от других элементов. Например, это поле ввода, кнопка, строка меню, полоса прокрутки, «радиопереключатель» и т.п. Само окно приложения – тоже его компонент. В Java компонентом считается объект класса Component или одного из классов, расширяющих Component. В классе Component определены общие методы работы с любым компонентом GUI. Этот класс – вершина иерархии графических библиотек, поэтому его необходимо рассмотреть подробнее. Класс Component Класс Component является абстрактным и не может использоваться сам по себе, применяются только унаследованные от него подклассы. В этом классе определены методы, отвечающие за управление событиями, позиционирование и изменение размеров окна, перерисовку окна и т.п. Компонент всегда занимает прямоугольную область окна со сторонами, параллельными сторонам экрана. В компоненте есть система координат. Ее начало – точка с координатами (0,0) – находится в левом верхнем углу компонента. Оси направлены так как показано на рис.9.2. Ox Oy Рис.9.2 Высоту и ширину компонента можно узнать с помощью метода Dimension getSize() Этот метод возвращает объект класса Dimension в полях width и height, которого хранятся ширина и высота компонента. Ту же задачу можно решить с помощью методов int getWidth() int getHeight() класса Component. Разница заключается в том, что в объекте класса Dimension переменные width и height хранятся в виде чисел типа double, а методы класса Component возвращают числа типа int. Чтобы установить положение и размеры компонента можно воспользоваться методом setBounds(int x, int y, int width, int height) Доступность компонента и его видимость на экране определяется с помощью методов isEnabled() isVisible() Управлять этими параметрами можно с помощью методов setEnabled(boolean b) setVisible(boolean b) 109 Программирование на языке Java Класс Container Каждый компонент перед выводом на экран должен быть помещен в контейнер – специальный объект, отвечающий за размещение компонентов на экране. Контейнер может содержать набор компонентов, которые добавляются к нему с помощью метода Component add(Component comp) и другие контейнеры. В языке Java контейнер – объект класса Container или всякого его расширения. Класс Container сам является невидимым компонентом, он расширяет класс Component. Все класс окон унаследованы от класса Container. Классы окон Класс JFrame Контейнер JFrame это готовое окно со строкой заголовка, в которую помещены кнопки контекстного меню, сворачивания/разворачивания окна, закрытия приложения. Окно типа Frame имеет рамку, которая позволяет перемещать его и изменять его размеры с помощью мыши. Конструкторы класса JFrame: JFrame() JFrame(String title) Первый конструктор создает окно с пустой строкой заголовка. Второй – окно со строкой заголовка, задаваемой параметром title. Заголовок окна можно создать и позже – методом setTitle(String title) Созданное окно типа Frame, вначале является невидимым. Чтобы сделать его видимым, следует вызвать метод setVisible(Boolean state) класса Component, рассмотренный выше. Окно типа JFrame после создания автоматически регистрируется в оконном менеджере графической оболочки. Класс JWindow Контейнер JWindow – это пустое окно без рамки, строки заголовка, строки меню, полос прокрутки, т.е. это просто прямоугольная область на экране. Оно не регистрируется в оконном менеджере графической оболочки, следовательно его нельзя перемещать и менять размеры средствами операционной системы. Окно типа Window может быть создано только уже существующим окном-владельцем. Когда окно-владелец убирается с экрана, вместе с ним убирается и порожденное окно. Конструкторы класса Window: JWindow(JFrame f) JWindow(JWindow w) Первый конструктор – создает окно, владелец которого – фрейм f. Второй – окно, владелец которого – уже имеющееся окно или подкласс класса Window. Уничтожить окно, освободив занимаемы им ресурсы, можно методом: void dispose() 110 Программирование на языке Java Окно типа Window можно использовать для создания всплывающих окон предупреждения., сообщений, подсказок. Класс JDialog Класс JDialog – это окно фиксированного размера, предназначенное для ответа на сообщения приложения. Оно автоматически регистрируется в оконном менеджере графической оболочки, следовательно, его можно перемещать по экрану, менять размеры. Окно типа JDialog, как и его суперкласс – окно типа Window – обязательно должно иметь владельца, который указывается в конструкторе. Окно типа JDialog может быть модальным либо немодальным. В классе JDialog есть семь конструкторов: JDialog(JDialog owner) Создает немодальное диалоговое окно с владельцем owner и пустой строкой заголовка JDialog(JDialog owner, String title) Создает немодальное диалоговое окно с владельцем owner и строкой заголовка title JDialog(JDialog owner, String title, boolean modal) Создает диалоговое окно с владельцем owner и строкой заголовка title. Окно будет модальным, если параметр modal == true. Следующие 4 конструктора аналогичны, но создают диалоговые окна, принадлежащие окну типа Frame. JDialog(JFrame JDialog(JFrame JDialog(JFrame JDialog(JFrame owner) owner, boolean modal) owner, String title) owner, String title, boolean modal) Класс JFileChooser Класс JFileChooser – это диалоговое окно, содержащее стандартное окно File Load…/File Save As…. Класс JFileChooser находится в пакете javax.swing.filechooser. Основные конструкторы класса JFileChooser: JFileChooser() Создает окно со списком файлов из текущего каталога JFileChooser(String path) Создает окно со списком файлов из каталога, указанного в path Методы File getSelectedFile() и String getName(File f) возвращают соответственно выбранный файл и его имя в виде строки. Можно установить начальный каталог для поиска файла методом void setCurrentDirectory(File f). Пример: JFileChooser chooser = new JFileChooser(); int returnVal = chooser.showOpenDialog(null); if(returnVal == JFileChooser.APPROVE_OPTION) { System.out.println("You chose to open this file: " + chooser.getSelectedFile().getName()); } Ограничить множество отображаемых файлов можно создав специальный класс, унаследованный от абстрактного класса FileFilter, и реализовав в этом классе метод accept(). 111 Программирование на языке Java Графический контекст При создании компонента автоматически формируется его графический контекст (graphics context). Контекст содержит текущий и альтернативный цвет рисования и цвет фона, текущий шрифт для вывода текста, систему координат (см.рис.9.2). Управляет контекстом класс Graphics. Т.к. графический контекст сильно зависит от конкретной графической платформы, этот класс является абстрактным. Каждя JVM реализует методы этих классов, создает их экземпляры для компонента. Получить ссылку на созданный графический контекст можно с помощью метода Graphics getGraphics() После получения cсылки на графический контекст, можно пользоваться методами класса Graphics для работы с графикой и текстом. Основные методы класса Graphics представлены в таблице 9.1. Таблица 9.1 Метод Описание drawLine(int x1,int y1, int x2, Вычерчивает текущим цветом отрезок прямой между int y2) точками (x1,y1) и (x2,y2) drawRect(int x, int y, int Чертит прямоугольник со сторонами, параллельными width, int height) краям экрана, задаваемый координатами верхнего draw3DRect(int x, int width, int height, raised) y, int boolean drawOval(int x, int width, int height) y, int drawArc(int x, int y, int width, int height, int startAngle, int arc) drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) drawPolyline(int xPoints[], int yPoints[], int nPoints) drawPolygon(int xPoints[], yPoints[], int nPoints) drawPolygon(Polygon p) угла (x,y), шириной width и высотой height Чертит прямоугольник, «выделяющийся» из плоскости рисования, если raised = true и «вдавленный» в плоскость, если raised = false Чертит овал, вписанный в прямоугольник, заданный аргументами метода (если width = height – окружность) Чертит дугу овала, вписанного в прямоугольник, заданный первыми четырьмя аргументами. Дуга имеет величину arc градусов и отсчитывается от угла startAngle. Угол отсчитывается в градусах от оси Ox. Положительный угол отсчитывается против часовой стрелки, отрицательный – по часовой стрелке. Чертит прямоугольник с закругленными краями. Закругления вычерчиваются четвертинками овалов, вписанных в прямоугольники шириной arcWidth и высотой arcHeight, построенные в углах основного прямоугольника. Чертит ломаную линию с вершинами в точках (xPoints[i], yPoints[i]) и числом вершин nPoints int Чертит замкнутую ломаную с вершинами в точках (xPoints[i], yPoints[i]) и числом вершин nPoints Чертит замкнутую ломаную, вершины которой заданы объектом p класса Polygon (этот класс подробнее рассматривается ниже) 112 Программирование на языке Java fillRect(int x, int y, int width, int height) fill3DRect(int x, int y, int width, int height, boolean raised) fillOval(int x, int y, int width, int height) fillArc(int x, int y, int width, int height, int startAngle, int arc) fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) fillPolyline(int xPoints[], int yPoints[], int nPoints) fillPolygon(int xPoints[], int yPoints[], int nPoints) fillPolygon(Polygon p) drawString(String s, int x, int y) Эти методы аналогичны соответствующим методам draw…(), но в отличие от них вычерчивают фигуры, залитые текущим цветом Выводит строку s. Вывод начинается с позиции (x,y). drawBytes(byte b[],int offset, Выводит length элементов массива b, начиная с инint length, int x, int y) декса offset. Вывод начинается с позиции (x,y). drawChars(char ch[],int offset, Выводит length элементов массива ch, начиная с int length, int x, int y) индекса offset. Вывод начинается с позиции (x,y). Класс Color Цвет в Java – объект класса Color. В классе Color 7 конструкторов: Color(int r, int g, int b) Создается цвет, получающийся смешением красной (r), зеленой (g) и синей (b) составляющих (модель RGB). Значение интенсивности каждой составляющей меняется от 0 до 255. Color(int rgb) Все три составляющие цвета задаются одним числом. В битах 16-23 – красная составляющая, в битах 8-15 – зеленая, в битах 0-7 – синяя. Color(float r, float g, float b) Аналогичен первому, но составляющие модели RGB задаются вещественными числами от 0.0 до 1.0, что позволяет изменять их более плавно. Color(int r, int g, int b, int a) Color(float r, float g, float b, float a) В этих конструкторах вводится четвертая составляющая (a), определяющая прозрачность цвета. Она может меняться от 255 (цвет совершенно не прозрачен – предыдущий цвет не виден) до 0(цвет абсолютно прозрачен – для каждого пиксела виден только предыдущий цвет). Color(int rgba, boolean hasAlpha) Данный конструктор учитывает прозрачность цвета исходя из значения параметра hasAlpha. Если hasAlpha = true, в качестве значения прозрачности используются биты 24-31 параметра rgba, если hasAlpha = false, прозрачность считается равной 255. Color(ColorSpace cspace, float[] components, float alpha) 113 Программирование на языке Java Данный конструктор позволяет создавать цвет в цветовых моделях, отличных от RGB. Например, CMYK, HSB и т.п. Тип цветовой модели задается параметром ColorSpace. Если нет необходимости тщательно подбирать цвета, можно воспользоваться одной из статических констант типа Color, имеющихся в классе Color. Таких констант 13: black, blue, cyan, darkGray, gray, green, lightGray, magenta, orange, pink, red, white, yellow. Класс Polygon Этот класс предназначен для работы с многоугольниками. Объекты данного класса можно создать двумя конструкторами: Polygon() Создается пустой объект. Polygon(int xPoints[], int yPoints[], int nPoints) Создается многоугольник с вершинами (xPoints[i], yPoints[i]). Число вершин – nPoints. Данный класс содержит методы, позволяющие легко проверить, лежит ли в многоугольнике заданная точка, отрезок или целый прямоугольник. Основные методы класса Polygon собраны в таблице 9.2. Таблица 9.2 Метод Описание Проверяет, лежит ли точка (x,y) внутри многоугольника boolean contains(double x, double y, Проверяет, лежит ли прямоугольник, заданdouble w, double h) ный аргументами метода внутри многоугольника boolean contains(int x, int y) Проверяет, лежит ли точка (x,y) внутри многоугольника boolean contains(Point p) Проверяет, лежит ли точка (x,y) внутри многоугольника boolean intersects(double x, double Проверяет, пересекается ли прямоугольник, y, double w, double h) заданный аргументами метода с многоугольником boolean contains(double x, double y) В следующем примере строится квадрат. Выбирается случайная точка, выводятся ее координаты и проверяется ее принадлежность квадрату. Пример 9.2: import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.Random; class Rect {public static void main(String args[]) {int xPoints[] = new int[4]; int yPoints[] = new int[4]; int x,y; 114 Программирование на языке Java JFrame f = new JFrame(); f.setBounds(10,10,500,200); f.setVisible(true); Graphics g = f.getGraphics(); g.setColor(new Color (0,0,255)); Random r = new Random(); xPoints[0]=20;yPoints[0]=70; xPoints[1]=280;yPoints[1]=70; xPoints[2]=280;yPoints[2]=150; xPoints[3]=20;yPoints[3]=150; x = r.nextInt (500); y = r.nextInt (200); Polygon p = new Polygon(xPoints,yPoints,4); g.drawPolygon (p); g.setColor(new Color (255,0,0)); if (p.contains (x,y)==true) g.drawString ("Точка " + x + " " + y + " попадает в прямоугольник", 20,50); else g.drawString ("Точка " + x + " " + y + " не попадает в прямоугольник", 20,50); f.addWindowListener (new WindowAdapter() {public void windowClosing(WindowEvent ev) {System.exit (0); } }); } } Вывод этой программы: Элементы управления Библиотеки AWT и Swing поддерживает следующие основные элементы управления: Текстовые метки Кнопки Флажки «Радиопереключатели» 115 Программирование на языке Java Списки Поля со списком Текстовые поля Текстовые области Панели прокрутки Панели с вкладками Деревья Таблицы Все элементы управления реализованы как объекты специальных классов, являющихся подклассами класса Component. Как уже говорилось ранее, каждый компонент (в т.ч. элемент управления) должен быть включен в некоторый контейнер (подкласс класса Container). В библиотеке AWT таким контейнером является само окно. Для добавления элемента управления к окну необходимо использовать одну из форм метода add( ), определенного в классе Container. Самая простая форма выглядит следующим образом: Component add(Component obj) Здесь obj – экземпляр элемента управления, который добавляется к окну. Метод возвращает ссылку на объект, который передается параметром obj. Сразу после добавления эле- мент будет выводиться на экран автоматически, когда отображается его «родительское» окно. Удаление элемента управления из окна производится методом void remove (Component obj). Вызывая метод removeAll() можно удалить сразу все присоединенные к окну элемен- ты управления. Управлять положением элемента управления относительно окна, в котором он размещен, можно с помощью методов setBounds( ) и getBounds( ). Формат этих методов: void setBounds(int x, int y, int width, int height) void setBounds(Rectangle r) Rectangle getBounds() В компоненте хранятся координаты его левого верхнего угла в системе координат «родительского» окна. Узнать их можно с помощью метода: Point getLocation() а изменить с помощью методов: void setLocation(int x, int y) void setLocation(Point p) Все элементы управления, за исключением текстовых меток, могут взаимодействовать с пользователем, генерируя некоторые события, которые в программе можно идентифицировать и обрабатывать. Модель обработки событий, реализованная в языке Java, будет рассматриваться ниже. В библиотеке Swing компоненты перед выводом на экран должны быть помещены не в окно, а внутрь специального контейнера, который называется панель содержания (content pane). Этот контейнер не нужно создавать, его можно получить для окна подобно графическому контексту: JFrame f = new JFrame("Test"); Container cp = f.getContentPane(); После этого все операции добавления/удаления компонентов выполняются для панели содержания, а не для самого окна. 116 Программирование на языке Java Графические изображения В библиотеке Swing графические изображения инкапсулированы классом ImageIcon, реализующим интерфейс Icon. Конструктор класса ImageIcon: ImageIcon(String filename) Основные методы класса ImageIcon: int getIconHeight() int getIconWidth() void paintIcon(Component comp, Graphics g, int x, int y) Текстовые метки Самый простой для использования компонент графического интерфейса – текстовая метка (label). Текстовые метки – это объекты класса JLabel, содержащие одну строку статического текста и/или графическое изображение. Среди всех элементов графического интерфейса только метки являются пассивными, т.е. не поддерживают никакого взаимодействия с пользователем во время выполнения. Конструкторы класса JLabel: JLabel (String str) JLabel (Icon id_icon) JLabel (String str, Icon id_icon, int align) создает метку, содержащую строку str и/или графическое изображение id_icon. Выравнивание строки определяется параметром align. Значением align должна быть одна из трех констант, определенных в классе JLabel: JLabel.LEFT - выравнивание по левому краю JLabel.RIGHT - выравнивание по правому краю JLabel.CENTER - выравнивание по центру Текст в метке можно устанавливать или изменять с помощью метода void setText(String str) Текущую метку можно получить, используя метод String getText( ) Управлять выравниванием текста можно с помощью методов void setAlignment(int align) int getAlignment( ) Графическое изображение в метке можно устанавливать или изменять методами: void setIcon(Icon id_icon) Текущее графическое изображение можно получить, используя метод Icon getIcon( ) Управляющие кнопки Управляющая кнопка – это объект класса JButton. Кнопка может содержать текстовую строку (надпись на кнопке) и/или графическое изображение. Она генерирует события в ответ на щелчок мышью. Основные конструкторы класса JButton: JButton(String str) JButton(Icon id_icon) Методы, позволяющие управлять видом кнопки: 117 Программирование на языке Java String getLabel( ) void setLabel(String str) Icon getLabel( ) void setIcon(Icon id_icon) Флажки – переключатели Флажки-переключатели являются объектами класса JCheckBox. Самая общая форма конструктора: JCheckBox (String str, Icon id_icon, boolean state) Управление состоянием флажка из программы осуществляется с помощью методов: boolean getSelected() void setSelected(boolean state) Группы кнопок («радиопереключатели») «Радиопереключатели» в библиотеке Swing реализованы как объекты класса JRadioButton. Самая общая форма конструктора: JRadioButton (String str, Icon id_icon, boolean state) «Радиопереключатели» должны быть объединены в группу, в пределах которой будет обеспечиваться уникальность выбора элемента. Чтобы создать группу создается экземпляр объекта специального класса ButtonGroup. Далее все созданные радиопереключатели добавляются в созданную группу (что не отменяет необходимости их добавления к панели содержания). Пример: JFrame f = new JFrame(); Container cp = f.getContentPane(); JRadioButton jrb1 = new JRadioButton("a",false); JRadioButton jrb2 = new JRadioButton("b",false); JRadioButton jrb3 = new JRadioButton("c",true); ButtonGroup bg = new ButtonGroup(); bg.add(jrb1); bg.add(jrb2); bg.add(jrb3); cp.add(jrb1); cp.add(jrb2); cp.add(jrb3); Раскрывающиеся списки Раскрывающийся список – компонент класса JComboBox. Создать раскрывающийся список можно с помощью одного из конструкторов: JComboBox() JComboBox(Vector v[]) JComboBox(Object obj[]) Далее в список можно добавлять новые пункты с помощью методов: addItem(Object item) Новые строки будут добавляться к списку в том порядке в котором выполнялись вызовы метода addItem( ). Вставить строку в список в определенную позицию (index) можно методом: 118 Программирование на языке Java insertItemAt(Object anObject, int index) Удаление строк из списка: void removeItem(String text) void removeItemAt(int index) void RemoveAllItems() Для определения текущего выбранного элемента можно использовать методы String getSelectedItem( ) int getSelectedIndex( ) Первый метод возвращает строку с именем элемента, а второй – номер выбранной строки. Строки в списке нумеруются от 0. По умолчанию выбранным считается нулевая строка. Чтобы получить текущее количество элементов в списке используется метод: int getItemCount( ) Зная номер строки в списке можно получить ее имя с помощью метода: String getItemAt(int index) Можно произвести выбор пункта в списке из программы с помощью методов: void setSelectedIndex (int index) void setSelectedItem (Object obj) По умолчанию раскрывающийся список является не редактируемым. Чтобы сделать его редактируемым, необходимо использовать метод: void setEditable (boolean state) Списки Списки – объекты класса JList. В них допускается множественный выбор. Стандартный объект класса JList – неизменяемый список, поэтому его необходимо заполнять данными в момент создания. Конструкторы: JList(Vector v[]) JList(Object obj[]) Кроме того объекты типа JList не поддерживают автоматическую прокрутку. Поэтому для того, чтобы элементы в списке могли прокручиваться, список необходимо поместить в специальный объект JScrollPane, а уже этот объект добавить в контейнер. Пример: JFrame f = new JFrame(); Container cp = f.getContentPane(); f.setBounds(100,100,300,300); String s[] = {"1","2","3","4","5","6","7","8","9","10"}; JList jl = new JList(s); jl.setBounds(10,10,30,30); JScrollPane p = new JScrollPane(jl); cp.add(p); f.setVisible(true); Для определения выбранного элемента (элементов) используются методы: Object getSelectedValue() Object[] getSelectedValues() int getSelectedIndex( ) int[] getSelectedIndices( ) 119 Программирование на языке Java Текстовые поля Однострочная область ввода текста (текстовое поле) – объект класса JTextField. Текстовые поля дают возможность вводить строки, редактировать их с помощью клавиш-стрелок, Backspace, Delete, пользоваться буфером обмена. Конструкторы: JTextFiled( ) JTextFiled(int numChars) JTextFiled(String str) JTextFiled(String str, int numChars) Первая форма создает пустое текстовое поле. Вторая текстовое поле шириной numChars символов. Третья – инициализирует текстовое поле строкой str. Четвертая – инициализирует текстовое поле и задает его ширину. Основные методы класса JTextField: String getText() Возвращает строку, содержащуюся в поле ввода. void setText(String str) Устанавливает в поле ввода текст str. String getSelectedText() Пользователь может выделять часть текста в текстовом поле с помощью клавиатуры или мыши. Метод getSelectedText() возвращает выделенную часть текста. void select(int start, int end) Этот метод позволяет программно выделить часть текста в поле ввода начиная с позиции start до позиции end. Следующие два метода управляют доступностью текстового поля для редактирования. boolean isEditable( ) void setEditable(boolean canEdit) В обоих методах true означает доступность текста для изменения. Если необходимо, чтобы пользователь мог вводить текст без его отображения в текстовом поле (например, пароли), то нужно воспользоваться методом void setEchoChar(char ch) ch – символ, который будет отображаться вместо фактически вводимого. Текстовые области Текстовая область (многострочное поле ввода) – объект класса JTextArea. Нажатие клавиши Enter переводит курсор в начало следующей строки. В текстовой области могут быть установлены линейки прокрутки. Конструкторы: JTextArea( ) JTextArea(int numLines, int numChars) JTextArea(String str) JTextArea(String str, int numLines, int numChars) numLines определяет высоту текстовой области в строках, numChars определяет ширину текстовой области в символах, str – начальный текст. Объект JTextArea поддерживает все методы, описанные выше для класса JTextField. В дополнение к ним поддерживаются методы: void append (String str) Строка str добавляется к концу текущего текста 120 Программирование на языке Java void insert (String str, int index) Строка str вставляется в позицию, указанную в параметре index. void replaceRange(String str, int start, int end) Заменяет символы от start до end-1 строкой str. Для обеспечения горизонтальной и вертикальной прокрутки компоненты JTextField и JTextArea должны быть помещены в контейнер JScrollPane. 121 Программирование на языке Java 122 Программирование на языке Java 123 Программирование на языке Java 124 Программирование на языке Java 125 Программирование на языке Java 126 Программирование на языке Java 127 Программирование на языке Java 128 Программирование на языке Java Расщепленные окна Специальный контейнерный класс JSplitPane (расщепленное окно) показывает две компоненты, расщепленные либо по вертикали, либо по горизонтали. Разграничительная полоса между ними является управляющим элементом, перетаскивая который с помощью мыши пользователь может распределять долю видимой площади для каждого компонента. В качестве каждой из этих двух компонент можно использовать другое расщепленное окно. Степень вложения не ограничивается, так что можно конструировать очень сложные окна с множественным расщеплением. Разработчики Swing рекомендуют вместо прямого добавления пары элементов в расщепленное окно вкладывать их сначала в контейнер ScrollPane. (см. выше), а затем его уже добавлять в расщепленное окно. Это даст возможность прокручивать и видеть любую часть исходных компонентов без перемещения разграничительной полосы, двигать которую для удобства лучше только в случае крайней необходимости. Ниже показан пример программы, использующей расщепленное окно. В левой части показан список имен графических файлов, а справа - выбранная картинка. 129 Программирование на языке Java Ползунковый регулятор Использование класса JSlider (ползунковый регулятор) дает возможность пользователю вводить численную величину, ограниченную заданными минимальным и максимальным значением. Используя JSlider вместо ввода в текстовое поле, пользователь гарантируется от ошибок. Кроме того, операция передвижения ползунка с помощью мыши осуществляется быстрее, чем набивка руками на клавиатуре. Класс JSlider имеет множество методов, позволяющих пользователю формировать подходящий вид регулятора, включая размеры, шкалу и оцифровку. Ниже показан пример типичного ползункового регулятора. Указатель полноты выполнения процесса Некоторые задачи, запускаемые приложением, могут занимать какое-то время. Дружественный интерфейс предоставляет пользователю индикатор, информирующий его о том, какая часть работы уже сделана и сколько еще осталось. В пакете Swing имеется три класса, обеспечивающие подобные функции. JProgressBar - компонент, отображаемый на экране в виде равномерно движущейся полоски, показывающей, какая часть полной работы уже выполнена. ProgressMonitor - не отображаемый на экране компонент. В процессе выполнения какойлибо задачи этот класс отслеживает ход ее выполнения (проводит мониторинг) и в какой-то определенный момент, если возникает необходимость, выставляет на экран диалог. ProgressMonitorInputStream - это обычный входной поток с присоединенным к нему объектом ProgressMonitor, для отслеживания процесса чтения данных из потока. С помощью метода класса getProgressMonitor() пользователь может получить экземпляр класса ProgressMonitor и затем использовать его для анализа процесса чтения. Ниже показано приложение, использующее класс JProgressBar. 130 Программирование на языке Java Всплывающая подсказка Все классы Swing, наследующие класс JComponent, могут использовать вплывающую подсказку, представляющую собой маленькое окно с некоторым поясняющим текстом, которое появляется всякий раз, когда пользователь удерживает курсор мыши некоторое малое время на данном компоненте. Создать всплывающую подсказку очень легко. Нужно просто использовать метод setToolTipText(String s) с аргументом, содержащим нужный поясняющий текст. Ниже показано приложение, использующее всплывающую подсказку для кнопки JButton. Менеджеры компоновки Хотя все компоненты окна можно позиционировать вручную (с помощью метода setBounds()) такой способ позиционирования имеет множество недостатков и как правило не применяется. Во-первых, очень утомительно рассчитывать координаты позиционирования для каждого компонента, во-вторых, при изменении размеров окна с помощью мыши все компоненты останутся на своих местах, «привязанные» к левому верхнему углу окна, в-третьих, внешний вид окна и размещенных в нем элементов будет в значительной степени зависеть от графической подсистемы конкретного компьютера (например, от разрешения экрана), что не соответствует концепции кроссплатформности. Поэтому были разработаны специальные программные средства для автоматического управления размещением компонентов внутри контейнера. Средства автоматического размещения компонентов организованы в библиотеке AWT с помощью интерфейса (LayoutManager) и пяти классов, реализующих этот интерфейс (BorderLayout, CardLayout, FlowLayout, GridLayout, GridBagLayout). Эти классы получили название менеджеров размещения или менеджеров компоновки. Каждый компонент класса Container или одного из его подклассов (например, любое окно) имеет связанный с ним менеджер компоновки, т.е. экземпляр некоторого класса, реализующего интерфейс LayoutManager. 131 Программирование на языке Java Менеджер компоновки устанавливается методом void setLayout(LayoutManager obj) здесь obj - ссылка на необходимый менеджер компоновки. Если необходимо отключить менеджер компоновки и позиционировать компоненты в окне вручную, необходимо передать в качестве параметра obj значение null. Менеджер компоновки применяется каждый раз, когда к контейнеру добавляется новый компонент, или контейнер изменяется в размерах. Рассмотрим встроенные менеджеры компоновки. Менеджер FlowLayout FlowLayout – это менеджер поточной компоновки. Он размещает компоненты в окне начиная от левого верхнего угла слева направо и сверху вниз. Между компонентами по вертикали и горизонтали оставляется небольшое пространство. Кроме того, в каждом ряду можно управлять выравниванием компонентов. Конструкторы FlowLayout: FlowLayout (int align, int h, int v) Данный конструктор задает размещение потоковое размещение элементов, где между компонентами по вертикали оставляется промежуток v пикселов, а по горизонтали – h пикселов. Выравнивание компонентов в рядах определяет параметр align. Он должен принимать одно из следующих значений: FlowLayour.LEFT FlowLayout.RIGHT FlowLayout.CENTER Следующий конструктор: FlowLayout (int align) Выравнивание задается параметром align а промежутки между компонентами по горизонтали и по вертикали задаются равными 5 пикселов. Третий конструктор: FlowLayout () задает размещение с выравниванием по центру и промежутками между компонентами по горизонтали и по вертикали равными 5 пикселов. После создания размещения его параметры можно изменять с помощью методов: void setAlignment(int align) void setHgap(int hgap) void setVgap(int vgap) Менеджер FlowLayout является менеджером размещения установленным по умолчанию для класса Panel (т.е. если методом setLayout() не был установлен другой менеджер размещения, то компоненты будут размещаться поточным способом). Пример 9.4: Frame f = new Frame(“FlowTest”); f.setLayout (new FlowLayout(FlowLayout.LEFT, 10,10)); Менеджер BorderLayout Класс BorderLayout реализует граничный стиль компоновки. При этом контейнер делится на 5 неравных областей, заполняя каждую область одним компонентом как показано на рис. 9.3. Области получили географические названия NORTH, SOUTH, EAST, WEST, CENTER. Добавлять компоненты в этом случае можно с помощью специальной формы метода add(): 132 Программирование на языке Java void add (Component comp, Object region) где параметр region должен принимать одно из следующих значений: BorderLayout.NORTH BorderLayout.SOUTH BorderLayout.EAST BorderLayout.WEST BorderLayout.CENTER North West Center East South Рис.9.3 Можно также пользоваться обычным методом add(), в этом случае компонент будет помещен в область CENTER. Если какая то из областей контейнера не используется для размещения объектов, то эта область не занимает места в контейнере (см. пример 9.5). Конструкторы класса BorderLayout: BorderLayout () BorderLayout (int horz, int vert) Первый конструктор задает размещение без промежутков между областями, вторая определяет между областями промежутки horz пикселов по горизонтали и vert пикселов по вертикали. BorderLayout является менеджером размещения установленным по умолчанию для классов Window, Frame, Dialog. Удобство этого менеджера в том, что в каждую из областей можно поместить не компонент, а панель (объект класса Panel), и размещать на ней компоненты в соответствии с менеджером FlowLayout принятым по умолчанию для класса Panel. Далее показан пример такого размещения. Пример 9.5: import java.awt.*; Frame f = new Frame(); // Создаем р2.add(new р2.add(new р2.add(new панель р2 с тремя кнопками Panel р2 == new Panel(); Button("Выполнить")); Button("Отменить")) ; Button("Выйти")); // Создаем панель p1 и устанавливаем для нее компоновку BorderLayout Panel p1 == new Panel(); p1.setLayout(new BorderLayout()); // Помещаем панель р2 с кнопками на "юге" панели р1 р1.add (р2, BorderLayout.SOUTH); 133 Программирование на языке Java // Поле ввода помещаем на "севере" панели p1 p1.add(new TextField("Поле ввода", 20), ВоrderLayout.NORTH); // Область ввода помещается в центре панели p1 р1.add(new TextArea ("Область ввода", 5, 20, TextArea.SCROLLBARS_NONE), BorderLayout.CENTER); //добавляем к основному окну линейки прокрутки на «юге» и «востоке» f.add (new Scrollbar (Scrollbar. HORIZONTAL), BorderLayout.SOUTH); f.add(new Scrollbar(Scrollbar.VERTICAL), BorderLayout.EAST) ; // Панель р1 помещаем в "центре" контейнера f.add(p1, BorderLayout.CENTER) ; setSize(300, 200); setVisible(true); В результате выполнения этого фрагмента компоненты будут размещены как показано на рис.9.4. Рис.9.4 Менеджер GridLayout Менеджер GridLayout размещает компоненты в двумерной сетке (иногда такое размещение называют табличным). Число строк и столбцов сетки следует задавать при создании экземпляра объекта GridLayout. Компоненты размещаются слева направо по строкам созданной таблицы в том порядке, в котором они заданы методом add(). Конструкторы, определенные в классе GridLayout: GridLayout() GridLayout(int numRows, int numColumns) GridLayout(int numRows, int numColumns, int horz, int vert) Конструктор по умолчанию задает таблицу, в которой одна строка, а число столбцов определяется в зависимости от количества размещаемых компонентов по принципу: каждый компонент в своем столбце. Вторая форма конструктора определяет размещение с указанным числом строк и столбцов. Третья форма конструктора позволяет задать между ячейками таблицы горизонтальные и вертикальные промежутки. Указание нулевого количества строк или столбцов означает, что менеджер компоновки создает нужное число строк и столбцов в зависимости от числа размещаемых компонентов. Также следует заметить, что если одновременно 134 Программирование на языке Java указано ненулевое число строк и столбцов, то заданное значение для числа столбцов игнорируется, как если бы в качестве этого параметра был задан 0. Вместо этого, количество столбцов определяется исходя из количества строк и числа размещаемых компонентов (для каждого компонента – своя ячейка). Параметр, отвечающий за количество столбцов действует только в том случае, если количество строк указано равным 0 (тогда количество столбцов равно заданному, а количество строк зависит от числа размещаемых компонентов). Пример 9.6: Frame f = new Frame ( ); f.setLayout(new GridLayout(3, 2)); f.add(new Button(“1”)); f.add(new Button(“2”)); f.add(new Button(“3”)); f.add(new Button(“4”)); f.add(new Button(“5”)); f.add(new Button(“6”)); f.add(new Button(“7”)); f.add(new Button(“8”)); f.add(new Button(“9”)); При выполнении данного фрагмента кода, параметр «2» для числа столбцов в конструкторе GridLayout будет проигнорирован, а 9 компонентов будут размещены в 3-х строках и 3-х столбцах, как показано на рис.9.5. 1 4 7 2 5 8 3 6 9 Рис.9.5 Менеджер CardLayout Менеджер компоновки CardLayout показывает в контейнере только первый компонент. Остальные компоненты лежат под первым в определенном порядке как игральные карты в колоде. Их расположение определяется порядком, в котором написаны методы add(). Следующий компонент можно показать методом next(Container c) предыдущий previous(Container c) первый first(Container c) последний last(Container c) Аргумент этих методов – ссылка на контейнер, в который помещены компоненты, обычно this. В классе CardLayout 2 конструктора: CardLayout() Конструктор по умолчанию не отделяет компонент от границ контейнера 135 Программирование на языке Java CardLayout(int hgap, int vgap) Данный конструктор задает горизонтальные и вертикальные промежутки между компонентом и границами контейнера. Менеджер CardLayout позволяет организовать и произвольный доступ к компонентам. Метод add() для этого менеджера имеет вид add(Component comp, Object name) Аргумент name должен иметь тип String и содержать имя компонента. Показать нужный компонент с именем name можно с помощью метода show(Container parent, String name) В следующем примере создается контейнер Panel, для которого задается менеджер компоновки CardLayout. В контейнер помещаются 3 других компонента типа Panel, и пока- зывается на экране последний из них. Пример 9.7: Panel p = new Panel(); CardLayout c = new CardLayout(); p.setLayout(c); Panel p1 = new Panel(); Panel p2 = new Panel(); Panel p3 = new Panel(); p.add(p1,”1”); p.add(p2,”2”); p.add(p3,”3”); c.next(p); Меню В контейнере типа Frame заложена возможность установки стандартной строки меню, располагаемой ниже строки заголовка. Эта строка – объект класса MenuBar. Все что нужно сделать для установки строки меню в контейнере Frame – это создать объект класса MenuBar и обратиться к методу MenuBar. Пример 9.8: JFrame f = new JFrame(“Пример меню”); JMenuBar mb = new JMenuBar( ); f.setJMenuBar(mb); При этом будет создана пустая строка меню. Каждый объект строки меню – выпадающее меню (drop-down menu) – это объект класса Menu. Далее необходимо создать эти объекты и занести их в строку меню. Пример 9.9: JMenu mFile = new JMenu(“Файл”); mb.add(mFile); JMenu mEdit = new JMenu(“Правка”); mb.add(mEdit); JMenu mView = new JMenu(“Вид”); mb.add(mView); 136 Программирование на языке Java JMenu mHelp = new JMenu(“Справка”); mb.add(mHelp); Элементы меню будут располагаться слева направо в порядке вызова метода add(). Затем можно определять каждое выпадающее меню, создавая его пункты. Каждый пункт меню – это объект класса MenuItem. Схема его создания аналогична схеме создания меню. Пункты меню будут располагаться сверху вниз в порядке вызова метода add(). Пример 9.10: JMenuItem create = new JMenuItem(“Создать”); mFile.add(create); JMenuItem open = new JMenuItem(“Открыть”); mFile.add(open); Если необходимо объединить несколько пунктов меню в группу, отделив их вертикальной чертой (separator), то для этого необходимо либо воспользоваться методом addSeparator() класса Menu, либо определить разделитель как пункт меню специального вида: Пример 9.11: mFile.addSeparator( ); или mFile.add(new JMenuItem(“-”)); Из рис.9.1 видно, что класс Menu расширяет класс MenuItem, а не наоборот. Это означает, что меню само является пунктом меню, и позволяет задавать одно меню в качестве пункта другого. Пример 9.12: JMenu send = new JMenu (“Отправить”); mFile.add(send); Далее подменю send заполняется пунктами как обычное меню. Часто команды меню создаются для установки с их помощью каких-то параметров, подобно компоненту Checkbox. Такие пункты меню являются объектами класса CheckboxMenuItem. Покажем создание таких пунктов меню на примере. Пример 9.13: JCheckBoxMenuItem diskA = new JCheckBoxMenuItem(“Диск А”, true); JCheckBoxMenuItem diskC = new JCheckBoxMenuItem(“Диск C”, true); send.add(diskA); send.add(diskC); Если необходимо назначить пункту меню сочетание «горячих клавиш» (акселераторов) необходимо создать объект класса MenuShortcut одним из двух его конструкторов: Пример 9.14: 137 Программирование на языке Java JMenuShortcut(int key) JMenuShortcut(int key, boolean useShiftModifier) Первый конструктор задает действие акселератора при нажатой клавише Ctrl, второй позволяет указать (если параметр useShiftModifier = true) необходимость нажатия одновременно клавиш Ctrl и Shift. В качестве первого параметра конструктора указывается одна из клавиатурных констант вида VK_A, VK_B и т.п. Такие константы определены для каждой клавиши в классе KeyEvent, находящемся в пакете java.awt.event. Поэтому данный пакет необходимо импортировать в программу, если вы собираетесь пользоваться акселераторами. (Практически данный пакет импортируется во все программы, работающие с AWT, т.к. содержит классы, предназначенные для обработки событий). Пример 9.15: JMenuShortcut keyCreate = new JMenuShortcut (KeyEvent.VK_N); JMenuShortcut keyOpen = new JMenuShortcut (KeyEvent.VK_O, true); После создания акселератора, его необходимо указать в конструкторе класса MenuItem. Пример 9.16: JMenuItem create = new JMenuItem(“Создать”, keyCreate); JMenuItem open = new JMenuItem(“Открыть”, keyOpen); Выполнив все вышеприведенные действия, мы получим меню, показанное на рис.9.6. Рис.9.6 138 Программирование на языке Java 139