Text Input

   


We are finally ready to start introducing the Swing user interface components. We start with components that let a user input and edit text. You can use the JTextField and JTextArea components for gathering text input. A text field can accept only one line of text; a text area can accept multiple lines of text.

Both of these classes inherit from a class called JTextComponent. You will not be able to construct a JTextComponent yourself because it is an abstract class. On the other hand, as is so often the case in Java, when you go searching through the API documentation, you may find that the methods you are looking for are actually in the parent class JTextComponent rather than in the derived class. For example, the methods that get or set the text in a text field or text area are actually methods in JTextComponent.


 javax.swing.text.JTextComponent 1.2 

  • void setText(String t)

    changes the text of a text component.

    Parameters:

    t

    The new text


  • String getText()

    returns the text contained in this text component.

  • void setEditable(boolean b)

    determines whether the user can edit the content of the JTextComponent.

Text Fields

The usual way to add a text field to a window is to add it to a panel or other container just as you would a button:

 JPanel panel = new JPanel(); JTextField textField = new JTextField("Default input", 20); panel.add(textField); 

This code adds a text field and initializes the text field by placing the string "Default input" inside it. The second parameter of this constructor sets the width. In this case, the width is 20 "columns." Unfortunately, a column is a rather imprecise measurement. One column is the expected width of one character in the font you are using for the text. The idea is that if you expect the inputs to be n characters or less, you are supposed to specify n as the column width. In practice, this measurement doesn't work out too well, and you should add 1 or 2 to the maximum input length to be on the safe side. Also, keep in mind that the number of columns is only a hint to the AWT that gives the preferred size. If the layout manager needs to grow or shrink the text field, it can adjust its size. The column width that you set in the JTextField constructor is not an upper limit on the number of characters the user can enter. The user can still type in longer strings, but the input scrolls when the text exceeds the length of the field. Users tend to find scrolling text fields irritating, so you should size the fields generously. If you need to reset the number of columns at run time, you can do that with the setColumns method.

TIP

After changing the size of a text box with the setColumns method, call the revalidate method of the surrounding container.

 textField.setColumns(10); panel.revalidate(); 

The revalidate method recomputes the size and layout of all components in a container. After you use the revalidate method, the layout manager resizes the container, and the changed size of the text field will be visible.

The revalidate method belongs to the JComponent class. It doesn't immediately resize the component but merely marks it for resizing. This approach avoids repetitive calculations if multiple components request to be resized. However, if you want to recompute all components inside a JFrame, you have to call the validate method JFrame doesn't extend JComponent.


In general, you want to let the user add text (or edit the existing text) in a text field. Quite often these text fields start out blank. To make a blank text field, just leave out the string as a parameter for the JTextField constructor:

 JTextField textField = new JTextField(20); 

You can change the content of the text field at any time by using the setText method from the JTextComponent parent class mentioned in the previous section. For example:

 textField.setText("Hello!"); 

And, as was also mentioned in the previous section, you can find out what the user typed by calling the getText method. This method returns the exact text that the user typed. To trim any extraneous leading and trailing spaces from the data in a text field, apply the trim method to the return value of getText:

 String text = textField.getText().trim(); 

To change the font in which the user text appears, use the setFont method.


 javax.swing.JTextField 1.2 

  • JTextField(int cols)

    constructs an empty JTextField with a specified number of columns.

    Parameters:

    cols

    The number of columns in the field


  • JTextField(String text, int cols)

    constructs a new JTextField with an initial string and the specified number of columns.

    Parameters:

    text

    The text to display

     

    cols

    The number of columns


  • void setColumns(int cols)

    tells the text field the number of columns it should use.

    Parameters:

    cols

    The number of columns



 javax.swing.JComponent 1.2 

  • void revalidate()

    causes the position and size of a component to be recomputed.


 java.awt.Component 1.0 

  • void validate()

    recomputes the position and size of a component. If the component is a container, the positions and sizes of its components are recomputed.

Labels and Labeling Components

Labels are components that hold text. They have no decorations (for example, no boundaries). They also do not react to user input. You can use a label to identify components. For example, unlike buttons, text fields have no label to identify them. To label a component that does not itself come with an identifier:

  1. Construct a JLabel component with the correct text.

  2. Place it close enough to the component you want to identify so that the user can see that the label identifies the correct component.

The constructor for a JLabel lets you specify the initial text or icon, and optionally, the alignment of the content. You use constants from the SwingConstants interface to specify alignment. That interface defines a number of useful constants such as LEFT, RIGHT, CENTER, NORTH, EAST, and so on. The JLabel class is one of several Swing classes that implement this interface. Therefore, you can specify a right-aligned label either as

 JLabel label = new JLabel("Minutes", SwingConstants.RIGHT); 

or

 JLabel label = new JLabel("Minutes", JLabel.RIGHT); 

The setText and setIcon methods let you set the text and icon of the label at run time.

TIP

Beginning with JDK 1.3, you can use both plain and HTML text in buttons, labels, and menu items. We don't recommend HTML in buttons it interferes with the look and feel. But HTML in labels can be very effective. Simply surround the label string with <html>. . .</html>, like this:

 label = new JLabel("<html><b>Required</b> entry:</html>"); 

Fair warning the first component with an HTML label takes some time to be displayed because the rather complex HTML rendering code must be loaded.


Labels can be positioned inside a container like any other component. This means you can use the techniques you have seen before to place labels where you need them.


 javax.swing.JLabel 1.2 

  • JLabel(String text)

    constructs a label with left-aligned text.

    Parameters:

    text

    The text in the label


  • JLabel(Icon icon)

    constructs a label with a left-aligned icon.

    Parameters:

    icon

    The icon in the label


  • JLabel(String text, int align)

    constructs a label with the given text and alignment

    Parameters:

    text

    The text in the label

     

    align

    One of the SwingConstants constants LEFT, CENTER, or RIGHT


  • JLabel(String text, Icon icon, int align)

    constructs a label with both text and an icon. The icon is to the left of the text.

    Parameters:

    text

    The text in the label

     

    icon

    The icon in the label

     

    align

    One of the SwingConstants constants LEFT, CENTER, or RIGHT


  • void setText(String text)

    sets the text of this label.

    Parameters:

    text

    The text in the label


  • void setIcon(Icon icon)

    sets the icon of this label.

    Parameters:

    icon

    The icon in the label


Change Tracking in Text Fields

