Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Портянкин И. Swing

.pdf
Скачиваний:
140
Добавлен:
07.10.2020
Размер:
4.63 Mб
Скачать

Вывод вспомогательной информации

215

Надпись JLabel позволяет вывести на экран текст, значок, или оба элемента вместе. Текст и/или значок чаще всего задаются в конструкторе надписи, у которого имеются пять перегруженных версий на все случаи жизни, но можно также задать или изменить текст или значок потом, после создания объекта, манипулируя свойствами icon и text с помощью соответствующих методов get/set (это свойства JavaBeans). Вы также можете изменить шрифт вывода текста, используя метод setFont() (в примере мы этого не делаем, а по умолчанию применяется шрифт, предоставленный менеджером внешнего вида). В нашем примере мы создаем окно, в панель содержимого которого добавляем несколько надписей. Первая надпись — самый простой и наиболее распространенный вариант: просто некий необходимый пользователю текст выводится на экран. Рядом с ней было специально добавлено текстовое поле, и картина становится полной: надпись описывает, для чего предназначен другой компонент. Чаще всего так она и используется. Далее мы добавляем более сложные варианты надписей JLabel, одну со значком и вторую и со значком, и с текстом.

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

Таблица 8.1. Свойства для выравнивания содержимого надписей

Свойства

Предназначение

 

 

verticalAlignment, horizontalA-

Позволяют задать расположение содержимого надписи (и текста,

lignment (и соответствующие

и значка) относительно ее границ. Возможные положения описаны

методы get/set)

константами из интерфейса SwingContants, у вас есть три вариан-

 

та расположения по вертикали (центр, верх, низ) и столько же по

 

горизонтали (центр, справа, слева). Всего получается девять воз-

 

можных позиций

verticalTextPosition, horizon-

Дают возможность указать надписи, как ей следует располагать

talTextPosition (и соответ-

текст относительно значка. Вы можете задать положение текста

ствующие методы get/set)

по вертикали (по центру значка, по его верхней или нижней грани-

 

це) и по горизонтали (по центру значка, слева или справа от него).

 

Витогетакжеполучаетсядевятьвариантов(можнодажеразместить

 

текст поверх значка)

iconTextGap

В нашем примере мы не использовали это свойство, но оно очень

 

просто и позволяет указать расстояние между текстом и значком

 

в пикселах

Для того чтобы было проще использовать константы выравнивания, мы в нашем классе реализовали (implements) интерфейс SwingConstants, в котором они описаны, его подробное описание легко найти в интерактивной документации. Надпись со значком меняет расположение своего значка, а надпись со значком и текстом меняет не только расположение всего содержимого, но и положение текста относительно значка. Запустив программу с примером, вы увидите результаты наших действий и сможете убедиться в том, что у вас действительно очень широкие возможности по настройке содержи-

216

ГЛАВА 8

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

Стоит также отметить (хоть мы и не создали такой надписи в примере), что надписи JLabel могут быть «отключенными», так же как и большая часть других компонентов, таких как кнопки, надо лишь вызвать метод setEnabled(false). Это позволяет придать интерфейсу большую выразительность: если какие-то функции приложения недоступны, отключаются все элементы интерфейса, даже надписи. Если в надписи используется значок, то в отключенном состоянии он с помощью специального фильтра изображений1 переводится в черно-белые цвета. Впрочем, вы можете задать собственный значок для отключенного состояния, вызвав метод setDisabledIcon().

Значки Icon

Только что при рассмотрении примера с надписями JLabel мы видели, что для загрузки значков использовался класс ImageIcon. На самом деле в библиотеке Swing для вывода значков во всех компонентах библиотеке применяется интерфейс Icon, а класс ImageIcon — его самая популярная реализация с изображением в качестве значка2. «Поче-

1 Этот фильтр изображений называется GrayFilter, находится в пакете javax.swing и используется всеми компонентами Swing с поддержкой значков Icon, чтобы создавать «отключенные» версии значков (в том случае если вы не предоставляете отключенные значки самостоятельно). Задействовать данный фильтр можно и напрямую: удобный статический метод getDisabledImage() позволяет мгновенно получить черно-белый вариант любого изображения.

