Wednesday, June 6, 2012

SwingMetawidget: Limiting the Length of a JTextField

I was recently asked on the Metawidget forum whether SwingMetawidget could limit the maximum number of characters in a JTextField.

This isn't a capability JTextField offers by default, so SwingMetawidget doesn't offer it either. However it's easy to add using a custom WidgetProcessor and a Swing Document. Here's an example:

package com.myapp;

import static org.metawidget.inspector.InspectionResultConstants.*;

import java.util.Map;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

import org.metawidget.inspector.annotation.UiAttribute;
import org.metawidget.swing.SwingMetawidget;
import org.metawidget.widgetprocessor.iface.WidgetProcessor;

public class Main {

   public static void main( String[] args ) {

      Person person = new Person();

      SwingMetawidget metawidget = new SwingMetawidget();
      metawidget.addWidgetProcessor( new MaxLengthProcessor() );
      metawidget.setToInspect( person );

      JFrame frame = new JFrame( "Metawidget Tutorial" );
      frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
      frame.getContentPane().add( metawidget );
      frame.setSize( 400, 250 );
      frame.setVisible( true );
   }

   static class Person {

      private String   mName;

      @UiAttribute( name = MAXIMUM_LENGTH, value = "10" )
      public String getName() {

         return mName;
      }

      public void setName( String name ) {

         mName = name;
      }
   }

   static class MaxLengthProcessor
      implements WidgetProcessor<JComponent, SwingMetawidget> {

      public JComponent processWidget( JComponent widget, String elementName,
                                 Map<String, String> attributes, SwingMetawidget metawidget ) {

         String maximumLength = attributes.get( MAXIMUM_LENGTH );

         if ( maximumLength != null ) {

            final int maximumChars = Integer.parseInt( maximumLength );

            ( (JTextField) widget ).setDocument( new PlainDocument() {

               public void insertString( int offset, String string, AttributeSet attributeSet )
                     throws BadLocationException {

                  if ( string != null && ( getLength() + string.length() <= maximumChars ) ) {
                     super.insertString( offset, string, attributeSet );
                  }
               }
            } );
         }

         return widget;
      }
   }

}

Hope that helps somebody! Note you don't have to use @UiAttribute to set MAXIMUM_LENGTH. It could come from JPA's @Column( length ), or Bean Validator's @Size, or XML, or any number of other sources.

0 comments: