viernes, 1 de julio de 2011

How to: Disable Options JCombobox // JComboBox con opciones deshabilitadas e imagenes // Disabling Options on JComboBox


Woow mañana será un año desde mi última publicación en el post… Qué vergüenza x) pero por motivos de estudio y trabajo descontinué la publicación de artículos; No estoy seguro de cuantas personas son lectores frecuentes del blog, aunque espero que no sea el único *_* Bueno aunque si fuera el único si llego a sufrir de una amnesia profunda al menos voy a recordar que solía gustarme (eso si me recuerdo de la url del blog O.o) jajaja. También espero que de ahora en adelante pueda postear al menos un articulo cada semana o cada mes… pero no cada año como es el caso de este post x).

Bueno pues últimamente he estado un poco aprendiendo (o al menos tratando) un poco del extenso mundo de Java Swing, cosas como Objetos, Componente y Listeners, entre algunos mas. Pues en una de esas tardes que vas buscando el significado de la vida por internet (y obvio no lo encontré xD) mejor busque como hacer que un JcomboBox pueda mostrar un texto en la Ventana pero como Variable de ese texto tener otro valor. Explicándome mejor: Supongamos que tenemos una lista de paises —Paises[todos los países del Mundo], pero al usuario le queremos mostrar ex: Luxemburgo, y en la Base de Datos queremos guardar ese valor con el código ISO, ósea: LUX. En HTML el problema mencionando anteriormente se resolvería (si me memoria no me deja mal) fácilmente con un: 
<select>
   <option value='LUX'>Luxemburgo</option>
  </select> 
Pero en Java cuando estamos ingresando el valor del JcomboBox, podemos hacerlo de muchas formas, pasarle un vector con todos los item que deseamos que ese combo tenga o bien pasarle un Objeto a la vez  con los cuales se cargara el susodicho JcomboBox, en el ejemplo usaremos el ultimo método(uno por uno) y quedaría así:
JComboBox combo1 = new JComboBox();
  combo1.addItem("texto que mostrara el JcomboBox");
Pero haciéndolo de esa forma nos alejamos de nuestro objetivo, el cual era mostrar un texto en la ventana y que el valor de ese Item del Combo fuera otro. Para Poder lograr eso haremos una Clase que llamaremos ObjectoEnComboBox, dicha Clase tendrá un constructor el cual recibirá dos parámetros de tipo String los cuales serán: Texto a Mostrar en el ComboBox, Texto que queremos recibir del combo), cuando escriba el código omitiré los imports para hacer un poco más corto el código ok ;):
public class ObjectoEnComboBox{
  private String textoMostrado;
  private String valorCombo;
  
  public ObjectoEnComboBox(String textoMostrado, String valorCombo){
   this.textoMostrado = textoMostrado;
   this.valorCombo = valorCombo;
  }
  /**
  * Sobreescribiendo el metodo toString()
  */
   @Override
   public String toString() {
     return this.textoMostrado;
   }
  /**
   * Creando los getter
   */
  public String getTextoMostrado(){
    return textoMostrado;
  }

  public String getValorCombo(){
    return valorCombo;
  }
 }
Como dije anteriormente el constructor de la clase recibe dos parametros, los metodos getter de las dos propiedades entenderemos su uso cuando estemos aplicando el objeto. pero adelantando un poco: serviran para recuperar tanto el texto como el valor del combo ;).
Nota: es necesario sobreescribir el metodo toString() porque de lo contrario el texto que mostrara el combo sera la ubicacion en memoria del objecto. algo como
Project.Componente.ObjetoEnCombo@65765, y obviamente no queremos eso... pero si es lo que quieren no lo sobreescriban x)
bien ahora veremos como aplicar eso en codigo
public class ComboPrueba extends javax.swing.JFrame{

    private JComboBox combo;
    public ComboPrueba() {
        combo = new JComboBox();
        getContentPane().setLayout(new FlowLayout());
        /**
         * Creamos los item que tendra el combo
         */
        ObjetoEnCombo item1 = new ObjetoEnCombo("the Wonder woman", "F");
        ObjetoEnCombo item2 = new ObjetoEnCombo("Super Man", "M");
        combo.addItem(item1);
        combo.addItem(item2);
        combo.addActionListener(comboListener());
        add(combo);
        
        setVisible(true);
        setSize(new Dimension(150, 100));
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private ActionListener comboListener(){
        return new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println(((ObjetoEnCombo)combo.getSelectedItem()).getValorCombo());
            }
        };
    }

    public static void main(String ... args){
        new ComboPrueba();
    }

}
El ejemplo consiste en tener un combobox con dos item con valores predeterminados, como podemos ver al constructor de la clase le enviamos los dos valores que necesita y ademas le agregamos un listener al combo para imprimir en consola el valor (no el texto)del item seleccionado, para esto debemos hacer un cast al al Objecto que nos devuelve el combo con su metodo combo.getSelectedItem. ya teniendo el objecto simplemente accedemos a la propiedad de valor con getValor. que es el valor que queremos guardar en la base de datos x). Esto mas que todo sirve cuando tenemos en una tabla una llave foranea, obviamente no podemos mostrar la llave en pantalla, eso seria muy inseguro y ademas un usuario normal solo podria decir "wth???!! que es esto???"
pero yo se que ustedes han llegado aqui esperando poder hacer un combo con opciones deshabilitadas y con una imagen por cada item del combo pero... al momento ni una ni la otra x)