2 В данный момент JDK поддерживает форматы изображений JPEG, GIF (в том числе и анимированный) и PNG, то есть все самые популярные форматы Web. Особое внимание стоит обратить на формат PNG, который не имеет проблем с лицензированием и полностью поддерживает альфаканал (различные степени прозрачности).

Вывод вспомогательной информации

217

му же в библиотеке сразу не используются изображения Image?» — спросите вы. Все дело

втом, что интерфейс Icon можно легко реализовать самому. Это позволяет использовать

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

Создать свой значок Icon, используя только графические свойства Java, нетрудно:

//RedBullet.java

//Создание собственного значка

import javax.swing.*; import java.awt.*;

public class RedBullet implements Icon { public int getIconWidth() {

return 16;

}

public int getIconHeight() { return 16;

}

public void paintIcon(

Component c, Graphics g, int w, int h) { g.setColor(Color.red);

g.fillRect(0, 0, 16, 16);

}

}

Здесь мы создаем значок в виде красного квадрата. Первые два метода позволяют задать размеры значка, в третьем методе вы рисуете свой значок. Иногда такой подход может быть быстрее и эффективнее создания изображения из файла. Использовать такие значки можно в любых компонентах Swing с их поддержкой (то есть почти во всех). Тем не менее, чаще все-таки используется класс ImageIcon. Он позволяет загрузить изображение поддерживаемого формата из файла, сетевого ресурса, заданного URLадресом (Uniform Resource Locator — унифицированный указатель ресурса), и способен создавать изображение даже из массива байтов3. В отличие от стандартного метода загрузки изображений getImage() из класса java.awt.Toolkit, класс ImageIcon всегда загружает изображение полностью (метод getImage() сразу возвращает управление, даже если изображение загружено частично, в результате на экране может появиться совсем не то, что вы ожидаете). Для этого задействуется специальный класс MediaTracker, который в противном случае пришлось бы использовать самостоятельно. Остается лишь сказать, что в пути к изображению указывается прямой слеш, который автоматически заменяется разделителем пути текущей платформы:

new ImageIcon("data/resources/menu");

3 Возможность создать изображение на основе массива байтов значительно облегчает распространение приложения в виде единого исполняемого JAR-файла, ресурсы из которого можно получить только в виде подобного массива.

218

ГЛАВА 8

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

Использование HTML

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

В состав Swing входит пакет javax.swing.text.html, поддерживающий для текстовых компонентов язык разметки HTML версии 3.2. Окончательный вывод текста на экран выполняет объект View (мы рассмотрим его в главе 16, посвященной текстовым возможностям Swing), который может использовать для вывода текста любой компонент. В любом объекте JLabel в виде клиентского свойства находится объект View, который и выполняет вывод текста на экран (что интересно, он занимается этим, даже если вы выводите простой текст, а не HTML). Чтобы вывести на надписи HTML-текст, достаточно указать в начале строки его отличительный признак — символы <html>. Рассмотрим пример:

//HTMLabel.java

//Использование в надписях языка HTML import javax.swing.*;

public class HTMLabel extends JFrame { private String html1 =

"<html><b>Слава</b><font size=5 color=red> HTML"; private String html2 =

"<html><font size=4 color=blue>" + "<ul>Список:<li>Один<li>Два";

private String html3 =

"<html><body bgcolor=white><h2>Любой цвет фона"; private String html4 =

"<html><h2>Изображения:<img src=\"file:monkey.gif\">"; public HTMLabel() {

super("HTMLabel");

//при закрытии окна выход setDefaultCloseOperation(EXIT_ON_CLOSE);

//добавляем надписи

JPanel contents = new JPanel(); contents.add(new JLabel(html1)); contents.add(new JLabel(html2)); contents.add(new JLabel(html3)); contents.add(new JLabel(html4)); // выводим окно на экран

Вывод вспомогательной информации

219

add(contents); setSize(400, 300); setVisible(true);

}

public static void main(String[] args) { SwingUtilities.invokeLater(

new Runnable() {

public void run() { new HTMLabel(); } });

}

}

