⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 input.java

📁 Semantic Web Ontology Editor
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
// (c) 2003 Allen I Holub. All rights reserved.
package com.holub.ui;

import com.holub.ui.NumericInput;// for testing

import java.util.logging.*;
import javax.swing.*;
import javax.swing.Timer;	// disambiguate from java.util.Timer
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;

import com.holub.tools.Log;

/* Demonstrate a JComponent-style proxy.
 *  <p>
 * This class is
 * a validating Text field. The first time you type something
 * invalid, an tool tip pops up describing what correct
 * input is. Subsequent errors just beep at you, but the
 * tooltip will continue to pop up if the mouse hovers.
 *
 * <!-- ====================== distribution terms ===================== -->
 * <p><blockquote
 * 	style="border-style: solid; border-width:thin; padding: 1em 1em 1em 1em;">
 * <center>
 * 			Copyright &copy; 2003, Allen I. Holub. All rights reserved.
 * </center>
 * <br>
 * <br>
 * 		This code is distributed under the terms of the
 * 		<a href="http://www.gnu.org/licenses/gpl.html"
 * 		>GNU Public License</a> (GPL)
 * 		with the following ammendment to section 2.c:
 * 		<p>
 * 		As a requirement for distributing this code, your splash screen,
 * 		about box, or equivalent must include an my name, copyright,
 * 		<em>and URL</em>. An acceptable message would be:
 * <center>
 * 		This program contains Allen Holub's <em>XXX</em> utility.<br>
 * 				(c) 2003 Allen I. Holub. All Rights Reserved.<br>
 * 						http://www.holub.com<br>
 * </center>
 * 		If your progam does not run interactively, then the foregoing
 * 		notice must appear in your documentation.
 * </blockquote>
 * <!-- =============================================================== -->
 * @see DateInput
 * @see NumericInput
 * @author Allen I. Holub
 */

public class Input extends JTextField implements Styles
{

	private final Customizer customizer;

	private String lastValid;	 // Useful only in on-exit-style validation.
								 // holds the last-known valid contents
								 // of the control.

	private boolean valid = true; // Used for communication between
	private int		offset;		  // the Document event handler and the
	private int		length;		  // UI Delegate update code.

	private Popup popup = null; // Popup window used for "help,"
								// is null unless window is visible.

	private static int POPUP_LIFETIME = 15;	// Maximum lifetime of popup
										    // window in seconds.

	/** Provides information about, defines nonstandard initial
	 *  state for, and validates user input.
	 *  The predefined {@link NumericInput} class implements
	 *  this interface for generic numbers, and the predefined
	 *  {@link Input.Default} class implements it for
	 *  a default, non-validating text control.
	 */

	public interface Customizer
	{
		/** Called by the Input object to determine whether validation
		 *  is performed (by calling {@link #isValid}) after every
		 *  character is entered or when the user hits enter (or the
		 *  input object looses focus)
		 *  <p>
		 *  Note that on-exit validation causes validation to occur
		 *  in two situations: the user hits Enter or the control
		 *  looses focus. The Control won't let the focus change
		 *  occur if the contents don't validate. However the Esc
		 *  character is recognized as a reset-to-original-value
		 *  request, so you can exit the field if you want to.
		 *  The string ("Type Esc to exit") is automatically appended
		 *  to the error message in this mode.
		 *
		 *  @return false for character-by-character validation, true for
		 *  		one-time validation on loss of focus or Enter.
		 */
		boolean validatesOnExit();

		/** Return true if the string is valid input. This method
		 *  is called either on exiting the control or after every
		 *  character is typed, depending on the return value of
		 *  {@link #validatesOnExit}. Reguardless of the
		 *  "validate-on-exit" mode, an hitting Esc alwasy resets
		 *  the control to the last-known valid value.
		 *  <p>
		 *  This method is also called when the control is initialized,
		 *  and the constructor will throw an exception if the initial
		 *  value is not valid.
		 *
		 *  @param s The entire contents of the control, including any
		 *  		 characters the user just entered.
		 */
		boolean isValid( String s );

		/** Return a description of what valid input looks likes.
		 *  The string should be HTML, however the main context
		 *  &lt;html&gt;, &lt;head&gt;, and &lt;body&gt; elements are already
		 *  established, so these tags should not appear in
		 *  your own text.
		 *  @param badInput This is the string that the user tried to type.
		 *  				The control rejects the bad input, so this
		 *  				string is not displayed. You can put it into
		 *  				your error message if you like, however.
		 *  @return a help string or null if no help is avilable.
		 */
		String help( String badInput );

		/** Set up the look of the component for stuff not covered
		 *  by the Style class. (For example, alignment and tool-tip
		 *  text). This method after all initializations (including
		 *  the text entry) have been made to the component.
		 *  customizations have been made.
		 */
		void prepare( JTextField current );

	}