Let us put a few text fields to work. Figure 9-12 shows the running application listed in Example 9-2. The program shows a clock and two text fields that enter the hours and minutes. Whenever the content of the text fields changes, the clock is updated.

Figure 9-12. Text field example


To track every change in the text field requires a bit of an effort. First of all, note that it is not a good idea to monitor keystrokes. Some keystrokes (such as the arrow keys) don't change the text. And, depending on the look and feel, there may be mouse actions that result in text changes. As you saw in the beginning of this chapter, the Swing text field is implemented in a rather general way: the string that you see in the text field is just a visible manifestation (the view) of an underlying data structure (the model). Of course, for a humble text field, there is no great difference between the two. The view is a displayed string, and the model is a string object. But the same architecture is used in more advanced editing components to present formatted text, with fonts, paragraphs, and other attributes that are internally represented by a more complex data structure. The model for all text components is described by the Document interface, which covers both plain text and formatted text (such as HTML). The point is that you can ask the document (and not the text component) to notify you whenever the data has changed, by installing a document listener:

 textField.getDocument().addDocumentListener(listener); 

When the text has changed, one of the following DocumentListener methods is called:

 void insertUpdate(DocumentEvent event) void removeUpdate(DocumentEvent event) void changedUpdate(DocumentEvent event) 

The first two methods are called when characters have been inserted or removed. The third method is not called at all for text fields. For more complex document types, it would be called when some other change, such as a change in formatting, has occurred. Unfortunately, there is no single callback to tell you that the text has changed usually you don't much care how it has changed. And there is no adapter class either. Thus, your document listener must implement all three methods. Here is what we do in our sample program:

 private class ClockFieldListener implements DocumentListener {    public void insertUpdate(DocumentEvent event) { setClock(); }    public void removeUpdate(DocumentEvent event) { setClock(); }    public void changedUpdate(DocumentEvent event) {} } 

The setClock method uses the getText method to obtain the current user-input strings from the text fields. Unfortunately, that is what we get: strings. We need to convert the strings to integers by using the familiar, if cumbersome, incantation:

 int hours = Integer.parseInt(hourField.getText().trim()); int minutes = Integer.parseInt(minuteField.getText().trim()); 

But this code won't work right when the user types a noninteger string, such as "two", into the text field or even leaves the field blank. For now, we catch the NumberFormatException that the parseInt method throws, and we simply don't update the clock when the text field entry is not a number. In the next section, you see how you can prevent the user from entering invalid input in the first place.

NOTE

Instead of listening to document events, you can also add an action event listener to a text field. The action listener is notified whenever the user presses the ENTER key. We don't recommend this approach, because users don't always remember to press ENTER when they are done entering data. If you use an action listener, you should also install a focus listener so that you can track when the user leaves the text field.


Finally, note how the ClockPanel constructor sets the preferred size:

 public ClockPanel() {    setPreferredSize(new Dimension(2 * RADIUS + 1, 2 * RADIUS + 1)); } 

When the frame's pack method computes the frame size, it uses the panel's preferred size.

