19.4 A Simple Form


One of the most common user-interface constructs is the basic form. Typically, forms are made up of labels and fields, with the label describing the text to be entered in the field. Here's a primitive TextForm class that shows the use of mnemonics, tooltips, and basic accessibility support. Note that we call setLabelFor( ) to associate each label with a text field. This association allows the mnemonics to set the focus and, together with setToolTipText( ), supports accessibility (see Chapter 25).

// TextForm.j ava // import javax.swing.*; import java.awt.event.*; import java.awt.*; // A simple label/field form panel public class TextForm extends JPanel {   private JTextField[] fields;   // Create a form with the specified labels, tooltips, and sizes.   public TextForm(String[] labels, char[] mnemonics, int[] widths, String[] tips) {     super(new BorderLayout( ));     JPanel labelPanel = new JPanel(new GridLayout(labels.length, 1));     JPanel fieldPanel = new JPanel(new GridLayout(labels.length, 1));     add(labelPanel, BorderLayout.WEST);     add(fieldPanel, BorderLayout.CENTER);     fields = new JTextField[labels.length];     for (int i=0; i < labels.length; i+=1) {       fields[i] = new JTextField( );       if (i < tips.length) fields[i].setToolTipText(tips[i]);       if (i < widths.length) fields[i].setColumns(widths[i]);       JLabel lab = new JLabel(labels[i], JLabel.RIGHT);       lab.setLabelFor(fields[i]);       if (i < mnemonics.length) lab.setDisplayedMnemonic(mnemonics[i]);       labelPanel.add(lab);       JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));       p.add(fields[i]);       fieldPanel.add(p);     }   }   public String getText(int i) {     return( fields[i].getText( ) );   }   public static void main(String[] args) {     String[] labels = { "First Name", "Middle Initial", "Last Name", "Age" };     char[] mnemonics = { 'F', 'M', 'L', 'A' };     int[] widths = { 15, 1, 15, 3 };     String[] descs = { "First Name", "Middle Initial", "Last Name", "Age" };     final TextForm form = new TextForm(labels, mnemonics, widths, descs);     JButton submit = new JButton("Submit Form");     submit.addActionListener(new ActionListener( ) {         public void actionPerformed(ActionEvent e) {           System.out.println(form.getText(0) + " " + form.getText(1) + ". " +                              form.getText(2) + ", age " + form.getText(3));         }       });     JFrame f = new JFrame("Text Form Example");     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     f.getContentPane( ).add(form, BorderLayout.NORTH);     JPanel p = new JPanel( );     p.add(submit);     f.getContentPane( ).add(p, BorderLayout.SOUTH);     f.pack( );     f.setVisible(true);   } }

We've included a simple main( ) method here to show how this form class might be used. Clearly, much could be done to make this simple class more flexible and powerful. That aside, Figure 19-4 shows what we get.

Figure 19-4. A simple text form
figs/swng2.1904.gif

19.4.1 Understanding JTextField Sizing

Depending on how you construct your JTextField, and how it is laid out in its container, you may be a bit surprised by its size when it appears on the screen. Here are three things to watch out for:

Height stretching

JTextField's getPreferredSize( ) method returns a reasonable height the height of the field's font plus enough for the border but layout managers such as BorderLayout (west, center, and east positions) and GridLayout ignore this and stretch the field vertically. The field handles vertical stretching by centering its single line of text within its too-tall editing area. A little stretching may look OK, but it doesn't take much to distort the field. To prevent stretching, place the JTextField inside a JPanel (which defaults to FlowLayout), then add the JPanel to the container.

Note that the north and south positions of BorderLayout do respect the height returned by getPreferredSize( ). The width is ignored instead. The field is stretched to cover the entire width of the container.

Skimpy columns

Specifying the number of columns your JTextField should have, by either creating it with one of the constructors that takes a columns parameter or by explicitly calling setColumns( ), may not actually produce a field capable of displaying that many columns without scrolling. This is especially true for narrow fields (less than four columns) and fields with constant-width fonts.

This tight squeeze happens because of the sizing of the component using the lowercase character m of the field's font, as described earlier. getPreferredSize( ) returns a width that is the number of columns times the pixel width of m. Because the field's border occupies some of this space, the field can be too small for its contents. This isn't a problem for wide fields with proportional fonts because most of the characters the user enters are narrower than an m, so there is enough slack to cover the field's border. Otherwise, you may have to implement a workaround.

A simple and effective workaround for this problem is to specify one more column than you actually need. Another workaround is to do something like this:

// A hack to make a JTextField really two columns wide JTextField tf = new JTextField("mm"); tf.setPreferredSize( tf.getPreferredSize( ) ); tf.setText(""); // Empty the field.

This works only because the field's columns property defaults to 0. (When columns is nonzero, setPreferredSize( ) does not affect the width, though it does affect the height.)

Dynamic width

If the columns property is 0 (and presuming that an explicit preferredSize hasn't been set), the width returned by getPreferredSize( ) is just enough to display the field's contents and border and varies dynamically when the user edits the contents. In practice, the displayed size of the field does not change on every keystroke, which would be disconcerting, but only when the field is revalidated. This happens, for example, when an enclosing container is resized.

Still, you probably don't want your fields to change size at all. There are several ways to make sure they don't. You can use a layout manager that ignores the width returned by getPreferredSize( ), such as GridLayout or BorderLayout (north and south positions). You can specify a nonzero value for columns in the constructor (or via setColumns( )). Alternately, you can specify an explicit width (and height) with setPreferredSize( ).

19.4.1.1 Restricting input

One of the most common extensions of a text field is a field that enforces some type of restriction on the text that may be entered into it (uppercase only, numbers only, no more than 10 characters, and so on). With a java.awt.TextField, such restrictions can be enforced by filtering key events. In earlier versions of Swing, this was done by creating a restricted document model. As of SDK 1.4, Swing provides a JFormattedTextField (described in Chapter 20) for this purpose.



Java Swing
Graphic Java 2: Mastering the Jfc, By Geary, 3Rd Edition, Volume 2: Swing
ISBN: 0130796670
EAN: 2147483647
Year: 2001
Pages: 289
Authors: David Geary

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