Deshabilitar items del Combo
Bien, este ejemplo pueda que te sirva/interese si quieres deshabilitar algunas opciones del combo en tiempo de ejecucion, mas claro con un ejemplo: Si tenes un sistema de ingreso de usuario (un usuario pertenece a un departamento) pero por cada departamento hay un limite de asistentes (usuarios) entonces no puedes deshabilitarlos definidamente desde el codigo de la clase porque aun no sabes o mas bien, esos valores puede que cambien con el tiempo, entonces ...
para esta opcion necesitamos crear una clase (ComboConImagenYOpciones.java) que extienda de JCombobox, sobreescribiremos algunos metodos del jcombo para darle funcionabilidades especiales a nustros combito ^^; funcionalidades como coloear el item de gris indicando que esta deshabilitado para la seleccion, si el item que se quiere elegir es una opcion deshabilitada no cerrar el menu del combobox y que este permanezca abierto para proceder a seleccionar una opcion valida. Tambien le asignaremos un ListCellRenderer, el cual nos ayudara a darle un mejor aspecto visual.
La explicacion del codigo a continuacion del mismo
public class ComboConImagenYOpciones extends JComboBox {

    private boolean estaHabilitado = true;
    private final HashSet opcionesDeshabilitadas = new HashSet();

    public ComboConImagenYOpciones() {
        setRenderer(new ListCellRenderer() {
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                JLabel labelOpcion = new JLabel();
                if(value instanceof ObjetoEnCombo){
                    ObjetoEnCombo miOpcion = (ObjetoEnCombo) value;
                    labelOpcion.setText(miOpcion.getTextoMostrado());
                    if(opcionesDeshabilitadas.contains(miOpcion.getValorCombo())){
                        labelOpcion.setEnabled(false);
                        labelOpcion.setBackground(Color.LIGHT_GRAY);
                    }
                }
                return labelOpcion;
            }
        });
    }


    /**
     *
     * @param opcionesExcluidas Llaves de todas las opciones que quiero deshabilitar
     */
    public void setOpcionesDeshabilitadas(HashSet opcionesExcluidas) {
        this.opcionesDeshabilitadas.clear();
        for (String opcion : opcionesExcluidas) {
            this.opcionesDeshabilitadas.add(opcion);
        }
    }

    @Override
    public void setSelectedIndex(int anIndex) {
        String selected = ((ObjetoEnCombo)getModel().getElementAt(anIndex)).getValorCombo();
        if(opcionesDeshabilitadas.contains(selected)){
            estaHabilitado = false;
        }else{
            super.setSelectedIndex(anIndex);
        }
    }

    @Override
    public void setPopupVisible(boolean v) {
        if (!estaHabilitado) {
            estaHabilitado = true;
        } else {
            super.setPopupVisible(v);
        }
    }
}

bueno ya por ultimo estoy viendo que la entrada se hizo un poco larga.... :s y un amigo me acaba de decir literalmente: "Las entradas largas aburren" asi que he decidido dejar la parte de las imagenes para un segundo post. pero adelantando un poco, para poner imagenes necesitaremos un HashMap para que cada opcion del combo tenga su propia imagen, el ComboConImagenYOpciones.java tendra un metodo en el cual le setearemos dicho valores,
Bueno ahora si ya no sigo porque sino mejor lo termino en esta entrada x) Nos vemos mañana, almenos eso espero para commemorar el 1 año de NO post en este blog... que verguenza

Codigo del JCombobox Completo Aca :D

2 comentarios:

  1. Puya cubo... en LinUES no posteás nada, ta chivo el asunto pero compartilos con la comunidad también ;)

    ResponderEliminar
  2. Hey Gativiris mil perdones pero esa onda la hice en el trabajo shhhhh pero que nadie se entere x) por eso ves que la ventanita de la captura es del win seven, pero pense que solo cosas de Linux pero si se puede ya lo pongo :D

    ResponderEliminar