Example 9-2. TextTest.java
   1. import java.awt.*;   2. import java.awt.event.*;   3. import java.awt.geom.*;   4. import javax.swing.*;   5. import javax.swing.event.*;   6.   7. public class TextTest   8. {   9.    public static void main(String[] args)  10.    {  11.      TextTestFrame frame = new TextTestFrame();  12.      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  13.      frame.setVisible(true);  14.    }  15. }  16.  17. /**  18.    A frame with two text fields to set a clock.  19. */  20. class TextTestFrame extends JFrame  21. {  22.    public TextTestFrame()  23.    {  24.       setTitle("TextTest");  25.  26.       DocumentListener listener = new ClockFieldListener();  27.  28.       // add a panel with text fields  29.  30.       JPanel panel = new JPanel();  31.  32.       panel.add(new JLabel("Hours:"));  33.       hourField = new JTextField("12", 3);  34.       panel.add(hourField);  35.       hourField.getDocument().addDocumentListener(listener);  36.  37.       panel.add(new JLabel("Minutes:"));  38.       minuteField = new JTextField("00", 3);  39.       panel.add(minuteField);  40.       minuteField.getDocument().addDocumentListener(listener);  41.  42.       add(panel, BorderLayout.SOUTH);  43.  44.       // add the clock  45.  46.       clock = new ClockPanel();  47.       add(clock, BorderLayout.CENTER);  48.       pack();  49.    }  50.  51.    /**  52.       Set the clock to the values stored in the text fields.  53.    */  54.    public void setClock()  55.    {  56.       try  57.       {  58.          int hours = Integer.parseInt(hourField.getText().trim());  59.          int minutes = Integer.parseInt(minuteField.getText().trim());  60.          clock.setTime(hours, minutes);  61.       }  62.       catch (NumberFormatException e) {}  63.       // don't set the clock if the input can't be parsed  64.    }  65.  66.    public static final int DEFAULT_WIDTH = 300;  67.    public static final int DEFAULT_HEIGHT = 300;  68.  69.    private JTextField hourField;  70.    private JTextField minuteField;  71.    private ClockPanel clock;  72.  73.    private class ClockFieldListener implements DocumentListener  74.    {  75.       public void insertUpdate(DocumentEvent event) { setClock(); }  76.       public void removeUpdate(DocumentEvent event) { setClock(); }  77.       public void changedUpdate(DocumentEvent event) {}  78.    }  79. }  80.  81. /**  82.    A panel that draws a clock.  83. */  84. class ClockPanel extends JPanel  85. {  86.    public ClockPanel()  87.    {  88.       setPreferredSize(new Dimension(2 * RADIUS + 1, 2 * RADIUS + 1));  89.    }  90.  91.    public void paintComponent(Graphics g)  92.    {  93.       // draw the circular boundary  94.  95.       super.paintComponent(g);  96.       Graphics2D g2 = (Graphics2D) g;  97.       Ellipse2D circle = new Ellipse2D.Double(0, 0, 2 * RADIUS, 2 * RADIUS);  98.       g2.draw(circle);  99. 100.       // draw the hour hand 101. 102.       double hourAngle = Math.toRadians(90 - 360 * minutes / (12 * 60)); 103.       drawHand(g2, hourAngle, HOUR_HAND_LENGTH); 104. 105.       // draw the minute hand 106. 107.       double minuteAngle = Math.toRadians(90 - 360 * minutes / 60); 108.       drawHand(g2, minuteAngle, MINUTE_HAND_LENGTH); 109.    } 110. 111.    public void drawHand(Graphics2D g2, double angle, double handLength) 112.    { 113.       Point2D end = new Point2D.Double( 114.          RADIUS + handLength * Math.cos(angle), 115.          RADIUS - handLength * Math.sin(angle)); 116.       Point2D center = new Point2D.Double(RADIUS, RADIUS); 117.       g2.draw(new Line2D.Double(center, end)); 118.    } 119. 120.    /** 121.       Set the time to be displayed on the clock 122.       @param h hours 123.       @param m minutes 124.    */ 125.    public void setTime(int h, int m) 126.    { 127.       minutes = h * 60 + m; 128.       repaint(); 129.    } 130. 131.    private double minutes = 0; 132.    private int RADIUS = 100; 133.    private double MINUTE_HAND_LENGTH = 0.8 * RADIUS; 134.    private double HOUR_HAND_LENGTH = 0.6 * RADIUS; 135. } 


 javax.swing.JComponent 1.2 

  • void setPreferredSize(Dimension d)

    sets the preferred size of this component.


 javax.swing.text.Document 1.2 

  • int getLength()

    returns the number of characters currently in the document.

  • String getText(int offset, int length)

    returns the text contained within the given portion of the document.

    Parameters:

    offset

    The start of the text

     

    length

    The length of the desired string


  • void addDocumentListener(DocumentListener listener)

    registers the listener to be notified when the document changes.


 javax.swing.event.DocumentEvent 1.2 

  • Document getDocument()

    gets the document that is the source of the event.


 javax.swing.event.DocumentListener 1.2 

  • void changedUpdate(DocumentEvent event)

    is called whenever an attribute or set of attributes changes.

  • void insertUpdate(DocumentEvent event)

    is called whenever an insertion into the document occurs.

  • void removeUpdate(DocumentEvent event)

    is called whenever a portion of the document has been removed.

Password Fields

Password fields are a special kind of text field. To avoid nosy bystanders being able to glance at a password, the characters that the user entered are not actually displayed. Instead, each typed character is represented by an echo character, typically an asterisk (*). Swing supplies a JPasswordField class that implements such a text field.

The password field is another example of the power of the model-view-controller architecture pattern. The password field uses the same model to store the data as a regular text field, but its view has been changed to display all characters as echo characters.


 javax.swing.JPasswordField 1.2 

  • JPasswordField(String text, int columns)

    constructs a new password field.

    Parameters:

    text

    The text to be displayed, null if none

     

    columns

    The number of columns


  • void setEchoChar(char echo)

    sets the echo character for this password field. This is advisory; a particular look and feel may insist on its own choice of echo character. A value of 0 resets the echo character to the default.

    Parameters:

    echo

    The echo character to display instead of the text characters


  • char[] getPassword()

    returns the text contained in this password field. For stronger security, you should overwrite the content of the returned array after use. (The password is not returned as a String because a string would stay in the virtual machine until it is garbage-collected.)

Formatted Input Fields

In the last example program, we wanted the program user to type numbers, not arbitrary strings. That is, the user is allowed to enter only digits 0 through 9 and a hyphen ( ). The hyphen, if present at all, must be the first symbol of the input string.

On the surface, this input validation task sounds simple. We can install a key listener to the text field and then consume all key events that aren't digits or a hyphen. Unfortunately, this simple approach, although commonly recommended as a method for input validation, does not work well in practice. First, not every combination of the valid input characters is a valid number. For example, --3 and 3-3 aren't valid, even though they are made up from valid input characters. But, more important, there are other ways of changing the text that don't involve typing character keys. Depending on the look and feel, certain key combinations can be used to cut, copy, and paste text. For example, in the Metal look and feel, the CTRL+V key combination pastes the content of the paste buffer into the text field. That is, we also need to monitor that the user doesn't paste in an invalid character. Clearly, trying to filter keystrokes to ensure that the content of the text field is always valid begins to look like a real chore. This is certainly not something that an application programmer should have to worry about.

Perhaps surprisingly, before JDK 1.4, there were no components for entering numeric values. Starting with the first edition of Core Java, we supplied an implementation for an IntTextField, a text field for entering a properly formatted integer. In every new edition, we changed the implementation to take whatever limited advantage we could from the various half-baked validation schemes that were added to each version of the JDK. Finally, in JDK 1.4, the Swing designers faced the issues head-on and supplied a versatile JFormattedTextField class that can be used not just for numeric input but also for dates and for even more esoteric formatted values such as IP addresses.

Integer Input

Let's get started with an easy case first: a text field for integer input.

 JFormattedTextField intField = new JFormattedTextField(NumberFormat.getIntegerInstance()); 

The NumberFormat.getIntegerInstance returns a formatter object that formats integers, using the current locale. In the US locale, commas are used as decimal separators, allowing users to enter values such as 1,729. The internationalization chapter in Volume 2 explains in detail how you can select other locales.

As with any text field, you can set the number of columns:

 intField.setColumns(6); 

You can set a default value with the setValue method. That method takes an Object parameter, so you'll need to wrap the default int value in an Integer object:

 intField.setValue(new Integer(100)); 

Typically, users will supply inputs in multiple text fields and then click a button to read all values. When the button is clicked, you can get the user-supplied value with the getValue method. That method returns an Object result, and you need to cast it into the appropriate type. The JFormattedTextField returns an object of type Long if the user edited the value. However, if the user made no changes, the original Integer object is returned. Therefore, you should cast the return value to the common superclass Number:

 Number value = (Number) intField.getValue(); int v = value.intValue(); 

The formatted text field is not very interesting until you consider what happens when a user provides illegal input. That is the topic of the next section.

Behavior on Loss of Focus

Consider what happens when a user supplies input to a text field. The user types input and eventually decides to leave the field, perhaps by clicking on another component with the mouse. Then the text field loses focus. The I-beam cursor is no longer visible in the text field, and keystrokes are directed toward a different component.

When the formatted text field loses focus, the formatter looks at the text string that the user produced. If the formatter knows how to convert the text string to an object, the text is valid. Otherwise it is invalid. You can use the isEditValid method to check whether the current content of the text field is valid.

The default behavior on loss of focus is called "commit or revert." If the text string is valid, it is committed. The formatter converts it to an object. That object becomes the current value of the field (that is, the return value of the getValue method that you saw in the preceding section). The value is then converted back to a string, which becomes the text string that is visible in the field. For example, the integer formatter recognizes the input 1729 as valid, sets the current value to new Long(1729) and then converts it back into a string with a decimal comma: 1,729.

Conversely, if the text string is invalid, then the current value is not changed and the text field reverts to the string that represents the old value. For example, if the user enters a bad value, such as x1, then the old value is restored when the text field loses focus.

NOTE

The integer formatter regards a text string as valid if it starts with an integer. For example, 1729x is a valid string. It is converted to the number 1729, which is then formatted as the string 1,729.


You can set other behaviors with the setFocusLostBehavior method. The "commit" behavior is subtly different from the default. If the text string is invalid, then both the text string and the field value stay unchanged they are now out of sync. The "persist" behavior is even more conservative. Even if the text string is valid, neither the text field nor the current value are changed. You would need to call commitEdit, setValue, or setText to bring them back in sync. Finally, there is a "revert" behavior that doesn't ever seem to be useful. Whenever focus is lost, the user input is disregarded, and the text string reverts to the old value.

NOTE

Generally, the "commit or revert" default behavior is reasonable. There is just one potential problem. Suppose a dialog box contains a text field for an integer value. A user enters a string " 1729", with a leading space and then clicks the OK button. The leading space makes the number invalid, and the field value reverts to the old value. The action listener of the OK button retrieves the field value and closes the dialog. The user never knows that the new value has been rejected. In this situation, it is appropriate to select the "commit" behavior and have the OK button listener check that all field edits are valid before closing the dialog.


Filters

This basic functionality of formatted text fields is straightforward and sufficient for most uses. However, you can add a couple of refinements. Perhaps you want to prevent the user from entering nondigits altogether. You achieve that behavior with a document filter. Recall that in the model-view-controller architecture, the controller translates input events into commands that modify the underlying document of the text field, that is, the text string that is stored in a PlainDocument object. For example, whenever the controller processes a command that causes text to be inserted into the document, it calls the "insert string" command. The string to be inserted can be either a single character or the content of the paste buffer. A document filter can intercept this command and modify the string or cancel the insertion altogether. Here is the code for the insertString method of a filter that analyzes the string to be inserted and inserts only the characters that are digits or a - sign. (The code handles supplementary Unicode characters, as explained in Chapter 3. See Chapter 12 for the StringBuilder class.)

 public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)    throws BadLocationException {    StringBuilder builder = new StringBuilder(string);    for (int i = builder.length() - 1; i >= 0; i--)    {       int cp = builder.codePointAt(i);       if (!Character.isDigit(cp) && cp != '-')       {          builder.deleteCharAt(i);          if (Character.isSupplementaryCodePoint(cp))          {             i--;             builder.deleteCharAt(i);          }       }    }    super.insertString(fb, offset, builder.toString(), attr); } 

You should also override the replace method of the DocumentFilter class it is called when text is selected and then replaced. The implementation of the replace method is straightforward see the program at the end of this section.

Now you need to install the document filter. Unfortunately, there is no straightforward method to do that. You need to override the getdocumentFilter method of a formatter class, and pass an object of that formatter class to the JFormattedTextField. The integer text field uses an InternationalFormatter that is initialized with NumberFormat.getIntegerInstance(). Here is how you install a formatter to yield the desired filter:

 JFormattedTextField intField = new JFormattedTextField(new       InternationalFormatter(NumberFormat.getIntegerInstance())       {          protected DocumentFilter getDocumentFilter()          {             return filter;          }          private DocumentFilter filter = new IntFilter();       }); 

NOTE

The JDK documentation states that the DocumentFilter class was invented to avoid subclassing. Until JDK 1.3, filtering in a text field was achieved by extending the PlainDocument class and overriding the insertString and replace methods. Now the PlainDocument class has a pluggable filter instead. That is a splendid improvement. It would have been even more splendid if the filter had also been made pluggable in the formatter class. Alas, it was not, and we must subclass the formatter.


Try out the FormatTest example program at the end of this section. The third text field has a filter installed. You can insert only digits or the minus ('-') character. Note that you can still enter invalid strings such as "1-2-3". In general, it is impossible to avoid all invalid strings through filtering. For example, the string "-" is invalid, but a filter can't reject it because it is a prefix of a legal string "-1". Even though filters can't give perfect protection, it makes sense to use them to reject inputs that are obviously invalid.

TIP

Another use for filtering is to turn all characters of a string to upper case. Such a filter is easy to write. In the insertString and replace methods of the filter, convert the string to be inserted to upper case and then invoke the superclass method.


Verifiers

There is another potentially useful mechanism to alert users to invalid inputs. You can attach a verifier to any JComponent. If the component loses focus, then the verifier is queried. If the verifier reports the content of the component to be invalid, the component immediately regains focus. The user is thus forced to fix the content before supplying other inputs.

A verifier must extend the abstract InputVerifier class and define a verify method. It is particularly easy to define a verifier that checks formatted text fields. The isEditValid method of the JFormattedTextField class calls the formatter and returns TRue if the formatter can turn the text string into an object. Here is the verifier.

 class FormattedTextFieldVerifier extends InputVerifier {    public boolean verify(JComponent component)    {       JFormattedTextField field = (JFormattedTextField) component;       return field.isEditValid();    } } 

You can attach it to any JFormattedTextField:

 intField.setInputVerifier(new FormattedTextFieldVerifier()); 

However, a verifier is not entirely foolproof. If you click on a button, then the button notifies its action listeners before an invalid component regains focus. The action listeners can then get an invalid result from the component that failed verification. There is a reason for this behavior: users may want to press a Cancel button without first having to fix an invalid input.

The fourth text field in the example program has a verifier attached. Try entering an invalid number (such as x1729) and press the TAB key or click with the mouse on another text field. Note that the field immediately regains focus. However, if you press the OK button, the action listener calls getValue, which reports the last good value.

Other Standard Formatters

Besides the integer formatter, the JFormattedTextField supports several other formatters. The NumberFormat class has static methods

 getNumberInstance getCurrencyInstance getPercentInstance 

that yield formatters of floating-point numbers, currency values, and percentages. For example, you can obtain a text field for the input of currency values by calling

JFormattedTextField currencyField = new JFormattedTextField(NumberFormat .getCurrencyInstance());

To edit dates and times, call one of the static methods of the DateFormat class:

 getDateInstance getTimeInstance getDateTimeInstance 

For example,

 JFormattedTextField dateField = new JFormattedTextField(DateFormat.getDateInstance()); 

This field edits a date in the default or "medium" format such as

 Feb 24, 2002 

You can instead choose a "short" format such as

 2/24/02 

by calling

 DateFormat.getDateInstance(DateFormat.SHORT) 

NOTE

By default, the date format is "lenient." That is, an invalid date such as February 31, 2002, is rolled over to the next valid date, March 3, 2002. That behavior may be surprising to your users. In that case, call setLenient(false) on the DateFormat object.


The DefaultFormatter can format objects of any class that has a constructor with a string parameter and a matching toString method. For example, the URL class has a URL(String) constructor that can be used to construct a URL from a string, such as

 URL url = new URL("http://java.sun.com"); 

Therefore, you can use the DefaultFormatter to format URL objects. The formatter calls toString on the field value to initialize the field text. When the field loses focus, the formatter constructs a new object of the same class as the current value, using the constructor with a String parameter. If that constructor throws an exception, then the edit is not valid. You can try that out in the example program by entering a URL that does not start with a prefix such as "http:".

NOTE

By default, the DefaultFormatter is in overwrite mode. That is different from the other formatters and not very useful. Call setOverwriteMode(false) to turn off overwrite mode.


Finally, the MaskFormatter is useful for fixed-size patterns that contain some constant and some variable characters. For example, social security numbers (such as 078-05-1120) can be formatted with a

 new MaskFormatter("###-##-####") 

The # symbol denotes a single digit. Table 9-2 shows the symbols that you can use in a mask formatter.

Table 9-2. MaskFormatter Symbols

#

A digit

?

A letter

U

A letter, converted to upper case

L

A letter, converted to lower case

A

A letter or digit

H

A hexadecimal digit [0-9A-Fa-f]

*

Any character

'

Escape character to include a symbol in the pattern


You can restrict the characters that can be typed into the field by calling one of the methods of the MaskFormatter class:

 setValidCharacters setInvalidCharacters 

For example, to read in a letter grade (such as A+ or F), you could use

 MaskFormatter formatter = new MaskFormatter("U*"); formatter.setValidCharacters("ABCDF+- "); 

However, there is no way of specifying that the second character cannot be a letter.

Note that the string that is formatted by the mask formatter has exactly the same length as the mask. If the user erases characters during editing, then they are replaced with the placeholder character. The default placeholder character is a space, but you can change it with the setPlaceholderCharacter method, for example,

 formatter.setPlaceholderCharacter('0'); 

By default, a mask formatter is in overtype mode, which is quite intuitive try it out in the example program. Also note that the caret position jumps over the fixed characters in the mask.

The mask formatter is very effective for rigid patterns such as social security numbers or American telephone numbers. However, note that no variation at all is permitted in the mask pattern. For example, you cannot use a mask formatter for international telephone numbers that have a variable number of digits.

Custom Formatters

If none of the standard formatters is appropriate, it is fairly easy to define your own formatter. Consider 4-byte IP addresses such as

 130.65.86.66 

You can't use a MaskFormatter because each byte might be represented by one, two, or three digits. Also, we want to check in the formatter that each byte's value is at most 255.

To define your own formatter, extend the DefaultFormatter class and override the methods

 String valueToString(Object value) Object stringToValue(String text) 

The first method turns the field value into the string that is displayed in the text field. The second method parses the text that the user typed and turns it back into an object. If either method detects an error, it should throw a ParseException.

In our example program, we store an IP address in a byte[] array of length 4. The valueToString method forms a string that separates the bytes with periods. Note that byte values are signed quantities between -128 and 127. To turn negative byte values into unsigned integer values, you add 256.

 public String valueToString(Object value) throws ParseException {    if (!(value instanceof byte[]))       throw new ParseException("Not a byte[]", 0);    byte[] a = (byte[]) value;    if (a.length != 4)        throw new ParseException("Length != 4", 0);    StringBuilder builder = new StringBuilder();    for (int i = 0; i < 4; i++)    {       int b = a[i];       if (b < 0) b += 256;       builder.append(String.valueOf(b));       if (i < 3) builder.append('.');    }    return builder.toString(); } 

Conversely, the stringToValue method parses the string and produces a byte[] object if the string is valid. If not, it throws a ParseException.

 public Object stringToValue(String text) throws ParseException {    StringTokenizer tokenizer = new StringTokenizer(text, ".");    byte[] a = new byte[4];    for (int i = 0; i < 4; i++)    {       int b = 0;       try       {          b = Integer.parseInt(tokenizer.nextToken());       }       catch (NumberFormatException e)       {          throw new ParseException("Not an integer", 0);       }       if (b < 0 || b >= 256)          throw new ParseException("Byte out of range", 0);       a[i] = (byte) b;    }    return a; } 

Try out the IP address field in the sample program. If you enter an invalid address, the field reverts to the last valid address.

The program in Example 9-3 shows various formatted text fields in action (see Figure 9-13). Click the Ok button to retrieve the current values from the fields.

Figure 9-13. The FormatTest program


NOTE

The "Swing Connection" online newsletter has a short article describing a formatter that matches any regular expression. See http://java.sun.com/products/jfc/tsc/articles/reftf/.


Example 9-3. FormatTest.java

   1. import java.awt.*;   2. import java.awt.event.*;   3. import java.lang.reflect.*;   4. import java.net.*;   5. import java.text.*;   6. import java.util.*;   7. import javax.swing.*;   8. import javax.swing.text.*;   9.  10. /**  11.    A program to test formatted text fields  12. */  13. public class FormatTest  14. {  15.    public static void main(String[] args)  16.    {  17.       FormatTestFrame frame = new FormatTestFrame();  18.       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  19.       frame.setVisible(true);  20.    }  21. }  22.  23. /**  24.    A frame with a collection of formatted text fields and  25.    a button that displays the field values.  26. */  27. class FormatTestFrame extends JFrame  28. {  29.    public FormatTestFrame()  30.    {  31.       setTitle("FormatTest");  32.       setSize(WIDTH, HEIGHT);  33.  34.       JPanel buttonPanel = new JPanel();  35.       okButton = new JButton("Ok");  36.       buttonPanel.add(okButton);  37.       add(buttonPanel, BorderLayout.SOUTH);  38.  39.       mainPanel = new JPanel();  40.       mainPanel.setLayout(new GridLayout(0, 3));  41.       add(mainPanel, BorderLayout.CENTER);  42.  43.       JFormattedTextField intField = new JFormattedTextField(NumberFormat .getIntegerInstance());  44.       intField.setValue(new Integer(100));  45.       addRow("Number:", intField);  46.  47.       JFormattedTextField intField2 = new JFormattedTextField(NumberFormat .getIntegerInstance());  48.       intField2.setValue(new Integer(100));  49.       intField2.setFocusLostBehavior(JFormattedTextField.COMMIT);  50.       addRow("Number (Commit behavior):", intField2);  51.  52.       JFormattedTextField intField3  53.          = new JFormattedTextField(new  54.             InternationalFormatter(NumberFormat.getIntegerInstance())  55.             {  56.                protected DocumentFilter getDocumentFilter()  57.                {  58.                   return filter;  59.                }  60.                private DocumentFilter filter = new IntFilter();  61.             });  62.       intField3.setValue(new Integer(100));  63.       addRow("Filtered Number", intField3);  64.  65.       JFormattedTextField intField4 = new JFormattedTextField(NumberFormat .getIntegerInstance());  66.       intField4.setValue(new Integer(100));  67.       intField4.setInputVerifier(new FormattedTextFieldVerifier());  68.       addRow("Verified Number:", intField4);  69.  70.       JFormattedTextField currencyField  71.          = new JFormattedTextField(NumberFormat.getCurrencyInstance());  72.       currencyField.setValue(new Double(10));  73.       addRow("Currency:", currencyField);  74.  75.       JFormattedTextField dateField = new JFormattedTextField(DateFormat .getDateInstance());  76.       dateField.setValue(new Date());  77.       addRow("Date (default):", dateField);  78.  79.       DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT);  80.       format.setLenient(false);  81.       JFormattedTextField dateField2 = new JFormattedTextField(format);  82.       dateField2.setValue(new Date());  83.       addRow("Date (short, not lenient):", dateField2);  84.  85.       try  86.       {  87.          DefaultFormatter formatter = new DefaultFormatter();  88.          formatter.setOverwriteMode(false);  89.          JFormattedTextField urlField = new JFormattedTextField(formatter);  90.          urlField.setValue(new URL("http://java.sun.com"));  91.          addRow("URL:", urlField);  92.       }  93.       catch (MalformedURLException e)  94.       {  95.          e.printStackTrace();  96.       }  97.  98.       try  99.       { 100.          MaskFormatter formatter = new MaskFormatter("###-##-####"); 101.          formatter.setPlaceholderCharacter('0'); 102.          JFormattedTextField ssnField = new JFormattedTextField(formatter); 103.          ssnField.setValue("078-05-1120"); 104.          addRow("SSN Mask:", ssnField); 105.       } 106.       catch (ParseException exception) 107.       { 108.          exception.printStackTrace(); 109.       } 110. 111.       JFormattedTextField ipField = new JFormattedTextField(new IPAddressFormatter()); 112.       ipField.setValue(new byte[] { (byte) 130, 65, 86, 66 }); 113.       addRow("IP Address:", ipField); 114.    } 115. 116.    /** 117.       Adds a row to the main panel. 118.       @param labelText the label of the field 119.       @param field the sample field 120.    */ 121.    public void addRow(String labelText, final JFormattedTextField field) 122.    { 123.       mainPanel.add(new JLabel(labelText)); 124.       mainPanel.add(field); 125.       final JLabel valueLabel = new JLabel(); 126.       mainPanel.add(valueLabel); 127.       okButton.addActionListener(new 128.          ActionListener() 129.          { 130.             public void actionPerformed(ActionEvent event) 131.             { 132.                Object value = field.getValue(); 133.                if (value.getClass().isArray()) 134.                { 135.                   StringBuilder builder = new StringBuilder(); 136.                   builder.append('{'); 137.                   for (int i = 0; i < Array.getLength(value); i++) 138.                   { 139.                      if (i > 0) builder.append(','); 140.                      builder.append(Array.get(value, i).toString()); 141.                   } 142.                   builder.append('}'); 143.                   valueLabel.setText(builder.toString()); 144.                } 145.                else 146.                   valueLabel.setText(value.toString()); 147.             } 148.          }); 149.    } 150. 151.    public static final int WIDTH = 500; 152.    public static final int HEIGHT = 250; 153. 154.    private JButton okButton; 155.    private JPanel mainPanel; 156. } 157. 158. /** 159.    A filter that restricts input to digits and a '-' sign. 160. */ 161. class IntFilter extends DocumentFilter 162. { 163.    public void insertString(FilterBypass fb, int offset, String string, AttributeSet  attr) 164.       throws BadLocationException 165.    { 166.       StringBuilder builder = new StringBuilder(string); 167.       for (int i = builder.length() - 1; i >= 0; i--) 168.       { 169.          int cp = builder.codePointAt(i); 170.          if (!Character.isDigit(cp) && cp != '-') 171.          { 172.             builder.deleteCharAt(i); 173.             if (Character.isSupplementaryCodePoint(cp)) 174.             { 175.                i--; 176.                builder.deleteCharAt(i); 177.             } 178.          } 179.       } 180.       super.insertString(fb, offset, builder.toString(), attr); 181.    } 182. 183.    public void replace(FilterBypass fb, int offset, int length, String string,  AttributeSet attr) 184.       throws BadLocationException 185.    { 186.       if (string != null) 187.       { 188.          StringBuilder builder = new StringBuilder(string); 189.          for (int i = builder.length() - 1; i >= 0; i--) 190.          { 191.             int cp = builder.codePointAt(i); 192.             if (!Character.isDigit(cp) && cp != '-') 193.             { 194.                builder.deleteCharAt(i); 195.                if (Character.isSupplementaryCodePoint(cp)) 196.                { 197.                   i--; 198.                   builder.deleteCharAt(i); 199.                } 200.             } 201.          } 202.          string = builder.toString(); 203.       } 204.       super.replace(fb, offset, length, string, attr); 205.    } 206. } 207. 208. /** 209.    A verifier that checks whether the content of 210.    a formatted text field is valid. 211. */ 212. class FormattedTextFieldVerifier extends InputVerifier 213. { 214.    public boolean verify(JComponent component) 215.    { 216.       JFormattedTextField field = (JFormattedTextField) component; 217.       return field.isEditValid(); 218.    } 219. } 220. 221. /** 222.    A formatter for 4-byte IP addresses of the form a.b.c.d 223. */ 224. class IPAddressFormatter extends DefaultFormatter 225. { 226.    public String valueToString(Object value) 227.       throws ParseException 228.    { 229.       if (!(value instanceof byte[])) 230.          throw new ParseException("Not a byte[]", 0); 231.       byte[] a = (byte[]) value; 232.       if (a.length != 4) 233.          throw new ParseException("Length != 4", 0); 234.       StringBuilder builder = new StringBuilder(); 235.       for (int i = 0; i < 4; i++) 236.       { 237.          int b = a[i]; 238.          if (b < 0) b += 256; 239.          builder.append(String.valueOf(b)); 240.          if (i < 3) builder.append('.'); 241.       } 242.       return builder.toString(); 243.    } 244. 245.    public Object stringToValue(String text) throws ParseException 246.    { 247.       StringTokenizer tokenizer = new StringTokenizer(text, "."); 248.       byte[] a = new byte[4]; 249.       for (int i = 0; i < 4; i++) 250.       { 251.          int b = 0; 252.          if (!tokenizer.hasMoreTokens()) 253.             throw new ParseException("Too few bytes", 0); 254.          try 255.          { 256.             b = Integer.parseInt(tokenizer.nextToken()); 257.          } 258.          catch (NumberFormatException e) 259.          { 260.             throw new ParseException("Not an integer", 0); 261.          } 262.          if (b < 0 || b >= 256) 263.             throw new ParseException("Byte out of range", 0); 264.          a[i] = (byte) b; 265.       } 266.       if (tokenizer.hasMoreTokens()) 267.          throw new ParseException("Too many bytes", 0); 268.       return a; 269.    } 270. } 


 javax.swing.JFormattedTextField 1.4 

  • JFormattedTextField(Format fmt)

    constructs a text field that uses the specified format.

  • JFormattedTextField(JFormattedTextField.AbstractFormatter formatter)

    constructs a text field that uses the specified formatter. Note that DefaultFormatter and InternationalFormatter are subclasses of JFormattedTextField.AbstractFormatter.

  • Object getValue()

    returns the current valid value of the field. Note that this may not correspond to the string that is being edited.

  • void setValue(Object value)

    attempts to set the value of the given object. The attempt fails if the formatter cannot convert the object to a string.

  • void commitEdit()

    attempts to set the valid value of the field from the edited string. The attempt may fail if the formatter cannot convert the string.

  • boolean isEditValid()

    checks whether the edited string represents a valid value.

  • void setFocusLostBehavior(int behavior)

  • int getFocusLostBehavior()

    set or get the "focus lost" behavior. Legal values for behavior are the constants COMMIT_OR_REVERT, REVERT, COMMIT, and PERSIST of the JFormattedTextField class.


 java.text.DateFormat 1.1\ 

  • static DateFormat getDateInstance()

  • static DateFormat getDateInstance(int dateStyle)

  • static DateFormat getTimeInstance()

  • static DateFormat getTimeInstance(int timeStyle)

  • static DateFormat getDateTimeInstance()

  • static DateFormat getDateTimeInstance(int dateStyle, int timeStyle)

    return formatters that yield the date, time, or both date and time of Date objects. Legal values for dateStyle and timeStyle are the constants SHORT, MEDIUM, LONG, FULL, and DEFAULT of the DateFormat class.


 javax.swing.JFormattedTextField.AbstractFormatter 1.4 

  • abstract String valueToString(Object value)

    converts a value to an editable string. Throws a ParseException if value is not appropriate for this formatter.

  • abstract Object stringToValue(String s)

    converts a string to a value. Throws a ParseException if s is not in the appropriate format.

  • DocumentFilter getDocumentFilter()

    override this method to provide a document filter that restricts inputs into the text field. A return value of null indicates that no filtering is needed.


 javax.swing.text.DefaultFormatter  1.3 

  • void setOverwriteMode(boolean mode)

  • boolean getOverwriteMode()

    set or get the overwrite mode. If mode is true, then new characters overwrite existing characters when editing text.


 javax.swing.text.DocumentFilter 1.4 

  • void insertString(DocumentFilter.FilterBypass bypass, int offset, String text, AttributeSet attrib)

    is invoked before a string is inserted into a document. You can override the method and modify the string. You can disable insertion by not calling super.insertString or by calling bypass methods to modify the document without filtering.

    Parameters:

    bypass

    An object that allows you to execute edit commands that bypass the filter

     

    offset

    The offset at which to insert the text

     

    text

    The characters to insert

     

    attrib

    The formatting attributes of the inserted text


  • void replace(DocumentFilter.FilterBypass bypass, int offset, int length, String text, AttributeSet attrib)

    is invoked before a part of a document is replaced with a new string. You can override the method and modify the string. You can disable replacement by not calling super.replace or by calling bypass methods to modify the document without filtering.

    Parameters:

    bypass

    An object that allows you to execute edit commands that bypass the filter

     

    offset

    The offset at which to insert the text

     

    length

    The length of the part to be replaced

     

    text

    The characters to insert

     

    attrib

    The formatting attributes of the inserted text


  • void remove(DocumentFilter.FilterBypass bypass, int offset, int length)

    is invoked before a part of a document is removed. Get the document by calling bypass.getDocument() if you need to analyze the effect of the removal.

    Parameters:

    bypass

    An object that allows you to execute edit commands that bypass the filter

     

    offset

    The offset of the part to be removed

     

    length

    The length of the part to be removed



 javax.swing.text.MaskFormatter 1.4 

  • MaskFormatter(String mask)

    constructs a mask formatter with the given mask. See Table 9-2 on page 367 for the symbols in a mask.

  • void setValidCharacters(String characters)

  • String getValidCharacters()

    set or get the valid editing characters. Only the characters in the given string are accepted for the variable parts of the mask.

  • void setInvalidCharacters(String characters)

  • String getInvalidCharacters()

    set or get the invalid editing characters. None of the characters in the given string are accepted as input.

  • void setPlaceholderCharacter(char ch)

  • char getPlaceholderCharacter()

    set or get the placeholder character that is used for variable characters in the mask that the user has not yet supplied. The default placeholder character is a space.

  • void setPlaceholder(String s)

  • String getPlaceholder()

    set or get the placeholder string. Its tail end is used if the user has not supplied all variable characters in the mask. If it is null or shorter than the mask, then the placeholder character fills remaining inputs.

  • void setValueContainsLiteralCharacters(boolean b)

  • boolean getValueContainsLiteralCharacters()

    set or get the "value contains literal characters" flag. If this flag is true, then the field value contains the literal (nonvariable) parts of the mask. If it is false, then the literal characters are removed. The default is TRue.