В примере мы добавляем в окно с рамкой четыре надписи, поддерживающие возможности встроенного языка HTML. Главное при использовании HTML — помнить, что строка с текстом должна начинаться с «волшебных» символов <html>, иначе все теги будут выведены в виде обычного текста. Мы задействовали разнообразные возможности HTML: различные стили и размеры текста, разные цвета для фона страницы и ее текста, и даже вывели изображение. Вы можете видеть, что даже список некоторых элементов в надписи JLabel благодаря HTML организовать не сложно. Как все это выглядит, можно посмотреть, запустив программу с примером.

Все возможности, описанные в спецификации языка HTML версии 3.2, поддерживаются встроенным в надписи элементом View. Как видно, поддерживаются и изображения, однако при работе с ними надо помнить, что встроенный язык HTML в качестве источника изображений распознает только правильные URL-адреса. Это могут быть адреса файлов на локальной машине (причем задавать файлы вы можете и относительно текущего каталога пользователя, как мы сделали это в примере, и с помощью абсолютных путей, таких как file:C:/images/pub/img.jpg) или полные сетевые адреса, например http://somehost/dir/image.gif. Впрочем, изображения с помощью встроенного языка HTML выводят все же редко, хотя возможность эта захватывающая. Дело в том, что приложения обычно распространяют в виде единственного архивного JAR-файла, в котором в том числе хранятся и изображения. Загрузка изображений из архива происходит уже во время работы программы, так что для их вывода чаще используют возможности надписей JLabel, позволяющих выводить значки и выстраивать их относительно текста.

220

ГЛАВА 8

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

Надписи и события

Надпись JLabel — такой же компонент, как и остальные, унаследованный от базового класса JComponent, поэтому она может обрабатывать любые виды общих для всех компонентов событий: надо лишь добавить к ней соответствующих слушателей. Но чаще всего надпись просто сообщает что-то пользователю, а не обрабатывает событий, чтобы не вводить его в заблуждение (помните принцип простого интерфейса с очевидным предназначением). Пользователь привык, что надписи выводят информацию, и не отвечают за что-то большее. Если вам нужно выполнять в приложении какую-то функцию, инициируйте ее выполнение с помощью кнопки или клавиатурного сокращения, в качестве альтернативы можно предложить компонент-гиперссылку JXHyperlink из пакета дополнений SwingX.

Надписи также не принимают фокус ввода, их свойство focusable по умолчанию установлено в false. Если только вы не хотите огорошить пользователей новаторским интерфейсом, в котором надписи живут своей жизнью, стандартное поведение вряд ли стоит менять.

Надписи и мнемоники

Создатели Swing добавили в надписи JLabel еще одну возможность, позволяющую отточить функциональность вашего пользовательского интерфейса. Надписи могут поддерживать мнемоники (mnemonics) для других компонентов, неспособных поддерживать их самостоятельно. Мнемоника — это специальное клавиатурное сокращение (на большинстве платформ сочетание клавиши Alt или Ctrl с кодом клавиши), позволяющая быстро активировать некоторый компонент интерфейса, например, кнопку или текстовое поле. В сложных интерфейсах, состоящих из множества компонентов, находить нужный компонент (который, возможно, является самым важным) может быть утомительно, и в таких ситуациях мнемоники очень полезны. Более того, они незаменимы для пользователей с ограниченными возможностями, которые не могут пользоваться мышью. Приложение высокого класса обязано предоставлять доступ с клавиатуры ко всем своим компонентам.

Некоторые компоненты, например кнопки, сами поддерживают мнемоники, другие, такие как текстовые поля или раскрывающиеся списки, могут поддерживать клавиатурные сокращения, но удобно информировать о них пользователя не в состоянии. Здесь пригодится надпись с мнемоникой около компонента: пользователь быстро увидит, как активируется данный компонент, потому что символ мнемоники в тексте надписи подчеркивается.

