Компонент JTextComponent
Абстрактный класс JTextComponent стоит на вершине иерархии текстовых компонентов и содержит их общие свойства.
Текстовые компоненты построены по схеме "Model-View-Controller", которая отражена во внутреннем устройстве класса JTextComponent. Рассмотрим это устройство подробнее. Начнем с модели данных текстовых компонентов.
Модель данных — документ
Модель данных схемы MVC текстовых компонентов описана интерфейсом Document и называется документом. Документ может быть простым, "плоским", или сложным, структурированным. Интерфейс Document описывает простой текст (content), содержащийся в компоненте, как последовательность символов Unicode. Количество символов в тексте можно узнать методом getLength(). Последовательность символов нумеруется, начиная от нуля. Каждый символ имеет свой порядковый номер, называемый позицией (position, location или offset) символа в тексте. Точнее говоря, модель данных задает позицию не символа, а позицию между символами, перед текущим символом текста, что удобно для вставки текста.
Если текст документа сложный, структурированный, то, чтобы скрыть сложность определения текущей позиции при частых вставках и удалениях текста, удобно воспользоваться объектом, описанным интерфейсом Position. Экземпляр класса, реализующего интерфейс Position, создается методом createPosition (int). Методы getStartPosition( ) и getEndPosition() возвращают начальную и конечную позиции текста в виде объекта, реализующего интерфейс Position. В интерфейсе Position всего один метод — getOffset (), возвращающий позицию символа в виде целого числа типа int. Кроме того, в интерфейсе Position есть вложенный класс Bias, в котором определены два экземпляра класса Bias: поле Forward и поле Backward. Они уточняют символ, позиция которого определена: текущий или предыдущий. Позиция символа используется, например, при получении текста методами
String getText(int offset, int length);
void getText(int offset, int length, Segment text);
извлекающими из документа фрагмент текста длиной length символов, начиная от позиции offset. Второй метод заносит извлеченный фрагмент в экземпляр text класса Segment. Опишем этот небольшой, но удобный класс.
Строка символов Segment
Класс Segment представляет строку символов в виде, удобном для быстрого просмотра. У строки класса Segment всегда есть текущий символ, который можно получить методом current ( ). Позицию текущего символа можно узнать методом getIndex (), а установить — методом setIndex (int). Класс Segment содержит методы previous () и next (), возвращающие предыдущий и следующий символ строки, а также методы first () и last (), возвращающие первый и последний символ строки. Будьте внимательны: эти четыре метода меняют текущую позицию строки!
Интересно, что для быстроты доступа строка класса Segment хранится в открытом (public) поле — массиве с именем array типа char [ ], начиная с индекса offset, и занимает в этом массиве count элементов. Это открытые поля, так что к массиву символов можно обращаться напрямую и менять его элементы, хотя при этом теряется главное назначение класса Segment- быстро просматривать текст. Метод getBeginIndex() воз
вращает индекс начала строки в массиве array, т. е. число offset, а getEndIndex( ) индекс элемента массива, следующего за последним символом строки.
Заканчивая обзор класса Segment, скажем, что для большей надежности выполнения метода getText(int, int, Segment) в класс Segment введен метод setPartialReturn(boolean). Если в этом методе задать параметр true, то передача текста методом getText () в экземпляр класса Segment будет происходить, по возможности, без дополнительного копирования. Значение параметра по умолчанию — false. С учетом этого, работа с классом Segment начинается примерно так:
Segment seg = new Segment(); seg.setPartialReturn(true); doc.getText(0, doc.getLength(), seg);
// Работаем с объектом seg...
Запись текста в документ
Прежде чем использовать текст документа, его надо записать в документ. Запись выполняется методом
void insertString(int offset, String text, AttributeSet attr);
Новый текст text вставляется перед символом с позицией offset, позиция этого и следующих символов увеличивается на длину вставленного текста.
Атрибуты текста
Как видно из сигнатуры метода insertString(), у вносимого текста могут быть атрибуты, например: имя шрифта, размер шрифта, цвет. Если у текста нет атрибутов, то третьему параметру метода надо дать значение null.
Атрибуты записываются в виде пар "имя — значение" в объект, реализующий интерфейс AttributeSet. Этот интерфейс описывает неизменяемое множество атрибутов, в нем не описаны методы добавления и удаления атрибутов. Такие методы внесены в его расширение — интерфейс MutableAttributeSet. В библиотеке Swing есть реализация данного интерфейса — класс SimpleAttributeSet. С помощью этого класса можно определить любые пары "имя — значение", но общепринятые атрибуты удобнее задавать с использованием констант и статических методов класса StyleConstants и четырех его подклассов, которые в то же время вложены в него: CharacterConstants, ColorConstants, FontConstants и ParagraphConstants.
Объект, реализующий интерфейс AttributeSet, может содержать ссылку на другой, "родительский" объект того же типа. Ссылка хранится как значение атрибута, имеющего имя ResolveAttribute. Так можно получить цепочку объектов, содержащих атрибуты текста. Если какая-то пара "имя — значение" не найдена в первом объекте методом getAttribute (Object), то она отыскивается в родительском объекте, который определяется методом getResolveParent (), затем поиск идет далее по цепочке.
У интерфейса MutableAttributeSet есть свое расширение- интерфейс Style. Это расши
рение дает возможность получить имя множества атрибутов методом getName ( ), создав так называемый стиль (style), и присоединить к множеству слушателя события
ChangeEvent методом
void addChangeListener(ChangeListener chl);
Заданное имя затем можно использовать как значение другого атрибута, а с помощью слушателя отслеживать добавление и удаление атрибутов.
Для создания стилей и работы с ними очень полезен класс StyleContext. Его экземпляр с общепринятым набором атрибутов можно получить следующим образом:
StyleContext stc = StyleContext.getDefaultStyleContext();
Затем в полученный объект stc можно добавить новые атрибуты методами addAttribute (), удалить атрибуты методами removeAttribute(), создать цепочку стилей.
Удаление текста из документа
Обратная операция — удаление части или всего текста из документа — выполняется методом
remove(int offset, int length);
Он удаляет length символов, начиная от символа, находящегося в позиции offset.
Фильтрация документа
Операции занесения текста в документ методом insertString() и удаления методом remove () можно изменить так, чтобы они производили различные проверки и модификации, фильтруя таким способом вставляемый или удаляемый текст. Это можно сделать прямым расширением класса, реализующего Document, и переопределением его методов insertString () и remove (). Но есть еще один способ, не изменяющий документ.
Сначала надо расширить класс DocumentFilter, переопределив его методы. В классе DocumentFilter всего три метода:
void insertString(DocumentFilter.FilterBypass fb, int offset,
String text, AttributeSet attr);
void remove(DocumentFilter.FilterBypass fb, int offset, int length); void replace(DocumentFilter.FilterBypass fb, int offset, int length,
String text, AttributeSet attr);
Их стандартная реализация просто вызывает соответствующие методы вложенного абстрактного класса FilterBypass, которые оставлены абстрактными.
После расширения класса DocumentFilter, вызванного переопределением методов, полученный фильтр надо установить в документ методом
void setDocumentFilter(DocumentFilter filter);
класса AbstractDocument. Далее всякое обращение к методам insertString () и remove () документа будет пропускаться через методы созданного фильтра.
Пример использования фильтра, пропускающего только цифры, приведен в листинге 12.1.
Внесение структуры в документ
В модель данных можно внести структуру дерева, например разбить документ на главы, параграфы, разделы. Каждый элемент разбиения описывается интерфейсом Element. Элемент занимает какую-то область текста с начальной позицией, возвращаемой методом getStartOffset (), и конечной позицией getEndOffset (). У элемента может быть родительский элемент, который легко получить методом getParentElement(). Область текста, занимаемая родительским элементом, полностью включает в себя область исходного элемента. У элемента могут быть дочерние элементы, чья область текста полностью лежит внутри области самого элемента. Их можно получить методом getElement(int). Число дочерних элементов возвращает метод getElementCount (), а индекс дочернего элемента — метод getElementIndex (int). Элементу можно дать имя, а затем получить его методом getName ().
Интерфейс Element частично реализован абстрактным классом AbstractElement, вложенным в класс AbstractDocument, и полностью реализован еще двумя вложенными
в AbstractDocument классами — BranchElement и LeafElement, расширяющими класс AbstractElement. Основная разница между ними в том, что у класса BranchElement могут быть дочерние элементы, а у класса LeafElement — нет.
Класс BranchElement, в свою очередь, расширяется классом SectionElement, вложенным в класс DefaultStyledElement, и классом BlockElement, вложенным в класс HTMLDocument.
Класс LeafElement расширяется классом RunElement, вложенным в класс HTMLDocument. Элементы создаются методами
Element createLeafElement(Element parent, AttributeSet attr,
int pos1, int pos2);
Element createBranchElement(Element parent, AttributeSet attr);
Для каждого структурного элемента можно задать свое множество атрибутов методом
addAttribute(Object name, Object value) или методом addAttributes(AttributeSet).
В документе допускается задание нескольких независимых структур. Их корневые элементы можно получить методом getRootElements ( ), возвращающим массив типа Element [ ]. Один из корневых элементов можно сделать корневым элементом по умолчанию и получать его методом getDefaultRootElement(), возвращающим элемент в виде объекта, реализующего интерфейс Element. Получив корневые элементы структурного дерева, легко обойти его, используя метод getElement(int) интерфейса Element или метод children (), имеющийся в его реализациях.
События в документе
При всяком изменении документа или его структуры происходит событие, описанное интерфейсом DocumentEvent. Он предлагает метод getDocument ( ), позволяющий узнать, в каком документе произошло событие, методы getOffset () и getLength (), сообщающие о начальной позиции и длине измененного текста. Вложенный интерфейс ElementChange содержит метод getElement (), позволяющий узнать элемент, в котором произошло событие, и методы, помогающие отследить добавление и удаление элемента из документа.
Реализация интерфейса DocumentEvent — класс DefaultDocumentEvent, вложенный в класс AbstractDocument, — добавляет к методам интерфейса метод undo (), отменяющий изменения, метод redo (), восстанавливающий изменения, и еще несколько информационных методов.
Если модель данных позволяет отменять и восстанавливать изменения (undo/redo), то при каждом таком действии в ней происходит событие класса UndoableEditEvent.
Реализации документа
Интерфейс Document частично реализован абстрактным классом AbstractDocument. Этот класс вносит понятие блокировки документа. Документ могут просматривать несколько подпроцессов-"читателей" и один подпроцесс-"писатель". Доступ их к документу блокируется методами readLock() и writeLock(). Блокировки снимаются методами
readUnlock() и writeUnlock().
Класс AbstractDocument обычно не расширяется непосредственно, а используются или расширяются его подклассы PlainDocument и DefaultStyledDocument.
Класс PlainDocument задает модель простого документа с "плоским" текстом, которая используется полями ввода JTextField, JPasswordField, JTextArea. Текст в этой модели имеет структуру: структурные элементы текста — это строки. Корневой элемент структуры можно получить методом getDefaultRootElement(). Метод getParagraphElement(int offset) возвращает элемент структуры — строку в виде объекта типа Element, к которому принадлежит позиция offset. Каждой строке, как любому элементу структуры, можно придать атрибуты. Отдельные символы атрибутов не имеют.
Более сложную структуру вносит в документ модель класса DefaultStyledDocument, используемая в текстовом редакторе JTextPane. В этой модели не только строке, но и каждому символу текста можно задать свой стиль.
Наконец, класс DefaultStyledDocument расширяется классом HTMLDocument. Это модель разметки языка HTML. В ней можно определить таблицы стилей (style sheets).
Установка модели данных
После того как новая модель данных определена, ее надо установить в компонент методом setDocument(Document) класса JTextComponent.
Вид
Вторая часть схемы MVC — Вид — построена для текстовых компонентов так, что для каждого элемента документа создается свой вид, значит, каждый элемент может получить свое графическое оформление.
Эта идея частично реализована абстрактным классом View. Он задает для каждого документа целую структуру Видов, отвечающую структуре элементов документа. Каждый вид из этой структуры при своем создании получает ссылку на определенный элемент документа, которую можно отследить методом getElement (). Документ, к которому относится Вид, можно получить методом getDocument(). У каждого Вида есть родительский вид, который определяется методами getParent() и setParent ( ), и множество дочерних видов. Их число можно определить методом getViewCount(), получить дочерние виды можно методом getView(int).
Создание дочерних Видов выполняется методом create(Element), описанным в интерфейсе ViewFactory. В документе у каждого элемента есть объект, реализующий этот интерфейс, который можно получить методом getViewFactory(). Еще несколько методов занимаются добавлением видов в иерархию и удалением их оттуда.
Каждый Вид должен преобразовать линейный порядок следования символов в элементе документа, определяемый их позициями, в двумерное отображение символов на экран, состоящее из нескольких строк экрана. Это выполняется методом
Shape modelToView(int startPos, Position.Bias b0,
int endPos, Position.Bias b1, Shape fig);
который возвращает двумерную фигуру класса Shape. Параметры метода задают начальную startPos и конечную endPos позиции текста, направления b0 и b1 от этих позиций к преобразуемому тексту, которые могут принимать одно из двух значений:
Position.Bias.Backward или Position.Bias. Forward, и окружающую фигуру fig.
Обратное преобразование выполняется методом
int viewToModel(float x, float y, Shape fig, Position.Bias[] b);
возвращающим позицию символа, имеющего координаты (x, y) на экране в фигуре fig. Кроме того, метод вычисляет массив направлений b, уточняющий положение символа в модели данных.
Для вывода на экран в каждом виде создается графический контекст — экземпляр класса Graphics. Непосредственный вывод элемента на экран выполняется методом paint (Graphics) подобно выводу компонента. Графическим контекстом можно воспользоваться не только в методе paint(Graphics), но и непосредственно, получив его методом getGraphics ( ).
Каждый Вид устанавливает свой размер методом setSize(float width, float height), у него есть минимальный, предпочтительный и максимальный размер.
В этом класс View напоминает класс Component. Сходство усиливается тем, что подобно тому, как класс Component порождает множество компонентов, создающих на экране графический интерфейс, класс View порождает множество подклассов-видов, отображающих на экране различные типы документов. Их иерархия показана на рис. 12.1.
Object
L View-г CompositeView— BoxView
PlainView
ImageView - IconView
-1— BlockView — ListView
— FlowView-ParagraphView
FieldView — TableView
LPasswordView — TableView.TableRow
— WrappedPlainView
— ZoneView
-GlyphView-LabelView—InlineView
-AsyncBoxView
- ComponentView-p FormView LobjectView
Рис. 12.1. Иерархия классов-видов
Как видно из рис. 12.1, иерархия Видов обширна и разветвлена. Большинство классов связано с интерпретацией языка HTML, например класс ImageView обрабатывает тег
<IMG>, класс FormView тег <FORM> и относящиеся к нему теги <INPUT>, <SELECT>, <TEXTAREA>,
класс ObjectView — тег <OBJECT>.
Класс PlainView создает несколько строк текста с одним шрифтом и используется в области ввода JTextArea, класс FieldView образует одну строку и применяется в поле ввода JTextField, класс PasswordView — в поле ввода пароля JPasswordView.
Класс BoxView и его подклассы создают прямоугольный вид текста разного вида.
Такое разнообразие видов обычно удовлетворяет запросы разработчика, и созданием собственных видов приходится заниматься редко.
Контроллер — редактор текста
Третья часть модели MVC — Контроллер — реализована в текстовых компонентах набором редакторов текста. Их иерархия начинается с абстрактного класса EditorKit, в котором описаны абстрактные методы чтения из байтового и символьного входного потока, например, связанного с клавиатурой, в модель данных
void read(InputStream in, Document doc, int pos); void read(Reader in, Document doc, int pos);
и методы записи из модели данных в байтовый и символьный потоки
void write(OutputStream out, Document doc, int pos, int length); void write(Writer out, Document doc, int pos, int length);
Класс позволяет создать свой документ методом
Document createDefaultDocument();
и получить связанную с ним "фабрику" видов методом
ViewFactory getViewFactory();
Класс определяет курсор как текущую позицию вида, предназначенную для вставки и удаления текста методом
Caret createCaret();
Опишем курсор подробнее.
Курсор
Курсор описан интерфейсом Caret и реализован классом DefaultCaret как тонкая вертикальная черта, отмечающая позицию между символами. Текущая позиция называется точкой (dot). Для работы с выделенным текстом отмечается еще одна позиция — другой конец выделенного текста — называемая меткой (mark). Пока выделения нет, метка совпадает с точкой. При перемещении точки методом moveDot (int) метка остается на месте и создается выделенный участок текста. При установке точки методом setDot (int) метка переносится в точку и выделение отменяется.
Выделенный текст можно отметить на экране или никак не отмечать. Это регулируется методом setSelectionVisible(boolean), а отслеживается логическим методом
isSelectionVisible().
Отследить положение точки и метки можно методами getDot ( ) и getMark (), возвращающими их линейную позицию в части Вид схемы MVC. Определить двумерную текущую позицию курсора можно методом
Point getMagicCaretPosition();
а установить — методом
void setMagicCaretPosition(Point);
Во время перемещения курсора эта позиция имеет значение null.
Визуализация курсора осуществляется методом paint(Graphics). Класс DefaultCaret расширяет класс Rectangle, определяя прямоугольник, внутри которого вычерчивается курсор.
Мерцание курсора можно задать методом setBlinkRate(int), в котором указывается задержка в миллисекундах.
Курсор можно показать на экране или убрать его с экрана методом setVisible(true), а проследить за этим-логическим методом isVisible().
Изменение положения курсора вызывает событие ChangeEvent, которое обрабатывается обычным образом. Кроме того, курсор реагирует на события мыши и изменение фокуса ввода, при этом метод paint(Graphics) может изменить форму и цвет курсора.
Таким образом, библиотека Swing предоставляет все возможности для создания курсора любого вида.
Ограничение перемещения курсора
Подобно тому, как класс DocumentFilter отбирает символы перед занесением их в документ, класс NavigationFilter позволяет отследить перемещения курсора и выделения текста и ограничить их, например для того, чтобы не допустить выделения какого-то участка текста.
Для того чтобы задать ограничения курсору, надо расширить класс NavigationFilter, переопределив следующие его методы:
П void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) — определяет положение следующей позиции точки dot и метки курсора;
П void moveDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) — определяет положение следующей позиции точки dot, оставляя метку на месте;
П int getNextVisualPositionFrom(JTextComponent tc, int pos, Position.Bias bias, int direction, Position.Bias[] biasRet) - вычисляет следующую позицию относительно
текущей позиции pos с учетом направления движения курсора direction. Стандартная реализация вызывает метод класса View с тем же названием.
После расширения класса NavigationFilter, вызванного переопределением методов, надо установить полученный ограничитель курсора в текстовый компонент методом
setNavigationFilter(NavigationFilter) класса JTextComponent.
Вот пример фильтра, ограничивающего перемещения курсора и область выделения текста первыми тридцатью символами.
class CursorFilter extends NavigationFilter{
public void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias){ super.setDot(fb, (dot < 30)? dot:30, bias);
}
public void moveDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias){ super.moveDot(fb, (dot < 30)? dot:30, bias);
}
}
После этого определяем текстовый компонент и устанавливаем в него фильтр, например:
JTextArea ta = new JTextArea(5, 60); ta.setNavigationFilter(new CursorFilter());
Реализации редактора
Прямая реализация абстрактного класса EditorKit — класс DefaultEditorKit — кроме определения абстрактных методов вводит еще множество статических полей, задающих реакцию на нажатие специальных клавиш и перемещение курсора. Такой контроллер используется по умолчанию в компоненте JTextComponent.
Класс DefaultEditorKit расширяется классом StyledEditorKit. Этот класс позволяет внести в текст атрибуты, изменяющие стиль текста: шрифт, цвет, подчеркивание, курсив и другие. Такой редактор применяется по умолчанию в компоненте JTextPane.
От класса StyledEditorKit порождены два класса: HTMLEditorKit и RTFEditorKit, редактирующие тексты в форматах HTML и RTF. Возможности последнего класса пока сильно ограничены, а класс HTMLEditorKit собрал вокруг себя два пакета: javax.swing.text.html и j avax. swing. text. html .parser. Классы этих пакетов позволяют задать нестандартную интерпретацию тегов HTML, создать и применить описание DTD документа и таблицы стилей CSS, разработать свой интерпретатор (parser) документа HTML.
Как видите, схема MVC получила в компоненте JTextComponent развитое детальное воплощение. Разработчик при желании может совершенно изменить стандартную реализацию текстовых компонентов. Правда, нужда в этом возникает редко. Чаще всего приходится переопределять метод insertString (), чтобы наложить какие-то ограничения на вводимые символы. Примеры этому будут даны далее.
Как принято в библиотеке Swing, класс JTextComponent дублирует многие методы своей схемы MVC. Большинство действий с текстовым компонентом можно выполнить без непосредственного обращения к Модели, Виду и Контроллеру компонента.
Раскладка клавиатуры
Еще одна возможность, заложенная в класс JtextComponent, — задать раскладку клавиатуры для ввода текста.
Для обеспечения такой возможности при нажатии или отпускании клавиши создается объект класса KeyStroke. Он содержит код клавиши и состояние клавиш-модификаторов <Shift>, <Alt>, <Ctrl> и <Meta>.
Класс KeyStroke предоставляет "фабричные" методы для создания своих объектов одним из следующих статических методов:
П KeyStroke getKeyStroke(char keyChar) — задается символ keyChar, отвечающий нажатию клавиши;
П KeyStroke getKeyStroke(int keyCode, int modifiers) — задается код клавиши keyCode константой вида vk_* класса KeyEvent и отмечается нажатие клавиш <Shift>, <Alt>, <Ctrl> и <Meta> в виде побитовой дизъюнкции констант shift_mask, alt_mask, CTRL_MASK и META_MASK класса InputEvent. Отсутствие модификаторов отмечается нулем;
П Keystroke getKeyStroke(Character keyChar, int modifiers) — символ задается объектом класса Character;
П Keystroke getKeyStroke(int keyCode, int modifiers, boolean onRelease) — последний параметр отмечает, что объект создается при нажатии (false) или отпускании клавиши (true);
П Keystroke getKeyStroke(String keyString) — все параметры записаны в одну строку keyString. Правила записи приведены в документации.
Полученный в результате нажатия или отпускания клавиши объект класса KeyStroke используется затем объектом, реализующим интерфейс Keymap. Этот объект задает реакцию на нажатие клавиши в виде объекта, реализующего интерфейс Action, и хранит набор пар "клавиша- действие" типа "Keystroke-Action". Интерфейс Action описан в
главе 14.
Такой механизм задания реакции на действия с клавиатурой заменяет обычную обработку событий клавиатуры через добавление слушателя к текстовому компоненту.
Новая пара "клавиша — действие" добавляется в набор методом
void addActionForKeyStroke(KeyStroke key, Action a);
Весь набор действий в виде массива типа Action[] можно получить методом
getBoundActions(), а набор объектов KeyStroke[] — методом getBoundKeyStrokes(). Отдельное действие Action возвращается методом getAction(KeyStroke).
Объекты типа Keymap можно связать в цепочку, задав родительский объект методом setResolveParent(Keymap). Если пара "клавиша — действие" не окажется найденной в данном объекте, то она будет отыскиваться в родительском объекте и далее по цепочке.
Библиотека Swing не реализует интерфейс Keymap открытым классом. Вместо этого реализация осуществляется закрытым полем класса JTextComponent. При создании текстового компонента это поле заполняется раскладкой по умолчанию default_keymap. Получить текущую раскладку можно методом getKeymap (), а установить новую — методом setKeymap (Keymap). Добавить новую раскладку в цепочку можно статическим методом
addKeymap(String name, Keymap parent);
Печать текста документа
Несколько логических методов print () класса JTextComponent вызывают появление на экране стандартного диалогового окна печати, помогающего выбрать принтер и распечатать на нем содержимое компонента. Методы возвращают false, если пользователь отменил печать, щелкнув мышью по кнопке Cancel в диалоговом окне, и true в противном случае.
П print () — печать текста компонента без колонтитулов.
П print(MessageFormat header, MessageFormat footer) — добавляется печать верхнего header и нижнего footer колонтитулов, оформленных как объекты класса
MessageFormat из пакета java.text.
Остальные, более сложные методы печати используют сервер печати, но это выходит за рамки нашей книги.
Поле ввода JTextField
Хотя внутреннее строение текстовых компонентов сложно, их обычное использование не представляет никаких трудностей.
Однострочное поле ввода создается одним из конструкторов:
П JTextField(int columns) — пустое поле ввода с окном, размер которого достаточен для размещения columns символов. В поле можно вводить сколько угодно символов, окно будет прокручиваться;
П JTextField (String text) -поле ввода с начальным текстом text;
П JTextField (String text, int columns) -поле ввода с начальным текстом text и шири
ной columns символов;
П JTextField(Document doc, String text, int columns) — задается модель данных doc.
Модель данных можно заменить методом setDocument(Document). Допустимо заменять не всю модель, а только шрифт методом setFont ( Font).
Методы, унаследованные от JTextComponent, позволяют занести текст в поле ввода методом setText (String), получить весь текст методом getText(), часть текста методом getText(int offset, int length) или только выделенную часть текста методом
getSelectedText().
Выделенный в поле текст можно заменить другим текстом content методом
replaceSelection(String content).
По умолчанию текст в поле прижимается влево. Изменить это правило можно методом
setHorizontalAlignment (int), задав в нем одну из констант: LEFT, CENTER, RIGHT, LEADING, TRAILING класса JTextField.
По умолчанию текст в поле можно редактировать, но разрешается создавать поле только для чтения унаследованным методом setEditable ( false).
В поле можно установить новый курсор методом setCaret(Caret). Допускается просто изменять цвет курсора методом setCaretColor(Color). Позицию курсора можно отследить методом getCaretPosition(), а задать программно — методом setCaretPosition (int). Переместить курсор программно, выделив таким способом участок текста, можно методом moveCaretPosition (int).
Границы выделенного участка возвращают методы getSelectionStart ( ) и getSelectionEnd ( ), а устанавливают — методы setSelectionStart (int) и setSelectionEnd (int).
Цвет выделенного текста можно задать методом setSelectedTextColor (Color), а цвет фона выделенного текста — методом setSelectionColor(Color).
Работу с системным буфером обмена (clipboard) обеспечивают методы cut (), copy (), отправляющие в буфер выделенный участок текста, и метод paste(), вставляющий в поле содержимое буфера.
Итак, основные действия с полем ввода легко выполняются без обращения к модели данных — документу, виду или редактору. Для более сложных действий надо получить ссылку на документ методом getDocument ( ).
В листинге 12.1 приведен пример текстового поля для ввода одних только цифр.
Листинг 12.1. Поле ввода цифр
import java.awt.*; import javax.swing.*; import javax.swing.text.*;
public class NumberText extends JFrame{
JTextField tf = new JTextField(5);
JLabel l = new JLabel(,,Вводите цифры:");
NumberText(){ super("text");
setLayout(new FlowLayout());
// Вставляем фильтр вводимых символов ((PlainDocument)tf.getDocument()).
setDocumentFilter(new NumberFilter());
// Текст будет выделяться только красным цветом tf.setSelectedTextColor(Color.red);
// При выделении текста фон останется белым tf.setSelectionColor(Color.white);
// Курсор будет красным tf.setCaretColor(Color.red); l.setLabelFor(tf);
add(l); add(tf);
setSize(400, 400);
setDefaultCloseOperation(EXIT ON CLOSE); setVisible(true);
}
public static void main(String[] args){ new NumberText();
}
// Фильтр вводимых данных class NumberFilter extends DocumentFilter{
// Переопределяем только один метод public void insertString(FilterBypass fb, int pos,
String text, AttributeSet attr) throws BadLocationException{
try{
Integer.parseInt(text); // Введена цифра? }catch(Exception e){
// Если не цифра, то символ не вводим super.insertString(fb, 0, "", attr); return;
}
// Если введена цифра, то заносим ее в поле super.insertString(fb, pos, text, attr);
}
}
}
Поле ввода пароля JPasswordField
Класс JPasswordField непосредственно расширяет класс JTextField, значит, к нему относится все сказанное ранее. Одно отличие заключается в том, что в этом поле вместо вводимых символов повторяется один символ, по умолчанию — звездочка. Звездочку можно заменить другим символом с помощью метода setEchoChar(char).
Второе отличие заключается в том, что вместо метода getText () для получения текста из поля пароля используется метод getPassword( ), возвращающий массив символов типа char [], а не строку.