SpinnerModel propio

De ChuWiki

Por defecto un JSpinner es un componente java para editar números. Podemos escribir un número en la caja de texto o bien con las flechitas del JSpinner incrementar y decrementar el número.

El JSpinner sabe qué datos puede mostrar y sabe cual es el siguiente o anterior de acuerdo a una clase SpinnerModel que lleva en su interior. Nosotros podemos cambiar esa clase y poner otro SpinnerModel a nuestro gusto, de forma que los posibles valores y el orden de ellos puede ser el que decidamos.

Para crear nuestro propio SpinnerModel, sólo debemos hacer una clase que implemente la interface SpinnerModel e implementar todos los métodos de la misma a nuestro gusto. Luego, al instanciar el JSpinnerModel, le pasamos nuestro modelo en el constructor.

SpinerModel modelo = new MiModeloSpinnerModel();
JSpinner spinner = new JSpinner(modelo);

En el siguiente ejemplo se crea un SpinnerModel con los valores de los días de la semana "Lunes", "Martes", ..., "Sábado" y "Domingo". El orden de los mismos será el normal.

/**
 * Ejemplo de Modelo para JSpinner
 */
package chuidiang.ejemplos;

import java.util.LinkedList;

import javax.swing.SpinnerModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Modelo para JSpinner con los días de la semana.
 * @author chuidiang
 *
 */
class ModeloDiasSemana implements SpinnerModel {

	/** Posibles valores */
	private String [] valores = {
			"Lunes",
			"Martes",
			"Miércoles",
			"Jueves",
			"Viernes",
			"Sábado",
			"Domingo"
	};
	
	/** Valor mostrado actualmente */
	private int actual=0;
	
	/** Lista de observadores interesados en el cambio del valor actual */
	private LinkedList<ChangeListener> observadores = new LinkedList<ChangeListener>();

	/**
	 * Nos pasan el valor actual. Comprobamos que es correcto, lo guardamos y avisamos
	 * a los observadores.
	 */
	@Override
	public void setValue(Object value) {
		// Se ignora la entrada si es null
		if (value==null)
			return;
		
		// Se busca el valor en la tabla de valores posibles
		for (int i=0;i<valores.length;i++)
			if (valores[i].equalsIgnoreCase(value.toString()))
			{
				// Se guarda como valor actual
				actual=i;
				// Se avisa a los observadores del cambio.
				fireChangeLister();
				// Una vez encontrado no hace falta seguir con el bucle.
				return;
			}
	}

	/**
	 * Avisa a los observadores del cambio en el valor actual.
	 */
	private void fireChangeLister() {
		ChangeEvent evento = new ChangeEvent(this);
		for (ChangeListener observador: observadores)
			observador.stateChanged(evento);
	}

	/**
	 * Elimina al observador de la lista de observadores.
	 */
	@Override
	public void removeChangeListener(ChangeListener l) {
		observadores.remove(l);
	}

	/**
	 * Devuelve el valor actual.
	 */
	@Override
	public Object getValue() {
		return valores[actual];
	}

	/**
	 * Devuelve el valor que va antes del actual en la lista de valores
	 */
	@Override
	public Object getPreviousValue() {
		int anterior=(actual-1)%valores.length;
		if (anterior < 0)
			anterior+=valores.length;
		return valores[anterior];
	}

	/**
	 * Devuelve el siguiente valor al actual en la lista de valores
	 */
	@Override
	public Object getNextValue() {
		return valores[(actual+1)%valores.length];
	}

	/**
	 * Añade el observador a la lista de observadores.
	 */
	@Override
	public void addChangeListener(ChangeListener l) {
		observadores.add(l);
	}
}

y aquí tienes un pequeño ejemplo completo de cómo usarlo.

/**
 * Ejemplo sencillo de JSpinner con SpinnerModel propio.
 * Chuidiang, 27 Oct 2007
 */
package chuidiang.ejemplos;

import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Ejemplo de uso de JSpinner.
 * Una ventana con un JSpinner y un JTextField. El valor elegido
 * en el JSpinner se presentará automáticamente en el JTextField.
 * @author chuidiang
 */
public class PruebaJSpinnerDiasSemana {
	/** El JextField */
	private JTextField tf;
	
	/** El JSpinner */
	private JSpinner spinner;
	
	/** La ventana principal */
	private JFrame v;

	/** Modelo de datos del JSpinner */
	private SpinnerModel modelo;

	/**
	 * Crea una instancia de esta clase.
	 * @param args
	 */
	public static void main(String[] args) {
		new PruebaJSpinnerDiasSemana();
	}
	
	/**
	 * Crea la ventana y la visualiza.
	 */
	public PruebaJSpinnerDiasSemana()
	{
		// Creacion del JTextField
		tf = new JTextField(20);

		modelo = new ModeloDiasSemana();
		// Creacion del JSpinner y valor inicial.
		spinner = new JSpinner(modelo);
		spinner.setValue("Miércoles");
		
		// Nos suscribimos a cambios en el modelo. 
		modelo.addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent e) {
				// El valor del JSpinner se pone
				tf.setText(modelo.getValue().toString());
			}
		
		});
		

		// Creacion de la ventana con los componentes
		v = new JFrame();
		v.getContentPane().setLayout(new FlowLayout());
		v.getContentPane().add(spinner);
		v.getContentPane().add(tf);
		v.pack();
		v.setVisible(true);
		v.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	}
}