Text Areas

Sometimes, you need to collect user input that is more than one line long. As mentioned earlier, you use the JTextArea component for this collection. When you place a text area component in your program, a user can enter any number of lines of text, using the ENTER key to separate them. Each line ends with a '\n'. If you need to break up the user's entry into separate lines, you can use the StringTokenizer class (see Chapter 12). Figure 9-14 shows a text area at work.

Figure 9-14. A text area


In the constructor for the JTextArea component, you specify the number of rows and columns for the text area. For example:

 textArea = new JTextArea(8, 40); // 8 lines of 40 columns each 

where the columns parameter works as before and you still need to add a few more columns for safety's sake. Also, as before, the user is not restricted to the number of rows and columns; the text simply scrolls when the user inputs too much. You can also use the setColumns method to change the number of columns, and the setRows method to change the number of rows. These numbers only indicate the preferred size the layout manager can still grow or shrink the text area.

If there is more text than the text area can display, then the remaining text is simply clipped. You can avoid clipping long lines by turning on line wrapping:

 textArea.setLineWrap(true); // long lines are wrapped 

This wrapping is a visual effect only; the text in the document is not changed no '\n' characters are inserted into the text.

In Swing, a text area does not have scrollbars. If you want scrollbars, you have to insert the text area inside a scroll pane.

 textArea = new JTextArea(8, 40); JScrollPane scrollPane = new JScrollPane(textArea); 