Поддержка мнемоник реализована в UI-представителе надписи JLabel, причем сделано все довольно интересно: когда вы сообщаете надписи, что хотели бы использовать ее для вывода мнемоники некоторого компонента, UI-представитель, во-первых, подчеркивает символ мнемоники при прорисовке надписи, во-вторых, регистрирует в кар-

Вывод вспомогательной информации

221

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

//LabelMnemonic.java

//Использование надписей для вывода мнемоник import javax.swing.*;

import java.awt.*;

public class LabelMnemonic extends JFrame { public LabelMnemonic() {

super("LabelMnemonic"); setDefaultCloseOperation(EXIT_ON_CLOSE); // добавим пару текстовых полей

JPanel contents = new JPanel(new GridLayout(2,2)); JTextField tf = new JTextField(10);

JLabel label = new JLabel("Ваше имя:");

//настройка мнемоники label.setLabelFor(tf); label.setDisplayedMnemonic('И');

//добавляем компоненты в таблицу contents.add(new JLabel("Ваша фамилия:")); contents.add(new JTextField(10)); contents.add(label);

contents.add(tf);

//выведем окно на экран setContentPane(contents); pack(); setVisible(true);

}

public static void main(String args[]) { SwingUtilities.invokeLater(

new Runnable() {

public void run() { new LabelMnemonic(); } });

}

}

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

222

ГЛАВА 8

(setLabelFor()), а также символ мнемоники, клавишу которого вместе с управляющей клавишей и нужно будет нажать (setDisplayedMnemonic()). Запустив пример, вы увидите, что надпись подсказывает пользователю, каким символом можно активизировать текстовое поле при нажатии нужного сочетания (чаще всего Alt+символ, в нашем случае Alt+И). В текущих выпусках JDK 1.6 -- 1.7 кириллические символы поддерживаются4, что замечательно, так как в первом издании книги мы сломали немало копий по этому поводу.

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

Всплывающие подсказки

Всплывающие подсказки (tool tips) — неизменный атрибут современного пользовательского интерфейса, и не зря: они намного упрощают ознакомление и последующую работу с вашим приложением. Это небольшие (чаще всего, хотя и не обязательно) текстовые описания компонентов вашего интерфейса, появляющиеся рядом с компонентом в том случае, если пользователь ненадолго задерживает на нем указатель мыши. Ценность всплывающих подсказок трудно переоценить — они намного ускоряют работу с любым, особенно сложным приложением. Вместо знакомства с документацией пользователь может прямо «на лету» узнать, для чего предназначен тот или иной элемент интерфейса, и быстро начать работу. Работу кнопками, на которых есть только значки, вообще невозможно представить без подсказок5. В Swing это особенно верно, потому что подсказки здесь обладают весьма широкими возможностями.

Любой компонент Swing может обладать всплывающей подсказкой, потому что поддержка их встроена в базовый класс библиотеки JComponent. Когда вы вызываете метод setToolTipText(), компонент регистрирует себя в классе ToolTipManager, который отвечает за правильный вывод подсказок. Класс ToolTipManager следит за перемещениями мыши на всех зарегистрированных в нем компонентах и при наступлении нужного момента (наведении указателя мыши) выводит подсказку на экран. Рассмотрим пример с подсказками:

//ToolTips.java

//Подсказки в Swing import javax.swing.*; import java.awt.*; import java.awt.event.*;