	/** An implemenation of Customizer that defines default behavior:
	 *  All input is valid; there is no help; The prepare
	 *  method makes the control 30 columns wide.
	 *  You can extend this class if you just want
	 *  to override one of the methods, much like an
	 *  AWT <em>Xxx</em><code>Adapter</code>.
	 */

	static public class Default implements Customizer
	{	public boolean isValid(String s){return true;}
		public String help(String s) { return null; }
		public void prepare( JTextField current )
		{	current.setColumns(30);
		}
		public boolean validatesOnExit(){ return true; }
	};

	/** A constrained type to describe the border style you want.
	 *  One of the predefined instances Input.BOXED, Input.UNDERLINED,
	 *  or Input.BORDERLESS, must be passed to the
	 *  {@linkplain Input#Input <code>Input</code> constructor}.
	 */

	public static final class BorderStyle{ private BorderStyle(){} }
	public static final BorderStyle BORDERLESS = null;
	public static final BorderStyle BOXED 		= new BorderStyle();
	public static final BorderStyle UNDERLINED = new BorderStyle();

	/** Construct a validating input field. Works like a JTextField,
	 *  but checks the input as it's typed and complains
	 *  if the input is invalid. Also implements the TagBehavior
	 *  interface, so can be used in a PAC system as a stand-in
	 *  for an &lt;input&gt; tag.
	 *  <p>
	 *  The default width of the control is determined by the width of the
	 *  <code>value</code> string. You can change the width from the
	 *  default by calling {@link javax.swing.JTextField#setColumns} after
	 *  you create the object. Unlike the standard JTextField, the maximum
	 *  and minimum widths are constrained to the initial size. (This
	 *  constraint is required for the control to work correctly inside
	 *  a {@link com.holub.ui.HTML.HtmlPane}, which is it's raison d'etre.)
	 *
	 *  @param value initial value.
	 *  @param customizer checks to see if the input is valid. A null argument
	 *  			is treated as if you had passed an {@link Default} object.
	 *  @param border one of BORDERLESS, BOXED, or UNDERLINED.
	 *  @param isHighlighted if true, highlight the text in the Style.HIGHLIGHT_COLOR
	 *
	 *  @throws IllegalArgumentException if the customizer indicates that the
	 *  		initial <code>value</code> is invalid.
	 */
	public Input(String value, Customizer customizer, final BorderStyle border, final boolean isHighlighted)
	{
		this.customizer	= (customizer != null)? customizer: new Default();

		if( !customizer.isValid(value) )
			throw new IllegalArgumentException("Customizer rejected initial value ["+ value +"]");

		lastValid = value;

		setFont( FONT );
		if( isHighlighted )
			setForeground( Color.RED ); // Affects border color too.

		if( border==BOXED )
		{	Border outer = BorderFactory.createLineBorder( Color.BLACK, 1 );
			Border inner = BorderFactory.createEmptyBorder( 0, 4, 0, 4 );

			setBorder( BorderFactory.createCompoundBorder(outer, inner) );
		}
		else if( border==UNDERLINED )
		{	setBorder
			(	new AbstractBorder()
				{	public void paintBorder(Component c, Graphics g,
										int x, int y, int width, int height)
					{	g.drawLine( x, y+height-1, x+width-1, y+height-1 );
					}
				}
			);
		}
		else	// BORDERLESS
		{   setBorder( null );	// no border
		}

		setColumns( value.length() );
		setText( value );
		customizer.prepare( this );

		// We do our own action-listener handling here, because
		// notifications are sent on loss of focus as well as
		// Enter. checkOnExit() validates the data, and
		// notifies listeners if its valid.

		super.addActionListener			// handles Enter
		(	new ActionListener()
			{	public void actionPerformed(ActionEvent e)
				{	if( !validateInputAndNotifyListenersIfValid() )
						retainFocus();
				}
			}
		);

		// Send action events on loss of focus as well as Enter, but
		// only if the control holds valid input.

		super.addFocusListener
		(	new FocusAdapter()
			{	public void focusLost( FocusEvent e )
		        {	if( !validateInputAndNotifyListenersIfValid() )
			            retainFocus();
		        }
			}
		);

		// Process an Esc to reset the field to its last known good
		// value.

		super.addKeyListener
		(	new KeyAdapter()
			{	public void keyPressed( KeyEvent e )
		        {	if( e.getKeyCode() == KeyEvent.VK_ESCAPE )
					{	Input.this.setText( lastValid );
					}
				}
			}
		);

		// Set up a document listener. The documenation for JTextField
		// uses an insertString override to map characters to upper case,
		// but here, I want to disallow characters that will make the
		// entire string invalid. Consequently, a different approach is
		// required. The characterValidator is always installed because

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -