Материал: Портянкин И. Swing

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

490

ГЛАВА 16

}catch (Exception ex) { JOptionPane.showMessageDialog(

JEditorPaneBrowser.this,"Адрес недоступен");

}

}

}

}

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

new Runnable() {

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

}

}

Наш браузер состоит из текстового поля, в котором пользователь будет набирать адрес для перехода, и редактора JEditorPane, предназначенного для отображения документа по указанному в поле адресу. Для начала необходимо создать нужные компоненты и расположить их в контейнере. Этим занимается метод createGUI(). Первым делом создается панель JPanel, в которой будет располагаться текстовое поле для ввода адреса. В ней мы используем менеджер последовательного расположения FlowLayout с выравниванием по левому краю, а также пустую рамку EmptyBorder, позволяющую визуально отделить содержимое панели от границ окна и улучшить восприятие интерфейса. В панель добавляется надпись, поясняющая функцию текстового поля, и само текстовое поле. Как видно, в нем будет 30 символов. К текстовому полю мы присоединяем слушателя окончания ввода, он реализован во внутреннем классе NewAddressAction (при описании текстовых полей мы отмечали в том числе и то, что в них полезно задействовать слушателей ActionListener.) Когда пользователь заканчивает ввод (нажав специальную клавишу, обычно Enter), вызывается метод слушателя actionPerformed(). В нем мы получаем текст, набранный в поле ввода адреса (это должен быть правильный URL-адрес, например такой: http://www.yahoo.com) и методом setPage() переводим редактор на новую страницу. В случае неудачи будет выведено краткое сообщение.

Теперь о настройке редактора JEditorPane. Для его создания мы выбираем конструктор, который позволяет сразу же задать документ для отображения (очень удобно для браузера: ведь в нем всегда есть домашняя страница). В качестве начальной страницы мы выбираем официальный сайт технологии Java, указывая ее полный адрес. Если вы захотите отобразить локальный файл, то это будет не так-то просто: методу setPage() требуется правильный URL-адрес, поэтому вам придется указать протокол доступа (file:)4 и правильный путь к файлу. Процедура не слишком приятная, но о ней придется вспоминать каждый раз, когда вы будете работать с локальными документами и методом setPage() (на самом деле при работе с локальными документами лучше загрузить текст файла самому и изменять его методом setText(), но будем считать, что наш браузер ориентирован на работу в Web). Далее нужно указать, какие документы должен отображать редактор, так чтобы он выбрал и настроил подходящую фабрику EditorKit. Делается это методом setContentType(), у нас документы имеют тип «text/html». Для поддержки ссылок редактирование должно быть отключено, управляем этим свойство editable. Ну и напоследок мы присоединяем к редактору слушателя HyperlinkListener, который будет получать

4Символы «file:» используются для задания относительных путей, таких как images/picture.gif,

асимволы «file://» — для задания абсолютных.

Текстовые компоненты

491

информацию о событиях, происходящих со ссылками документа. Слушатель реализован во внутреннем классе HyperlinkL.

В метод hyperlinkUpdate() класса HyperlinkL приходит вся информация о происходящих со ссылками событиях. Нас интересует только активизация ссылки пользователем, в самом начале метода мы проверяем, подходит ли нам пришедшее событие. Если событием на самом деле являлась активизация ссылки, то мы получаем адрес активизированной ссылки методом getURL() и переводим редактор на новую страницу методом setPage(), передав ему полученный адрес. В случае ошибки на экран выводится краткое сообщение.

Созданные и настроенные компоненты добавляются в окно: панель с полем для ввода адреса размещается на севере, редактор, предварительно включенный в панель прокрутки, — в центре. Запустив программу с примером, вы сможете оценить, как компонент JEditorPane показывает HTML-документы, и увидеть, на что похожи ваши любимые страницы, отображенные средствами Swing.

Правда, выбирать страницы для просмотра нужно аккуратнее: ни языки сценариев, ни модули расширения, ни возможности HTML 4.0 и выше не поддерживаются, так что не удивляйтесь, если порядочная часть страниц нашему браузеру так и не поддастся. Впрочем, не все так плохо: поддержка HTML позволяет несколькими строками кода выводить правильно составленные документы и, что еще лучше, сохранять в этом формате документы, созданные вашими программами. Браузеры и веб-страницы — это отдельная история, и если уж вам потребуется выводить на экран любые страницы, попробуйте воспользоваться специальными компонентами JavaBeans от сторонних производителей. Еще одним вариантом может быть использование класса Desktop из пакета java.awt, предоставляющего доступ к системному браузеру. Получив активный экземпляр этого класса методом getInstance(), а затем вызвав метод browse(), вы сможете открыть для пользователя окно с системным браузером, используемым по умолчанию. Иногда это именно то, что нужно.

Редактирование по максимуму — компонент JTextPane

Если компонент JEditorPane используется в основном для статичного отображения уже созданных текстовых документов некоторого формата (заданного фабрикой EditorKit), то унаследованный от него текстовый компонент JTextPane незаменим при создании в приложении многофункционального текстового редактора. Обладая всеми впечатляющими возможностями своего предка JEditorPane, класс JTextPane добавляет к нему то, без чего представить себе современные редакторы практически невозможно — разметку текста

492

ГЛАВА 16

стилями. Для этого в нем используется специальная модель документа StyledDocument и настроенная на поддержку такой модели фабрика классов StyledEditorKit.

Концепция стиля в текстовом редакторе очень проста, тем не менее она многократно повышает эффективность работы пользователя с текстом. Стиль (style) — это некоторый набор атрибутов редактируемого текста (такими атрибутами могут быть шрифт текста, его размер и цвет, выравнивание и т. п.), который можно применить к любому фрагменту текста. Стиль позволяет четко разделить внешний вид документа и собственно текст. Пользователь может сосредоточиться на наборе текста, используя при этом несколько стилей (пара заголовков, основной текст, текст сносок), а если у него возникнет необходимость оформить текст по-другому, понадобится лишь поменять атрибуты стилей. Текст, набранный с использованием стилей, изменится автоматически. Вы найдете стили в любом современном редакторе, в том числе они встроены в язык разметки HTML посредством расширений CSS (Cascaded Style Sheets — каскадные таблицы стилей).

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

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

Рассмотрим пример, в котором применим часть впечатляющих возможностей компонента JTextPane, в том числе наборы атрибутов и именованные стили. После разбора примера мы сможем в деталях понять, как работают механизмы класса

JTextPane:

//StyledText.java

//Богатые возможности редактора JTextPane import javax.swing.*;

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

public class StyledText extends JFrame { public StyledText() {

super("StyledText"); setDefaultCloseOperation(EXIT_ON_CLOSE); // создадим редактор

JTextPane textPane = new JTextPane();

//создание документа и стилей createDocument(textPane);

//добавим редактор в окно add(new JScrollPane(textPane));

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

Текстовые компоненты

493

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

}

private void createDocument(JTextPane tp) {

//настройка стилей

//стиль основного текста

Style normal = tp.addStyle("Normal", null); StyleConstants.setFontFamily(normal, "Verdana"); StyleConstants.setFontSize(normal, 13);

// заголовок

Style heading = tp.addStyle("Heading", normal); StyleConstants.setFontSize(heading, 20); StyleConstants.setBold(heading, true);

//наполняем документ содержимым, используя стили insertString("Незамысловатый Заголовок", tp, heading); insertString("Далее идет обычное содержимое,", tp, normal); insertString("помеченное стилем Normal.", tp, normal); insertString("Еще Один Заголовок", tp, heading);

//меняем произольную часть текста

SimpleAttributeSet red = new SimpleAttributeSet(); StyleConstants.setForeground(red, Color.red); StyledDocument doc = tp.getStyledDocument(); doc.setCharacterAttributes(5, 5, red, false);

// добавим компонент в конец текста tp.setCaretPosition(doc.getLength());

JCheckBox check = new JCheckBox("Все возможно!"); check.setOpaque(false); tp.insertComponent(check);

}

//вставляет строку в конец документа с переносом,

//используя заданный стиль оформления

private void insertString(String s, JTextPane tp, Style style) { try {

Document doc = tp.getDocument(); doc.insertString(doc.getLength(), s + "\n", style);

}catch (BadLocationException ex) { ex.printStackTrace();

}

}

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

494

ГЛАВА 16

new Runnable() {

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

}

}

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

Сначала создаются два именованных стиля, которые мы затем будем использовать при разметке своего текста. Посмотрите, как это делается: сначала создается базовый для всего документа стиль (с названием Normal). Для добавления стиля в редактор применяется метод с говорящим названием addStyle()5. Ему нужно передать два параметра: название нового стиля и стиль, который будет являться родительским для нового стиля, а в ответ он вернет новый стиль Style. Если в качестве второго параметра передать пустую ссылку null, стиль окажется без родителя и будет создаваться «с нуля». Именно таким образом мы создаем базовый стиль своего документа

. Второй стиль в нашем документе (у него название Heading) служит для заголовков. Он унаследован от стиля Normal, а значит, перенимает от своего родителя все установленные для того атрибуты, такие как размер и цвет шрифта. Стиль заголовка отличается увеличенным размером шрифта и полужирным начертанием. Обратите внимание, что для установки атрибутов стилей используются удобные статические методы класса StyleConstants.

После создания стилей можно приступать к вставке в документ текста, размеченного только что настроенными стилями. Вставить текст в компонент JTextPane можно только посредством модели документа Document, в которой имеется метод insertString(). Этот метод требует трех параметров: позицию для вставки, строку, которую вы собираетесь вставлять, и стиль, который будет иметь вставляемая строка. У нас вставкой текста в документ занимается собственный вспомогательный метод insertString(). В нем строка добавляется к концу документа и при этом дополняется символами переноса строки (их приходится указывать вручную, автоматически они не добавляются). Для вставки текста в конец документа в качестве первого параметра метода insertString() необходимо указать размер документа, который несложно узнать с помощью метода getLength(). Кстати, приходится следить за исключением, которое не преминет возникнуть в том случае, если позиция в документе будет неверно указана6. С помощью вспомогательного метода мы добавляем в документ текст: сначала заголовок, потом несколько строк с обычным стилем и снова заголовок. При этом используются созданные нами стили.

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

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

6 Случай с текстовыми компонентами и работой с их текстом как раз показывает, как иногда бывают надоедливы проверяемые (checked) исключения. Как правило, манипулируя текстом, мы осознаем его границы, и здесь вполне хватило бы непроверяемого исключения, которое не обязательно включать в блок try.

Источник: https://studfile.net/preview/15935977/