public class ToolTips extends JFrame {

4 К сожалению, только для надписей, но не для кнопок и меню.

5 Интересно, что кнопки с мелкими значками, так популярные в современных приложениях, от Web до мобильных устройств, часто подвергаются критике специалистов по удобству интерфейсов. Действительно, и попасть трудно, и почитать надо перед тем как нажимать, универсальных значков мало. Автор согласен с тем, что если есть место для текста, лучше сделать элемент с текстом, чем с красочным значком.

Вывод вспомогательной информации

223

public ToolTips() { super("ToolTips");

setDefaultCloseOperation(EXIT_ON_CLOSE);

//добавим несколько кнопок с подсказками

JButton b1 = new JButton("Один"); b1.setToolTipText("Это первая кнопка"); JButton b2 = new JButton() {

public Point getToolTipLocation(MouseEvent e) { return new Point(10, 10);

}

public String getToolTipText(MouseEvent e) { if ( e.getY() > 10 ) {

return "Нижняя часть кнопки!";

}

return super.getToolTipText(e);

}

}; b2.setText("Два");

b2.setToolTipText("<html><h3>Это вторая кнопка.<ul>" + "Она:<li>Ничего не делает<li>Но ее можно нажать!");

JPanel contents = new JPanel(); contents.add(b1); contents.add(b2);

//выводим окно на экран

add(contents); setSize(400, 150); setVisible(true);

}

public static void main(String[] args) { SwingUtilities.invokeLater(

new Runnable() {

public void run() { new ToolTips(); } });

}

}

Мы добавляем в окно две кнопки JButton, и задаем для каждой из них текст подсказки, что автоматически приводит к регистрации кнопок в классе ToolTipManager. Для первой кнопки мы используем простой текст, который появится в виде однострочной подсказки, шрифт и цвет которой зависят от текущих внешнего вида и расположения. Но вот для второй кнопки мы используем уже знакомый нам HTML-текст (помните, что начинать HTML-строку следует с символов <html>), и здесь у вас, так же как и в случае с надписями, просто безграничные возможности. Вы можете задействовать любые возможности HTML версии 3.2 для создания краткой, но мощной системы помощи, действующей прямо «на лету». В примере мы применили стиль заголовка и маркированный список — эти

224

ГЛАВА 8

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

Помимо метода setToolTipText(), позволяющего задать для вашего компонента подсказку, увасестьещепараметодов,способныхповлиятьнаеевывод,—этометодыgetToolTipLocation() и getToolTipText(MouseEvent), определенные в базовом классе JComponent. Правда, пользоваться ими довольно неудобно, потому что соответствующего метода set нет, и для получения нужного эффекта их приходиться переопределять, что мы и сделали в нашем примере, создав анонимный подкласс кнопки JButton. Метод getToolTipLocation() позволяет указать классу ToolTipManager, в каком месте экрана следует выводить подсказку относительно компонента, для которого подсказка выводится. Можно указывать различные места для подсказки в зависимости от события MouseEvent, по которому подсказка выводится. В примере мы указали, что подсказка должна выводиться на расстоянии 10 пикселов по осям X и Y от верхнего левого угла нашей кнопки (можно указывать и отрицательные расстояния, это будет означать, что вы хотите вывести подсказку не ниже компонента, как обычно, а выше). Правда, действует описанный механизм, только если подсказка выводится как легковесный компонент, то есть когда ей хватает места в пределах окна нашего приложения. В противном случае класс ToolTipManager сам решает, где удобнее ее разместить. Полученный эффект вы сможете наблюдать, запустив программу с примером: подсказка первой кнопки будет выводиться в разных местах, в зависимости от положения указателя мыши, а для второй кнопки она всегда будет появляться на указанном нами расстоянии (если ей хватит места). Метод getToolTipText() позволяет выводить для одного и того же компонента различные подсказки в зависимости от того, где пользователь задержал указатель мыши (координаты этого места позволяет узнать объект MouseEvent). Данный метод часто задействуется сложными компонентами Swing, такими как списки или таблицы, состоящими из многих элементов. С его помощью они обеспечивают вывод собственных подсказок для каждого элемента. По умолчанию он возвращает для любой точки текст, заданный методом setToolTipText(), но переопределив этот метод, вы сможете изменить подобное поведение. В примере мы используем подсказку по умолчанию только для верхней части кнопки (высотой в 10 пикселов), а для нижней части возвращаем собственный текст.

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