Como cambiar los colores de un JComboBox en Java

De ChuWiki


Para cambiar los colores de un JComboBox en Java necesitamos crear nuestra propia clase BasicComboBoxRenderer y definir en ella los colores que querarmos.

Veamos los detalles con un ejemplo que tienes en JComboBoxRender.java. En ese ejemplo también se cambia el botón del JComboBox, pero eso lo explicaremos en otro tutorial. Ignora todo lo relativo a MyArrow. Cualquier duda sobre este tutorial o Java en general suelo atender en este foro de java, python y otros

Creamos nuestro propio BasicComboBoxRenderer[editar]

Para crear nuestro BasicComboBoxRenderer solo tenemos que crear una clase que herede de BasicComboBoxRenderer y sobreescribir el método getListCellRendererComponent(). Vamos a ello

    public static class MyComboBoxRender extends BasicComboBoxRenderer {
        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
             // Aquí definimos los colores que queramos.
        }
    }

BasicComboBoxRenderer acaba heredando a su vez de un JLabel que es el que se usará para pintar los items del JComboBox desplegado. Ojo, es importante, sólo los items del JComboBox desplegado, NO del item visible cuando el JComboBox no está desplegado. Para el item visible cuando no está desplegado, Java tiene una lógica un poco extraña que vemos más abajo.

Cambiar los colores de los items desplegados[editar]

Vamos con la parte del menú desplegable del JComboBox.

Si llamamos al método de la clase padre getListCellRendererComponent() se hará una parte importante de nuestro trabajo. Se pondrán los colores por defecto para el item en la lista desplegada teniendo en cuenta si etá seleccionado, si no lo está, si tiene el foco, si no lo tiene, según su valor sea un texto o un icono. Así que es buena idea hacer esta llamada y luego cambiar los colores que queramos. En nuestro ejemplo, vamos a cambiar el color del texto y del fondo, teniendo en cuenta si está o no seleccionado.

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            // La llamada a super hace que coja los colores defecto según esté seleccionado, tenga foco, etc.
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);

            // Cambiamos color de fondo y letra del item del combo desplegado.
            if (isSelected) {
                this.setForeground(Color.BLUE);
                this.setBackground(Color.WHITE);
            } else {
                this.setBackground(Color.YELLOW);
                this.setForeground(Color.RED);
            }
            ...

Hemos hecho la llamada a super.getListCellRendererComponent() para tener parte del trabajo hecho.

Como hemos dicho que nuestra clase hereda de BasicComboBoxRenderer que a su vez acaba heredando a su vez de un <codeJJLabel y que este es el que se usa para el pintado de los item desplegados, nos basta llamar a this.setForeground() y this.setBackground() para cambiar los colores. Lo estamos haciendo en función de si el item está o no seleccionado.

Cambiar los colores del item visible cuando no está desplegado[editar]

Como hemos comentado, el item visible cuando no está desplegado el JComboBox tiene una lógica extraña. Si el JComboBox tiene el foco o el combo está desplegado, se va a dibujar con los colores "selected" del JList que nos pasan como parámetro. Así que tenemos que cambiar los colores "selected" de dicho JList

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {

            ...

            // list dibuja el elemento visible del combo cuando no está desplegado.
            list.setSelectionBackground(Color.RED);
            list.setSelectionForeground(Color.YELLOW);

            return this;
        }

Una vez cambiados los colores del JList, solo nos queda devolver el JLabel para pintando de los items. Como acabamos heredando de dicho JLabel, basta poner un return this al final.

Si el JComboBox no tiene el foco o su menú está desplegado, el color del item sale con los colores por defecto del JComboBox. Así que para este caso, no tener el foco o tener el menú desplegado, la forma de cambiarlo es cambiando los colores del JComboBox directamente.

combo.setBackground(Color.RED);
combo.setForeground(Color.YELLOW);

Cambiar los colores cuando el JComboBox está deshabilitado[editar]

No hay una forma fácil y elegante de cambiar los colores del JComboBox cuando está deshabilitado. Esto se debe a que el código de java por debajo no contempla esta opción. Sin embargo, si existe una forma fácil no elegante. Consiste en hacer el JComboBox editable para que presente un editor del combo. El editor es un JTextField y no un JLable. Aunque el combo sea editable, como está deshabilitado, no podremos tocar en él. Así que nos puede valer.

Simplemente tenemos que cambiar los colores del editor, sabiendo que por debajo es un JtextField

// Colores para cuando está deshabilitado
combo.getEditor().getEditorComponent().setBackground(Color.RED);
((JTextField)combo.getEditor().getEditorComponent()).setDisabledTextColor(Color.YELLOW);


Construir el JComboBox con el BasicComboBoxRenderer[editar]

Ya solo nos queda construir el JComboBox y ponerle todo lo que hemos construido

JComboBox<String> combo = new JComboBox<>();

// Cambiamos el render y los colores por defecto.
combo.setRenderer(new MyComboBoxRender());
combo.setBackground(Color.RED);
combo.setForeground(Color.YELLOW);

// Colores para cuando está deshabilitado. Para que haga caso, además de deshabilitar el combo,
// debemos ponerlo editable y acordarnos de ponerlo no editable cuando lo habilitemos.
combo.getEditor().getEditorComponent().setBackground(Color.RED);
((JTextField)combo.getEditor().getEditorComponent()).setDisabledTextColor(Color.YELLOW);

El resultado de este código completo es el de la siguiente imagen

Cambiar los colores del botón del JComboBox[editar]

En este otro tutorial explicamos cómo cambiar los colores del botón del JComboBox

Cambiar los colores de todos los JComboBox de la aplicación[editar]

Si queremos hacer esto con todos los JComboBox de la aplicación, hay una forma más fácil, aunque tiene sus pegas. Consiste en cambiar los colores por defecto usando UIManager. El código sería el siguiente

        UIManager.put("ComboBox.background",Color.RED);
        UIManager.put("ComboBox.foreground",Color.YELLOW);
        UIManager.put("ComboBox.disabledForeground", Color.YELLOW);
        UIManager.put("ComboBox.disabledBackground", Color.RED);
        UIManager.put("ComboBox.selectionBackground", Color.WHITE);
        UIManager.put("ComboBox.selectionForeground", Color.BLUE);

El problema con esto es qeu los colores ComboBox.selectionBackground y ComboBox.selectionForeground se usan tanto para el item seleccionado en el desplegable como para el valor visible cuando el desplegable está oculto y el JComboBox está oculto. Cuando el JComboBox pierda o gane el foco, veremos el cambio de color entre ComboBox.background y ComboBox.selectionBackground, así como en los "foreground" equivalentes.