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

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

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

485

однострочных текстовых полей мы сразу указываем количество символов, и нередко это правило ошибочно переносится на класс JTextArea. Задаваемые нами в конструкторе количества строк и символов поля определяют его первоначальный предпочтительный размер в контейнере, но не накладывают каких-либо ограничений на объем вводимого текста, который может быть произвольным. Для первого поля мы изменяем шрифт (здесь все аналогично однострочным полям) и задаем нестандартное значение для табуляции, вызывая метод setTabSize(). Данный метод позволяет указать, какое количество символов будет замещать символ табуляции (вставляемый нажатием клавиши Tab). По умолчанию это значение равно 8, но видно, что его можно изменить. Это может быть полезно в текстах с большим количеством отступов, например в текстах программ или в журнальных записях.

Второе текстовое поле создается с помощью конструктора, принимающего в качестве параметров только количества строк и символов; поначалу текста в таком поле не будет. Для второго поля мы меняем свойства, управляющие процессом переноса текста на новые строки, именно эти свойства наиболее полезны при работе с многострочными полями. По умолчанию текст в поле JTextArea не переносится на новую строку (после запуска программы с примером вы убедитесь в этом, взглянув на первое поле). Изменить данное поведение позволяют использованные нами в примере методы. Метод setLineWrap() включает автоматический перенос текста на новую строку. Длинные слова будут переноситься на следующие строки, так что в таком многострочном поле никогда не потребуется горизонтальная прокрутка. Метод setWrapStyleWord() изменяет стиль переноса длинных слов на новые строки. Если вы передадите в этот метод значение true, то слова, не умещающиеся в строке, будут целиком переноситься на строку новую. По умолчанию значение этого свойства равно false, это означает, что текст переносится, как только ему перестает хватать места в строке, независимо от того, в каком месте слова приходится делать перенос.

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

486

ГЛАВА 16

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

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

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

Напоследок сведем изученные нами свойства многострочных полей в табл. 16.2.

Таблица 16.2. Свойства многострочных текстовых полей

Свойства

Описание

(и методы get/set)

 

rows, columns

Задают размеры многострочного текстового поля, в строках и симво-

 

лах соответственно. Изменить размер поля можно и прямо во время

 

работы программы, поле JTextArea при этом автоматически проведет

 

проверку корректности и перерисовку контейнера

lineWrap, wrapStyleWord

Управляют включением переноса текста по строкам и типом этого пере-

 

носа. Когдапереносстрокотключен, второесвойствонедействует. Если

 

перенос строк включен и второе свойство равно false, перенос происхо-

 

дит в том месте, где заканчивается строка, независимо от того, в какой

 

точке слова это случается. В противном случае перенос происходит по

 

словам, которые не разбиваются на части, а переходят на новую строку

 

целиком (если такая возможность есть и слово не слишком длинное)

font

Позволяет задать шрифт для многострочного текстового поля. Шрифт

 

по умолчанию задается текущим менеджером внешнего вида и пове-

 

дения Swing

tabSize

Контролирует размер символа табуляции (вставляется нажатием кла-

 

виши Tab) в текстовом поле. По умолчанию для символа табуляции ис-

 

пользуются 8 «обычных» символов, это наиболее часто употребляемое

 

значение

lineCount, lineOfOffset,

Данные методы позволяют получить исчерпывающую информацию

lineStartOffset, lineEnd-

о распределении текста многострочного поля по строкам. Первый

Offset (только методы get)

метод get дает общее количество строк текста в поле. Второй метод

 

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

 

символ с данным смещением от начала текста. Последние два мето-

 

да действуют обратным образом: для заданного номера строки они

 

позволяют узнать смещение символа, находящегося в начале строки

 

и в конце строки

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

487

Помимо описанных в таблице свойств и методов многострочное поле JTextArea обладает еще парой весьма полезных методов. Метод append() позволяет присоединить к уже имеющемуся в поле тексту новую часть без удаления прежнего содержимого (в отличие от метода setText()). Метод insert() дает возможность вставить в произвольную область находящегося в поле текста новую строку. Оба этих метода избавляют нас от дополнительной «возни» с методом setText(), при использовании которого пришлось бы вручную манипулировать несколькими строками и преобразовывать их.

Редактор JEditorPane

Редактор JEditorPane представляет собой мощный инструмент, способный отображать на экране текст любого формата. В данный момент библиотекой Swing поддерживается два широко распространенных формата: HTML и RTF (Rich Text Format — расширенный текстовый формат)1, но потенциально редактор JEditorPane может отображать текст любого формата, с любыми элементами и любым оформлением. Такую гибкость редактору обеспечивает фабрика классов EditorKit, в обязанности которой входит создание и настройка всех объектов, необходимых для отображения текста некоторого типа2, в том числе модели документа (объекта Document), фабрики для отображения элементов документа ViewFactory, курсора и списка команд, поддерживаемых данным типом текста. Фабрика EditorKit также отвечает за правильное открытие и сохранение документа поддерживаемого ею формата. Так что возможности JEditorPane ограничены лишь наличием фабрик для различных текстовых форматов. Поддерживаемые стандартно форматы RTF и HTML описываются фабриками RTFEditorKit и HTMLEditorKit соответственно.

