JPasswordField组件被设计用来处理密码输入。密码文本域会显示一个特殊的输入掩码,而不会回显用户的输入。其作用类似于具有*输入掩码的JTextField。我们不能取消掩码设置,也不能剪切或是复制密码组件的内容。其目的就是为了强强安全性。
与JTextField相同,JPasswordField类有五个构造函数:
public JPasswordField() JPasswordField passwordField = new JPasswordField(); public JPasswordField(String text) JPasswordField passwordField = new JPasswordField("Initial Password"); public JPasswordField(int columnWidth) JPasswordField passwordField = new JPasswordField(14); public JPasswordField(String text, int columnWidth) JPasswordField passwordField = new JPasswordField("Initial Password", 14); public JPasswordField(Document model, String text, int columnWidth) JPasswordField passwordField = new JPasswordField(aModel, "Initial Password", 14);
使用无参数的构造函数,我们可以获得一个空的,零列宽的输入域,默认的初始化Document模型,以及*回显字符。尽管我们可以在构造函数中指定初始化文本,但是通常我们所要做的是提示用户输入密码来验证用户的标识,而不是确定用户是否可以提交一个表单。所以,JPasswordField的本意是在启动时是空的。类似于JTextField,我们也可以指定初始宽度,假定JPasswordField所在的窗口的布局管理器将处理这种请求。
我们也可以在构造函数中指定密码域的Document数据模型。当指定Document数据模型时,我们应该指定一个null初始化文本参数;否则,文档的当前内容就会被密码域的初始文本所替换。另外,我们不应尝试在JPasswordField中使用自定义的Document。因为组件在已输入多少字符之外并不会显示任何可视化的回馈,如果我们尝试将输入限制为数字数据,这会使用户感到迷惑。
表15-6显示了JPasswordField的四个属性。
设置echoChar属性可以使得我们使用默认星号字符以外的掩码字符。如查echoChar属性被设置为字符\u0000(0),public boolean echoCharIsSet()方法会返回false。在其他的情况下,方法会返回true。
注意,JPasswordField有一个受保护的只读的text属性,我们应避免使用这个属性。相反,我们应使用password属性,因为他会返回一个char[]并在使用之后立即清除。一个String必须等待垃圾回收器来翻译。
JPasswordField是JTextField的一个子类。在所有预定义的观感类型下,他与JTextField具有相同的外观(如图15-15所示)。一个不同就是当前的echoChar属性设置隐藏内容。如图15-16所示。顶部的文本组件是一个JTextField;而底部则是一个JPasswordField。
表15-7显示了JPasswordField的17个UIResource相关的属性。
JFormattedTextField提供了格式化文本输入的支持。当这个组件创建时,我们为输入定义了一个掩码。这个掩码可以是以下四种格式之一:一个java.text.Format对象,一个AbstractFormatter,一个AbstractFormatterFactory或是一个不同类型的实际值(例如3.141592)。
依据我们希望用户输入的数据类型,系统为我们的使用提供了一些抽象格式器。例如,NumberFormatter可以用来输入数字,而DateFormatter可以用来输入整个日期。同时还有一个MaskFormatter用于描述具有编辑字行串的输入,例如用于美国社会保险号码的“XXX-XX-XXX”。如果我们希望不同的显示与编辑格式,我们可以使用AbstractFormatterFactory。我们将会在第16章中了解到关于格式器与格式器工厂的更多内容。
JFormattedTextField类有六个构造函数:
public JFormattedTextField() JFormattedTextField formattedField = new JFormattedTextField(); public JFormattedTextField(Format format) DateFormat format = new SimpleDateFormat("yyyy--MMMM--dd"); JFormattedTextField formattedField = new JFormattedTextField(format); public JFormattedTextField(JFormattedTextField.AbstractFormatter formatter) DateFormat displayFormat = new SimpleDateFormat("yyyy--MMMM--dd"); DateFormatter displayFormatter = new DateFormatter(displayFormat); JFormattedTextField formattedField = new JFormattedTextField(displayFormatter); public JFormattedTextField(JFormattedTextField.AbstractFormatterFactory factory) DateFormat displayFormat = new SimpleDateFormat("yyyy--MMMM--dd"); DateFormatter displayFormatter = new DateFormatter(displayFormat); DateFormat editFormat = new SimpleDateFormat("MM/dd/yy"); DateFormatter editFormatter = new DateFormatter(editFormat); DefaultFormatterFactory factory = new DefaultFormatterFactory( displayFormatter, displayFormatter, editFormatter); JFormattedTextField formattedField = new JFormattedTextField(factory); public JFormattedTextField(JFormattedTextField.AbstractFormatterFactory factory, Object currentValue) DateFormat displayFormat = new SimpleDateFormat("yyyy--MMMM--dd"); DateFormatter displayFormatter = new DateFormatter(displayFormat); DateFormat editFormat = new SimpleDateFormat("MM/dd/yy"); DateFormatter editFormatter = new DateFormatter(editFormat); DefaultFormatterFactory factory = new DefaultFormatterFactory( displayFormatter, displayFormatter, editFormatter); JFormattedTextField formattedField = new JFormattedTextField(factory, new Date()); public JFormattedTextField(Object value) JFormattedTextField formattedField = new JFormattedTextField(new Date());
无参数的构造函数需要我们在稍后进行配置。其他的构造函数允许我们配置内容将会接受什么以及如何接受。
表15-8显示了JFormattedTextField的八个属性。我们不必像使用JTextField时一样,通过text属性将JFormattedTextField的内容获取为一个String,而是可以通过value属性将其获取为一个Object。所以,如果我们的格式器用于一个Date对象,我们所获得的值可以转换为java.util.Date类型。
列表15-14演示了具有自定义格式器与工厂的JFormattedTextField的用户。注意,当我们编辑底部的文本域时,显示格式与编辑格式是不同的。
/** * */ package swingstudy.ch15; import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import javax.swing.JFormattedTextField; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.text.DateFormatter; import javax.swing.text.DefaultFormatterFactory; /** * @author mylxiaoyi * */ public class FormattedSample { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable runner = new Runnable() { public void run() { JFrame frame = new JFrame("Formatted Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel datePanel = new JPanel(new BorderLayout()); JLabel dateLabel = new JLabel("Date: "); dateLabel.setDisplayedMnemonic(KeyEvent.VK_D); DateFormat format = new SimpleDateFormat("yyyy--MMMM--dd"); JFormattedTextField dateTextField = new JFormattedTextField(format); dateLabel.setLabelFor(dateTextField); datePanel.add(dateLabel, BorderLayout.WEST); datePanel.add(dateTextField, BorderLayout.CENTER); frame.add(datePanel, BorderLayout.NORTH); JPanel date2Panel = new JPanel(new BorderLayout()); JLabel date2Label = new JLabel("Date 2: "); date2Label.setDisplayedMnemonic(KeyEvent.VK_A); DateFormat displayFormat = new SimpleDateFormat("yyyy--MMMM--dd"); DateFormatter displayFormatter = new DateFormatter(displayFormat); DateFormat editFormat = new SimpleDateFormat("MM/dd/yy"); DateFormatter editFormatter = new DateFormatter(editFormat); DefaultFormatterFactory factory = new DefaultFormatterFactory(displayFormatter, displayFormatter, editFormatter); JFormattedTextField date2TextField = new JFormattedTextField(factory, new Date()); date2Label.setLabelFor(date2TextField); date2Panel.add(date2Label, BorderLayout.WEST); date2Panel.add(date2TextField, BorderLayout.CENTER); frame.add(date2Panel, BorderLayout.SOUTH); ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent event) { JFormattedTextField source = (JFormattedTextField)event.getSource(); Object value = source.getValue(); System.out.println("Class: "+value.getClass()); System.out.println("Value: "+value); } }; dateTextField.addActionListener(actionListener); date2TextField.addActionListener(actionListener); frame.setSize(250, 100); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } }
类似于JPasswordField,JFormattedTextField也是JTextField的一个子类。在所有的预定义的观感类型下,同样与JTextField具有相同的外观(如图15-15)。要自定义其显示,我们可以修改JFormattedTextField的16个UIResource相关的属性集合中的任何一个,如表15-9所示。
JTextArea是用于多行输入的文本组件。类似于JTextField,JTextArea的数据模型是Document接口的PlainDocument实现。所以,JTextArea被限制为单属性文本。类似于其他的需要滚动的Swing组件,JTextArea本身不支持滚动。我们需要将JTextArea放在JScrollPane中来允许在JTextArea中进行滚动。
JTextArea有六个构造函数:
public JTextArea() JTextArea textArea = new JTextArea(); public JTextArea(Document document) Document document = new PlainDocument(); JTextArea textArea = new JTextArea(document); public JTextArea(String text) JTextArea textArea = new JTextArea("..."); public JTextArea(int rows, int columns) JTextArea textArea = new JTextArea(10, 40); public JTextArea(String text, int rows, int columns) JTextArea textArea = new JTextArea("...", 10, 40); public JTextArea(Document document, String text, int rows, int columns) JTextArea textArea = new JTextArea(document, null, 10, 40);
除非特别指定,文本区域也可以存储零行与零列的内容。尽管这听起来像是一个严重的限制,我们只需要告诉文本区域来使得当前的LayoutManager处理我们的文本区域的尺寸。JTextArea的内容初始时是空的,除非使用起始文本字符串或是Document模型指定。
注意,其他的JTextArea初始设置包括一个Tab为八个位置以及关闭文字换行。要了解关于Tab的更多内容,可以查看第16章中的TabStop与TabSet类。
在创建了JTextArea之后,记得将JTextArea放在JScrollPane中。然后在屏幕上如果没有足够的空间,JScrollPane就会为我们管理滚动。
JTextArea textArea = new JTextArea(); JScrollPane scrollPane = new JScrollPane(textArea); content.add(scrollPane);
图15-17显示了在JScrollPane之内以及在JScrollPane之外的JTextArea的样子。不在JScrollPanel中的JTextArea,我们不能看到超出屏幕边界的文本。依照设计,将光标移动进区域并不会使得顶部的内容向上移动。
表15-10显示了JTextArea的12个属性。
rows与columns属性直接来自于构造函数的参数。preferredScrollableViewportSize与scrollableTracksViewportWidth属性来自于用于滚动支持的Scrollable接口实现。font与preferredSize属性仅是自定义由JTextComponent继承的行为。
更为有趣的属性是lineCount,tabSize以及lineWrap与wrapStyledWorld。lineCount属性可以使得我们确定文本域中有多少行。这对于调整尺寸十分有用。tabSize属性可以使得我们控制文本区域中tab位置。默认情况下,这个值为8.
lineWrap与wrapStyleWord属性配合使用。默认情况下,较长行的换行是禁止的。如果我们允许换行(通过将lineWrap属性设置为true),较长行换行的时机依赖于wrapStyleWord属性设置。初始时,这个属性为false,意味着如果lineWrap属性为true,将会在字符边界处换行。如果lineWrap与wrapStyleWord都为true,那么一行中不会适的单词将会被换到下一行,类似于字处理器中的样子。所以,要获得大多数人所希望的单词换行的功能,我们应将JTextArea的两个属性都设置为true:
JTextArea textArea = new JTextArea("..."); textArea.setLineWrap(true); textArea.setWrapStyleWord(true); JScrollPane scrollPane = new JScrollPane(textArea);
注意,Ctrl-Tab与Shift-Ctrl-Tab键的组合可以使得用户在JTextArea组件中变换焦点,而无需继承组件生成新类。
JTextArea并没有特定的事件。我们可以使用由JTextComponent继承的监听器中的一个或是关联一个InputVerifier。
有时,我们会在屏幕上放置一个JTextArea并在用户按下按钮之后获取其内容。而在另外一些时间,会涉及到更多的规划,此时我们希望在输入时监视输入,并且也许会进行相应的转换,例如:-)或是简单的笑脸。
每一个可安装的Swing观感都提供了不同的JTextArea外观以及默认的UIResource值集合。图15-18显示在JTextArea组件在预安装的观感类型下的外观。注意,每一个外观上的基本区别在于JScrollPane的滚动条,他并不是JTextArea的实际部分。
表15-11显示了JTextArea的15个UIResource相关的属性集合。
JEditorPane类提供了显示与编辑多属性文本的功能。虽然JTextField与JTextArea只支持单颜色,单字体内容,JEditorPane允许我们使用各种风格(例如粗体,14点Helvetica,段落右对齐)或是HTML查看器的外观来标记我们的内容,如图15-19所示。
注意,JEditorPane的HTML支持只在具有某些扩展的HTML 3.2级别上可用,而编写本书时HTML 4.0x是当前的版本。级联样式表(CSS)被部分支持。
JEditorPane借助于一个特定的文本标记机制的EditorKit来支持多属性文本的显示与编辑。存在预定义的工具集来支持原始文本,HTML文档以及RTF文档。因为内容是多属性的,PlainDocument模型不再够用。相反,Swing以DefaultStyledDocument类的形式提供了一个StyledDocument来维护文档模型。其余的部分是一个新的HyperlinkListsener/HyperlinkEvent事件处理对用来监视文档中的超连接操作。
JEditorPane有四个构造函数:
public JEditorPane() JEditorPane editorPane = new JEditorPane(); public JEditorPane(String type, String text) String content = "<H1>Got Java?</H1>"; String type = "text/html"; JEditorPane editorPane = new JEditorPane(type, content); public JEditorPane(String urlString) throws IOException JEditorPane editorPane = new JEditorPane("http://www.apress.com"); public JEditorPane(URL url) throws IOException URL url = new URL("http://www.apress.com"); JEditorPane editorPane = new JEditorPane(url);
无参数的构造函数创建了一个空的JEditorPane。如果我们要初始化内容,我们可以直接指定文本或是其MIME类型。或者是我们可以指定获取内容的URL。URL可以作为一个String或是一个URL对象来指定。当我们将内容指定为一个URL,JEditorPane会由响应来确定MIME类型。
表15-12显示了JEditorPane的11个属性。这些属性中的大部分仅是自定义父类的行为。
注意,page属性是非标准的,因为他有两个setter方法,但是只有一个getter方法。
JEditorPane的四个有趣属性是editorKit,contentType,page与text。editorKit属性是依据编辑器面板中的内容类型来配置的。我们将会在第16章中进行详细探讨其DefaultEditorKit,StyledEditorKit与HTMLEditorKit实现。contentType属性表示文档中内容类型的MIME类型。当我们在构造函数中(或是其他位置)设置内容时,这个属性会被自动设置。如果编辑器工具集不能确定MIME类型,我们可以进行手动设置。三个内建支持的数据类型是text/html,text/plain与text/rtf,通过预定义编辑器工具集的getContentType()方示可以获取这些类型。
page属性可以使得我们修改所显示的内容来反映一个特定URL的内容,从而我们可以以某种方式使用这些内容。text属性使得我们确定哪些文本内容基于当前的Document模型。
因为JEditorPane仅是一个具有一些特殊显示特性的另一个文本区域组件,他支持与JTextArea组件相同的用于事件处理的监听器。另外,JEditorPane提供了一个特殊的监听器事件组合来处理文档中的超链接。
HyperlinkListener接口定义了一个方法,public void hyperlinkUpdate(HyperlinkEvent hyperlinkEvent),他使用一个HyperlinkEvent来响应-不要惊奇-超链接事件。事件包含一个报告事件类型的HyperlinkEvent.EventType并且使得我们进行不同的响应,或者是当选中时跟随链接或者是当在超链接上移动鼠标时改变光标(尽管这是默认发生的)。
下面是HyperlinkListener定义:
public interface HyperlinkListener implements EventListener { public void hyperlinkUpdate(HyperlinkEvent hyperlinkEvent); } And, here is the HyperlinkEvent definition: public class HyperlinkEvent extends EventObject { // Constructors public HyperlinkEvent(Object source, HyperlinkEvent.EventType type, URL url); public HyperlinkEvent(Object source, HyperlinkEvent.EventType type, URL url, String description); public HyperlinkEvent(Object source, HyperlinkEvent.EventType type, URL url, String description, Element sourceElement) // Properties public String getDescription(); public HyperlinkEvent.EventType getEventType(); public Element getSourceElement(); public URL getURL(); }
超链接类型将会是HyperlinkEvent.EventType类的三个常量之一:
所以,如果我们希望在工具栏上创建一个显示URL的HyperlinkListener,当在超链接之前并在激活时跟随超链接,我们可以创建我们自己的最简单的HTML帮助查看器。列表15-15中的HyperlinkListener实现将会为我们实现这一技巧。在监听器中提供了一些println语句,当鼠标位于URL之上并且URL被激活时显示URL。
/** * */ package swingstudy.ch15; import java.awt.EventQueue; import java.awt.Frame; import java.io.IOException; import java.net.URL; import javax.swing.JEditorPane; import javax.swing.JOptionPane; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import javax.swing.text.Document; /** * @author mylxiaoyi * */ public class ActivatedHyperlinkListener implements HyperlinkListener { Frame frame; JEditorPane editorPane; public ActivatedHyperlinkListener(Frame frame, JEditorPane editorPane) { this.frame = frame; this.editorPane = editorPane; } /* (non-Javadoc) * @see javax.swing.event.HyperlinkListener#hyperlinkUpdate(javax.swing.event.HyperlinkEvent) */ @Override public void hyperlinkUpdate(HyperlinkEvent event) { // TODO Auto-generated method stub HyperlinkEvent.EventType type= event.getEventType(); final URL url = event.getURL(); if(type==HyperlinkEvent.EventType.ENTERED) { System.out.println("URL: "+url); } else if(type==HyperlinkEvent.EventType.ACTIVATED) { System.out.println("Activated"); Runnable runner = new Runnable() { public void run() { Document doc = editorPane.getDocument(); try { editorPane.setPage(url); } catch(IOException ioException) { JOptionPane.showMessageDialog(frame, "Error following link", "Invalid link", JOptionPane.ERROR_MESSAGE); editorPane.setDocument(doc); } } }; EventQueue.invokeLater(runner); } } }
提示,不要忘记调用setEditable(false)方法将JEditorPane设置为只读。否则,查看器就成为了编辑器。
列表15-16是使用我们新创建的ActivatedHyperlinkListener类的完整示例。他所创建的窗体类似于前面图15-19中所示的页面,尽管是在图片中,About链接已经被跟随。
/** * */ package swingstudy.ch15; import java.awt.EventQueue; import java.io.IOException; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.event.HyperlinkListener; /** * @author mylxiaoyi * */ public class EditorSample { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable runner = new Runnable() { public void run() { JFrame frame = new JFrame("EditorPane Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); try { JEditorPane editorPane = new JEditorPane("http://www.google.com"); editorPane.setEditable(false); HyperlinkListener hyperlinkListener = new ActivatedHyperlinkListener(frame, editorPane); editorPane.addHyperlinkListener(hyperlinkListener); JScrollPane scrollPane = new JScrollPane(editorPane); frame.add(scrollPane); } catch(IOException e) { System.err.println("Unable to load: "+e); } frame.setSize(640, 480); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } }
JEditorPane的外观类似于JTextArea。尽管所支持的内容不同,观感相关的属性通常是不同的。
表15-13显示了JEditorPane的15个UIResource相关的属性集合。属性的名字于JTextArea设置中的属性名字。
JTextPane是JEditorPane的一种特殊形式,特别设计用来编辑(与显示)格式化文本。他与JEditorPane的唯一不同在于提供显示内容的方式,因为文本并不是像在HTML或是RTF文档中一样使用格式标记的。
JTextPane依赖设置文本属性的三个接口:AttributeSet用于基本的属性集合,MutableAttributeSet用于可修改的属性集合,Style用作与StyledDocument的部分相关联的属性集合。
本节将会介绍JTextPane。要了解关于在JTextPane中配置格式化内容不同部分的格式的信息可以查看第16章。
JTextPane只有两个构造函数:
public JTextPane() JTextPane textPane = new JTextPane(); JScrollPane scrollPane = new JScrollPane(textPane); public JTextPane(StyledDocument document) StyledDocument document = new DefaultStyledDocument(); JTextPane textPane = new JTextPane(document); JScrollPane scrollPane = new JScrollPane(textPane);
无参数的构造函数初始时没有内容。第二个构造函数使得我们先创建Document,然后在JTextPane中使用。
提示,如果内容大于可用的屏幕空间,记得将我们的JTextPane放在JScrollPane中。
表15-14显示了JTextPane的八个属性。我们将会在第16章中详细探讨这些属性。
JTextPane是JEditorPane的一个子类。他在所有预定义的观感类型下与JTextArea具有相同的外观(如图15-18所示)。尽管内容也许不同,但是观感是相同的。
表15-15中显示了JTextPane UIResource相关属性的可用集合。对于JTextPane组件,有15个不同的属性。其属性名字类似于JTextArea设置中的属性名字。
列表15-17提供了一个向JTextPane载入StyledDocument内容的示例。这仅是向我们展示功能。Style,SimpleAttributeSet与StyledConstants的详细使用将会在第16章中进行探讨。
/** * */ package swingstudy.ch15; import java.awt.BorderLayout; import java.awt.EventQueue; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultStyledDocument; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; import javax.swing.text.StyledDocument; /** * @author mylxiaoyi * */ public class TextPaneSample { private static String message = "In the beginning, there was COBOL, then there was FORTRAN, "+ "then there was BASIC, ... and now there is Java.\n"; /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable runner = new Runnable() { public void run() { JFrame frame = new JFrame("TextPane Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); StyleContext context = new StyleContext(); StyledDocument document = new DefaultStyledDocument(context); Style style = context.getStyle(StyleContext.DEFAULT_STYLE); StyleConstants.setAlignment(style, StyleConstants.ALIGN_RIGHT); StyleConstants.setFontSize(style, 14); StyleConstants.setSpaceAbove(style, 4); StyleConstants.setSpaceBelow(style, 4); // Inset content try { document.insertString(document.getLength(), message, style); } catch(BadLocationException badLocationException) { System.err.println("Oops"); } SimpleAttributeSet attributes = new SimpleAttributeSet(); StyleConstants.setBold(attributes, true); StyleConstants.setItalic(attributes, true); // Insert content try { document.insertString(document.getLength(), "Hello Java", attributes); } catch(BadLocationException badLocationException) { System.err.println("Oops"); } // Third style for icon/component Style labelStyle = context.getStyle(StyleContext.DEFAULT_STYLE); Icon icon = new ImageIcon("Computer.gif"); JLabel label = new JLabel(icon); StyleConstants.setComponent(labelStyle, label); // Insert content try { document.insertString(document.getLength(), "Ignored", labelStyle); } catch(BadLocationException badLocationException) { System.err.println("Oops"); } JTextPane textPane = new JTextPane(document); textPane.setEditable(false); JScrollPane scrollPane = new JScrollPane(textPane); frame.add(scrollPane, BorderLayout.CENTER); frame.setSize(300, 150); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } }
上述源码的关键行是调用insertString()与其style参数:
document.insertString(document.getLength(), message, style);
图15-20显示了具有一些段落内容的JTextPane的样子。注意,内容并没有限制为仅是广西;他也可以具有图片。
在本章中,我们开始对Swing文本组件的细节进行探讨。我们首先了解了根文本组件,JTextComponent,以及为其他的文本组件定义了许多操作。然后我们探讨特定的文本组件,JTextField,JPasswordField,JFormattedTextField,JTextArea,JEditorPane与JTextPane。
我们同时探讨了构成不同的组件的各种片段。我们深入了基于Document接口,用于AbstractDocument与PlaintDocument类的文本组件模型。我们同时了解了使用DocumentFilter来创建自定义的组件限制文本组件的输入。噣上,我们探讨了用于显示光标与高亮文本的Caret与Highlighter接口,用于限制文本组件中移动的NavigationFilter,以及使得文本组件作为控制器的Keymap。类似于控制器,Keymap将用户的按钮转换为影响文本组件模型的特定动作。
我们同时了解了Swing文本组件中是如何处理事件的。除了基本的AWT事件处理类,Swing添加了一些特别设计的新类,使用CaretListener来监听光标移动,使用DocumentListener监听文档内容变化。而且通过InputVerifer还有一个通用的Swing输入验证支持。
在第16章中,我们将会进一步探讨Swing文本组件。本章仅是所有组件的基本特性,而下一章将会探讨使用TextAction,JFormattedField的格式化输入以及使用StyledDocument的配置Style对象的细节。同时我们还会在HTMLDocument标记中进行探讨。