The scroll pane now manages the view of the text area. Scrollbars automatically appear if there is more text than the text area can display, and they vanish again if text is deleted and the remaining text fits inside the area. The scrolling is handled internally in the scroll pane your program does not need to process scroll events.

TIP

This is a general mechanism that you will encounter many times when working with Swing to add scrollbars to a component, put them inside a scroll pane.


Example 9-4 is the complete code for the text area demo. This program simply lets you edit text in a text area. Click on "Insert" to insert a sentence at the end of the text. Click the second button to turn line wrapping on and off. (Its name toggles between "Wrap" and "No wrap".) Of course, you can simply use the keyboard to edit the text in the text area. Note how you can highlight a section of text, and how you can cut, copy, and paste with the CTRL+X, CTRL+C, and CTRL+V keys. (Keyboard shortcuts are specific to the look and feel. These particular key combinations work for the Metal and Windows look and feel.)

NOTE

The JTextArea component displays plain text only, without special fonts or formatting. To display formatted text (such as HTML or RTF), you can use the JEditorPane and JTextPane classes. These classes are discussed in Volume 2.


Example 9-4. TextAreaTest.java
  1. import java.awt.*;  2. import java.awt.event.*;  3. import javax.swing.*;  4.  5. public class TextAreaTest  6. {  7.    public static void main(String[] args)  8.    {  9.       TextAreaFrame frame = new TextAreaFrame(); 10.       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 11.       frame.setVisible(true); 12.    } 13. } 14. 15. /** 16.    A frame with a text area and buttons for text editing 17. */ 18. class TextAreaFrame extends JFrame 19. { 20.    public TextAreaFrame() 21.    { 22.       setTitle("TextAreaTest"); 23.       setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 24. 25.       buttonPanel = new JPanel(); 26. 27.       // add button to append text into the text area 28. 29.       JButton insertButton = new JButton("Insert"); 30.       buttonPanel.add(insertButton); 31.       insertButton.addActionListener(new 32.          ActionListener() 33.          { 34.             public void actionPerformed(ActionEvent event) 35.             { 36.                textArea.append("The quick brown fox jumps over the lazy dog. "); 37.             } 38.          }); 39. 40.       // add button to turn line wrapping on and off 41. 42.       wrapButton = new JButton("Wrap"); 43.       buttonPanel.add(wrapButton); 44.       wrapButton.addActionListener(new 45.          ActionListener() 46.          { 47.             public void actionPerformed(ActionEvent event) 48.             { 49.                boolean wrap = !textArea.getLineWrap(); 50.                textArea.setLineWrap(wrap); 51.                scrollPane.revalidate(); 52.                wrapButton.setText(wrap ? "No Wrap" : "Wrap"); 53.             } 54.          }); 55. 56.        add(buttonPanel, BorderLayout.SOUTH); 57. 58.        // add a text area with scrollbars 59. 60.        textArea = new JTextArea(8, 40); 61.        scrollPane = new JScrollPane(textArea); 62. 63.       add(scrollPane, BorderLayout.CENTER); 64.    } 65. 66.    public static final int DEFAULT_WIDTH = 300; 67.    public static final int DEFAULT_HEIGHT = 300; 68. 69.    private JTextArea textArea; 70.    private JScrollPane scrollPane; 71.    private JPanel buttonPanel; 72.    private JButton wrapButton; 73. } 


 javax.swing.JTextArea 1.2 

  • JTextArea(int rows, int cols)

    constructs a new text area.

    Parameters:

    rows

    The number of rows

     

    cols

    The number of columns


  • JTextArea(String text, int rows, int cols)

    constructs a new text area with an initial text.

    Parameters:

    text

    The initial text

     

    rows

    The number of rows

     

    cols

    The number of columns


  • void setColumns(int cols)

    tells the text area the preferred number of columns it should use.

    Parameters:

    cols

    The number of columns


  • void setRows(int rows)

    tells the text area the preferred number of rows it should use.

    Parameters:

    rows

    The number of rows


  • void append(String newText)

    appends the given text to the end of the text already in the text area.

    Parameters:

    newText

    The text to append


  • void setLineWrap(boolean wrap)

    turns line wrapping on or off.

    Parameters:

    wrap

    true if lines should be wrapped


  • void setWrapStyleWord(boolean word)

    If word is true, then long lines are wrapped at word boundaries. If it is false, then long lines are broken without taking word boundaries into account.

  • void setTabSize(int c)

    sets tab stops every c columns. Note that the tabs aren't converted to spaces but cause alignment with the next tab stop.

    Parameters:

    c

    The number of columns for a tab stop



 javax.swing.JScrollPane 1.2 

  • JScrollPane(Component c)

    creates a scroll pane that displays the content of the specified component. Scrollbars are supplied when the component is larger than the view.

    Parameters:

    c

    The component to scroll



       
    top



    Core Java 2 Volume I - Fundamentals
    Core Java(TM) 2, Volume I--Fundamentals (7th Edition) (Core Series) (Core Series)
    ISBN: 0131482025
    EAN: 2147483647
    Year: 2003
    Pages: 132

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net