Редактор JEditorPane, как правило, требуется именно для отображения текста поддерживаемого им формата, для редактирования текста пользователем с предоставлением последнему всех мыслимых возможностей (изменение стилей, вставка компонентов и значков, и пр.) лучше подходит текстовый компонент JTextPane. Класс JTextPane унаследован от JEditorPane, но гораздо удобнее для редактирования. Работа же с классом JEditorPane обычно происходит следующим образом. Вы методом setContentType() задаете, какой тип документа будет отображать редактор, и указываете местоположение документа, вызвав метод setPage() для перехода по URL-адресу документа (в этом случае считывать текст по указанному адресу будет фабрика EditorKit). Можно также самостоятельным считать текст документа и передать его в метод setText(). Редактор отобразит документ (если он был успешно считан) согласно его типу с помощью соответствующей этому типу фабрики EditorKit.

Для документов, которые поддерживают различного рода ссылки, редактор JEditorPane предоставляет слушателей HyperlinkListener. Эти слушатели оповещаются при активизации пользователем ссылки в документе. Слушателям передается URL-адрес активизированной ссылки, так что они могут заставить редактор немедленно перейти по этому адресу, вызвав все тот же метод setPage(), или использовать полученную информацию по своему усмотрению. Как и когда активизируются ссылки и что считается в документе ссылками, зависит, как нетрудно догадаться, от задействованной редактором фабрики EditorKit. Ссылки поддерживаются стандартной фабрикой HTMLEditorKit, необходимой для отображения HTML-документов, так что вы сможете сразу узнать, когда

1 Создатели Swing честно реализовали все возможности, описанные в спецификациях форматов HTML 3.2 и RTF. К сожалению, время от времени Swing оказывается не в состоянии прочитать тот или иной документ в этих форматах: слишком уж много «недокументированных» дополнений и нестандартных возможностей встречается в документах, создаваемых наиболее популярными редакторами, не говоря уже об обилии Javascript. Если вам важна возможность считывать любые документы, придется многое доделать своими руками.

2 Тип текста задается как строка MIME, например, для HTML — это text/html. Этой строке и сопоставляется подходящая фабрика EditorKit.

488

ГЛАВА 16

пользователь активизирует ссылку3. Есть только одно маленькое «но»: ссылки активизируются, только когда редактирование текста запрещено (свойство editable равно false).

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

//JEditorPaneBrowser.java

//Простой браузер на основе редактора JEditorPane import javax.swing.*;

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

import java.awt.event.*;

public class JEditorPaneBrowser extends JFrame { // наш редактор

private JEditorPane editor; // текстовое поле с адресом private JTextField address; public JEditorPaneBrowser() {

super("JEditorPaneBrowser"); setDefaultCloseOperation(EXIT_ON_CLOSE);

//создаем пользовательский интерфейс createGUI();

//выводим окно на экран setSize(500, 400); setVisible(true);

}

// настройка пользовательского интерфейса private void createGUI() {

//панель с адресной строкой

JPanel addressPanel = new JPanel(); addressPanel.setLayout(

new FlowLayout(FlowLayout.LEFT)); addressPanel.setBorder(BorderFactory.

createEmptyBorder(5, 5, 5, 5));

//поле для адреса

address = new JTextField(30); // слушатель окончания ввода

address.addActionListener(new NewAddressAction());

3 Слушатели оповещаются о трех событиях, происходящих со ссылками. Самым популярным событием без сомнения является активизация ссылки, но вы также можете узнать о «входе» в область ссылки (например, когда пользователь наводит на ссылку указатель мыши) и «выходе» из этой области. Используя их, вы сможете оперативно обновлять, к примеру, строку состояния своего приложения, так что пользователь будет видеть, по какому адресу предлагает перейти ссылка.

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

489

addressPanel.add(new JLabel("Адрес:")); addressPanel.add(address);

// настраиваем редактор try {

//пути к ресурсам нужно записывать

//полностью, вместе с протоколами

editor = new JEditorPane("http://java.sun.com");

}catch (Exception ex) { JOptionPane.showMessageDialog(

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

}

editor.setContentType("text/html");

editor.setEditable(false);

//поддержка ссылок editor.addHyperlinkListener(new HyperlinkL());

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

add(addressPanel, "North"); add(new JScrollPane(editor));

}

// слушатель, получающий уведомления о вводе нового адреса class NewAddressAction implements ActionListener {

public void actionPerformed(ActionEvent e) { // переходим по адресу

String newAddress = address.getText(); try {

editor.setPage(newAddress);

}catch (Exception ex) { JOptionPane.showMessageDialog(

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

}

}

}

// слушатель, обеспечивающий поддержку ссылок class HyperlinkL implements HyperlinkListener {

public void hyperlinkUpdate(HyperlinkEvent he) { // нужный ли это тип события

if ( he.getEventType() == HyperlinkEvent.EventType.ACTIVATED ) {

// переходим по адресу try {

editor.setPage(he.getURL());

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